• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / jorgen.edelbo_402

21 Aug 2024 11:10AM UTC coverage: 91.054% (-0.03%) from 91.085%
jorgen.edelbo_402

Pull #7803

Evergreen

jedelbo
Small fix to Table::typed_write

When writing the realm to a new file from a write transaction,
the Table may be COW so that the top ref is changed. So don't
use the ref that is present in the group when the operation starts.
Pull Request #7803: Feature/string compression

103494 of 181580 branches covered (57.0%)

1929 of 1999 new or added lines in 46 files covered. (96.5%)

695 existing lines in 51 files now uncovered.

220142 of 241772 relevant lines covered (91.05%)

7344461.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.24
/src/realm/sort_descriptor.hpp
1
/*************************************************************************
2
 *
3
 * Copyright 2016 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#ifndef REALM_SORT_DESCRIPTOR_HPP
20
#define REALM_SORT_DESCRIPTOR_HPP
21

22
#include <vector>
23
#include <unordered_set>
24
#include <realm/cluster.hpp>
25
#include <realm/path.hpp>
26
#include <realm/mixed.hpp>
27
#include <realm/util/bind_ptr.hpp>
28

29

30
namespace realm {
31

32
class SortDescriptor;
33
class ConstTableRef;
34
class Group;
35
class KeyValues;
36

37
enum class DescriptorType { Sort, Distinct, Limit, Filter };
38

39
struct LinkPathPart {
40
    // Constructor for forward links
41
    LinkPathPart(ColKey col_key)
42
        : column_key(col_key)
43
    {
×
44
    }
×
45
    // Constructor for backward links. Source table must be a valid table.
46
    LinkPathPart(ColKey col_key, ConstTableRef source);
47
    // Each step in the path can be a forward or a backward link.
48
    // In case of a backlink, the column_key indicates the origin link column
49
    // (the forward link column in the origin table), not the backlink column
50
    // itself.
51
    ColKey column_key;
52
    // "from" is omitted to indicate forward links, if it is valid then
53
    // this path describes a backlink originating from the column from[column_key]
54
    TableKey from;
55
};
56

57
class BaseDescriptor {
58
public:
59
    struct IndexPair {
60
        IndexPair(ObjKey k, size_t i)
61
            : key_for_object(k)
30,119,487✔
62
            , index_in_view(i)
30,119,487✔
63
        {
60,238,437✔
64
        }
60,238,437✔
65
        bool operator<(const IndexPair& other) const
66
        {
60,220,725✔
67
            return index_in_view < other.index_in_view;
60,220,725✔
68
        }
60,220,725✔
69
        ObjKey get_key() const
NEW
70
        {
×
NEW
71
            return key_for_object;
×
NEW
72
        }
×
73
        Mixed get_value() const
74
        {
1,124,852,007✔
75
            return cached_value;
1,124,852,007✔
76
        }
1,124,852,007✔
77
        ObjKey key_for_object;
78
        size_t index_in_view;
79
        Mixed cached_value;
80
        bool compressed = false;
81
    };
82
    class IndexPairs : public std::vector<BaseDescriptor::IndexPair> {
83
    public:
84
        size_t m_removed_by_limit = 0;
85
    };
86
    class Sorter {
87
    public:
88
        Sorter(std::vector<std::vector<ExtendedColumnKey>> const& columns, std::vector<bool> const& ascending,
89
               Table const& root_table, const IndexPairs& indexes);
90
        Sorter() {}
×
91

92
        bool operator()(IndexPair i, IndexPair j, bool total_ordering = true) const;
93

94
        bool has_links() const
95
        {
1,212✔
96
            return std::any_of(m_columns.begin(), m_columns.end(), [](auto&& col) {
1,314✔
97
                return !col.translated_keys.empty();
1,314✔
98
            });
1,314✔
99
        }
1,212✔
100

101
        bool any_is_null(IndexPair i) const
102
        {
954✔
103
            return std::any_of(m_columns.begin(), m_columns.end(), [=](auto&& col) {
1,134✔
104
                return !col.translated_keys.empty() && !col.translated_keys[i.index_in_view];
1,134✔
105
            });
1,134✔
106
        }
954✔
107
        void cache_first_column(IndexPairs& v);
108

109
    private:
110
        struct SortColumn {
111
            SortColumn(const Table* t, ExtendedColumnKey c, bool a)
112
                : table(t)
10,821✔
113
                , col_key(c)
10,821✔
114
                , ascending(a)
10,821✔
115
            {
21,642✔
116
            }
21,642✔
117
            std::vector<ObjKey> translated_keys;
118

119
            const Table* table;
120
            ExtendedColumnKey col_key;
121
            bool ascending;
122
        };
123
        std::vector<SortColumn> m_columns;
124
        struct ObjCache {
125
            ObjKey key;
126
            Mixed value;
127
            bool compressed = false;
128

129
            ObjKey get_key() const
NEW
130
            {
×
NEW
131
                return key;
×
NEW
132
            }
×
133
            Mixed get_value() const
134
            {
1,926,198✔
135
                return value;
1,926,198✔
136
            }
1,926,198✔
137
        };
138
        using TableCache = std::vector<ObjCache>;
139
        mutable std::vector<TableCache> m_cache;
140

141
        friend class ObjList;
142
    };
143

144
    BaseDescriptor() = default;
66,327✔
145
    virtual ~BaseDescriptor() = default;
213,918✔
146
    virtual bool is_valid() const noexcept = 0;
147
    virtual bool need_indexpair() const noexcept
148
    {
678✔
149
        return false;
678✔
150
    }
678✔
151
    virtual std::string get_description(ConstTableRef attached_table) const = 0;
152
    virtual std::unique_ptr<BaseDescriptor> clone() const = 0;
153
    virtual DescriptorType get_type() const = 0;
154
    virtual void collect_dependencies(const Table*, std::vector<TableKey>&) const {}
720✔
155
    virtual Sorter sorter(Table const&, const IndexPairs&) const
156
    {
×
157
        return {};
×
158
    }
×
159
    // Do what you have to do
160
    virtual void execute(IndexPairs&, const Sorter&, const BaseDescriptor*) const {}
×
161
    virtual void execute(const Table&, KeyValues&, const BaseDescriptor*) const {}
×
162
};
163

164

165
// ColumnsDescriptor encapsulates a reference to a set of columns (possibly over
166
// links), which is used to indicate the criteria columns for sort and distinct.
167
class ColumnsDescriptor : public BaseDescriptor {
168
public:
169
    ColumnsDescriptor() = default;
27,662✔
170

171
    // Create a descriptor for the given columns on the given table.
172
    // Each vector in `column_keys` represents a chain of columns, where
173
    // all but the last are Link columns (n.b.: LinkList and Backlink are not
174
    // supported), and the final is any column type that can be sorted on.
175
    // `column_keys` must be non-empty, and each vector within it must also
176
    // be non-empty.
177
    ColumnsDescriptor(std::vector<std::vector<ExtendedColumnKey>> column_keys);
178

179
    // returns whether this descriptor is valid and can be used for sort or distinct
180
    bool is_valid() const noexcept override
181
    {
115,395✔
182
        return !m_column_keys.empty();
115,395✔
183
    }
115,395✔
184
    void collect_dependencies(const Table* table, std::vector<TableKey>& table_keys) const override;
185

186
protected:
187
    std::vector<std::vector<ExtendedColumnKey>> m_column_keys;
188
};
189

190
class DistinctDescriptor : public ColumnsDescriptor {
191
public:
192
    DistinctDescriptor() = default;
44✔
193
    DistinctDescriptor(std::vector<std::vector<ExtendedColumnKey>> column_keys)
194
        : ColumnsDescriptor(std::move(column_keys))
1,065✔
195
    {
2,130✔
196
    }
2,130✔
197

198
    std::unique_ptr<BaseDescriptor> clone() const override;
199

200
    bool need_indexpair() const noexcept override
201
    {
1,212✔
202
        return true;
1,212✔
203
    }
1,212✔
204

205
    DescriptorType get_type() const override
206
    {
4,236✔
207
        return DescriptorType::Distinct;
4,236✔
208
    }
4,236✔
209

210
    Sorter sorter(Table const& table, const IndexPairs& indexes) const override;
211
    void execute(IndexPairs& v, const Sorter& predicate, const BaseDescriptor* next) const override;
212

213
    std::string get_description(ConstTableRef attached_table) const override;
214
};
215

216

217
class SortDescriptor : public ColumnsDescriptor {
218
public:
219
    // Create a sort descriptor for the given columns on the given table.
220
    // See ColumnsDescriptor for restrictions on `column_keys`.
221
    // The sort order can be specified by using `ascending` which must either be
222
    // empty or have one entry for each column index chain.
223
    SortDescriptor(std::vector<std::vector<ExtendedColumnKey>> column_indices, std::vector<bool> ascending = {});
224
    SortDescriptor() = default;
27,618✔
225
    ~SortDescriptor() = default;
203,538✔
226
    std::unique_ptr<BaseDescriptor> clone() const override;
227

228
    bool need_indexpair() const noexcept override
229
    {
19,764✔
230
        return true;
19,764✔
231
    }
19,764✔
232

233
    DescriptorType get_type() const override
234
    {
90,948✔
235
        return DescriptorType::Sort;
90,948✔
236
    }
90,948✔
237

238
    util::Optional<bool> is_ascending(size_t ndx) const
239
    {
2,228✔
240
        if (ndx < m_ascending.size()) {
2,228✔
241
            return util::Optional<bool>(m_ascending[ndx]);
2,228✔
242
        }
2,228✔
243
        return util::none;
×
244
    }
2,228✔
245

246
    enum class MergeMode {
247
        /// If another sort has just been applied, merge before it, so it takes primary precedence
248
        /// this is used for time based scenarios where building the last applied sort is the most important
249
        /// default historical behaviour
250
        append,
251
        /// If another sort has just been applied, merge after it to take secondary precedence
252
        /// this is used to construct sorts in a builder pattern where the first applied sort remains the most
253
        /// important
254
        prepend,
255
        /// Replace this sort descriptor with another
256
        replace
257
    };
258

259
    void merge(SortDescriptor&& other, MergeMode mode);
260

261
    Sorter sorter(Table const& table, const IndexPairs& indexes) const override;
262

263
    void execute(IndexPairs& v, const Sorter& predicate, const BaseDescriptor* next) const override;
264

265
    std::string get_description(ConstTableRef attached_table) const override;
266

267
private:
268
    std::vector<bool> m_ascending;
269
};
270

271
class LimitDescriptor : public BaseDescriptor {
272
public:
273
    LimitDescriptor(size_t limit)
274
        : m_limit(limit)
314✔
275
    {
628✔
276
    }
628✔
277
    LimitDescriptor() = default;
2✔
278
    ~LimitDescriptor() = default;
2,640✔
279

280
    bool is_valid() const noexcept override
281
    {
1,632✔
282
        return m_limit != size_t(-1);
1,632✔
283
    }
1,632✔
284
    std::string get_description(ConstTableRef attached_table) const override;
285
    std::unique_ptr<BaseDescriptor> clone() const override;
286
    size_t get_limit() const noexcept
287
    {
720✔
288
        return m_limit;
720✔
289
    }
720✔
290

291
    DescriptorType get_type() const override
292
    {
1,626✔
293
        return DescriptorType::Limit;
1,626✔
294
    }
1,626✔
295

296
    void execute(const Table&, KeyValues&, const BaseDescriptor*) const override;
297

298
private:
299
    size_t m_limit = size_t(-1);
300
};
301

302
class FilterDescriptor : public BaseDescriptor {
303
public:
304
    FilterDescriptor(std::function<bool(const Obj&)> fn)
305
        : m_predicate(std::move(fn))
14✔
306
    {
28✔
307
    }
28✔
308
    FilterDescriptor() = default;
309
    ~FilterDescriptor() = default;
234✔
310

311
    bool is_valid() const noexcept override
312
    {
108✔
313
        return m_predicate != nullptr;
108✔
314
    }
108✔
315
    std::string get_description(ConstTableRef attached_table) const override;
316
    std::unique_ptr<BaseDescriptor> clone() const override;
317

318
    DescriptorType get_type() const override
319
    {
192✔
320
        return DescriptorType::Filter;
192✔
321
    }
192✔
322

323
    void execute(const Table&, KeyValues&, const BaseDescriptor*) const override;
324

325
private:
326
    std::function<bool(const Obj&)> m_predicate;
327
};
328

329
class DescriptorOrdering : public util::AtomicRefCountBase {
330
public:
331
    DescriptorOrdering() = default;
1,809,378✔
332
    DescriptorOrdering(const DescriptorOrdering&);
333
    DescriptorOrdering(DescriptorOrdering&&) = default;
27,794✔
334
    DescriptorOrdering& operator=(const DescriptorOrdering&);
335
    DescriptorOrdering& operator=(DescriptorOrdering&&) = default;
67,930✔
336

337
    void append_sort(SortDescriptor sort, SortDescriptor::MergeMode mode = SortDescriptor::MergeMode::prepend);
338
    void append_distinct(DistinctDescriptor distinct);
339
    void append_limit(LimitDescriptor limit);
340
    void append_filter(FilterDescriptor predicate);
341
    void append(const DescriptorOrdering& other);
342
    void append(DescriptorOrdering&& other);
343
    realm::util::Optional<size_t> get_min_limit() const;
344
    /// Remove all LIMIT statements from this descriptor ordering, returning the
345
    /// minimum LIMIT value that existed. If there was no LIMIT statement,
346
    /// returns `none`.
347
    util::Optional<size_t> remove_all_limits();
348
    bool will_limit_to_zero() const;
349
    DescriptorType get_type(size_t index) const;
350
    bool is_empty() const
351
    {
3,155,691✔
352
        return m_descriptors.empty();
3,155,691✔
353
    }
3,155,691✔
354
    size_t size() const
355
    {
31,776✔
356
        return m_descriptors.size();
31,776✔
357
    }
31,776✔
358
    const BaseDescriptor* operator[](size_t ndx) const;
359
    bool will_apply_sort() const;
360
    bool will_apply_distinct() const;
361
    bool will_apply_limit() const;
362
    bool will_apply_filter() const;
363
    std::string get_description(ConstTableRef target_table) const;
364
    void collect_dependencies(const Table* table);
365
    void get_versions(const Group* group, TableVersions& versions) const;
366

367
private:
368
    std::vector<std::unique_ptr<BaseDescriptor>> m_descriptors;
369
    std::vector<TableKey> m_dependencies;
370
};
371
} // namespace realm
372

373
#endif /* REALM_SORT_DESCRIPTOR_HPP */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc