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

realm / realm-core / github_pull_request_275914

25 Sep 2023 03:10PM UTC coverage: 92.915% (+1.7%) from 91.215%
github_pull_request_275914

Pull #6073

Evergreen

jedelbo
Merge tag 'v13.21.0' into next-major

"Feature/Bugfix release"
Pull Request #6073: Merge next-major

96928 of 177706 branches covered (0.0%)

8324 of 8714 new or added lines in 122 files covered. (95.52%)

181 existing lines in 28 files now uncovered.

247505 of 266379 relevant lines covered (92.91%)

7164945.17 hits per line

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

95.37
/src/realm/object-store/dictionary.cpp
1
/////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2020 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
#include <realm/object-store/dictionary.hpp>
20

21
#include <realm/object-store/results.hpp>
22
#include <realm/table.hpp>
23

24
namespace realm {
25
namespace {
26
class DictionaryKeyAdapter : public CollectionBase {
27
public:
28
    DictionaryKeyAdapter(std::shared_ptr<Dictionary> dictionary)
29
        : m_dictionary(std::move(dictionary))
30
    {
2,360✔
31
    }
2,360✔
32

33
    // -------------------------------------------------------------------------
34
    // Things which this adapter does something different from Dictionary for
35

36
    Mixed get_any(size_t ndx) const override
37
    {
2,378✔
38
        return m_dictionary->get_key(ndx);
2,378✔
39
    }
2,378✔
40

41
    size_t find_any(Mixed value) const override
42
    {
348✔
43
        return m_dictionary->find_any_key(value);
348✔
44
    }
348✔
45

46
    ColKey get_col_key() const noexcept override
47
    {
5,960✔
48
        auto col_key = m_dictionary->get_col_key();
5,960✔
49
        auto type = ColumnType(m_dictionary->get_key_data_type());
5,960✔
50
        return ColKey(col_key.get_index(), type, col_key.get_attrs(), col_key.get_tag());
5,960✔
51
    }
5,960✔
52

53
    std::unique_ptr<CollectionBase> clone_collection() const override
54
    {
×
55
        return std::make_unique<DictionaryKeyAdapter>(*this);
×
56
    }
×
57

58
    // -------------------------------------------------------------------------
59
    // Things which this just forwards on to Dictionary
60

61
    size_t size() const override
62
    {
3,258✔
63
        return m_dictionary->size();
3,258✔
64
    }
3,258✔
65
    bool is_null(size_t ndx) const override
66
    {
×
67
        return m_dictionary->is_null(ndx);
×
68
    }
×
69
    void clear() override
70
    {
84✔
71
        m_dictionary->clear();
84✔
72
    }
84✔
73
    void sort(std::vector<size_t>& indices, bool ascending = true) const override
74
    {
168✔
75
        m_dictionary->sort_keys(indices, ascending);
168✔
76
    }
168✔
77
    void distinct(std::vector<size_t>& indices, util::Optional<bool> sort_order = util::none) const override
78
    {
42✔
79
        m_dictionary->distinct_keys(indices, sort_order);
42✔
80
    }
42✔
81
    const Obj& get_obj() const noexcept override
82
    {
8,282✔
83
        return m_dictionary->get_obj();
8,282✔
84
    }
8,282✔
85
    bool has_changed() const override
86
    {
2,850✔
87
        return m_dictionary->has_changed();
2,850✔
88
    }
2,850✔
89

90
    // -------------------------------------------------------------------------
91
    // Things not applicable to the adapter
92

93
    // We currently only support string keys which means these aren't reachable
94
    // as Results will handle the type-checks
95
    util::Optional<Mixed> min(size_t* = nullptr) const override
NEW
96
    {
×
NEW
97
        REALM_TERMINATE("not implemented");
×
NEW
98
    }
×
99
    util::Optional<Mixed> max(size_t* = nullptr) const override
100
    {
NEW
101
        REALM_TERMINATE("not implemented");
×
NEW
102
    }
×
103
    util::Optional<Mixed> sum(size_t* = nullptr) const override
104
    {
105
        REALM_TERMINATE("not implemented");
106
    }
107
    util::Optional<Mixed> avg(size_t* = nullptr) const override
108
    {
109
        REALM_TERMINATE("not implemented");
110
    }
111

112
private:
113
    std::shared_ptr<Dictionary> m_dictionary;
114
};
115
} // anonymous namespace
116

117
void DictionaryChangeSet::add(std::vector<Mixed>& arr, const Mixed& key)
118
{
297✔
119
    arr.push_back(key);
297✔
120
    if (key.is_type(type_String)) {
297✔
121
        REALM_ASSERT(m_string_store.size() < m_string_store.capacity());
297✔
122
        m_string_store.emplace_back();
297✔
123
        arr.back().use_buffer(m_string_store.back());
297✔
124
    }
297✔
125
}
297✔
126

127
DictionaryChangeSet::DictionaryChangeSet(const DictionaryChangeSet& other)
128
{
4✔
129
    m_string_store.reserve(other.m_string_store.size());
4✔
130
    for (auto k : other.deletions) {
4✔
131
        add(deletions, k);
2✔
132
    }
2✔
133
    for (auto k : other.insertions) {
4✔
134
        add(insertions, k);
4✔
135
    }
4✔
136
    for (auto k : other.modifications) {
4✔
NEW
137
        add(modifications, k);
×
138
    }
139

4✔
140
    collection_root_was_deleted = other.collection_root_was_deleted;
4✔
141
}
4✔
142

143
DictionaryChangeSet& DictionaryChangeSet::operator=(const DictionaryChangeSet& other)
144
{
84✔
145
    m_string_store.reserve(other.m_string_store.size());
555✔
146

555✔
147
    m_string_store.clear();
555✔
148
    deletions.clear();
555✔
149
    insertions.clear();
555✔
150
    modifications.clear();
555✔
151

555✔
152
    for (auto k : other.deletions) {
573✔
153
        add(deletions, k);
102✔
154
    }
102✔
155
    for (auto k : other.insertions) {
93✔
156
        add(insertions, k);
30✔
157
    }
29✔
158
    for (auto k : other.modifications) {
92✔
159
        add(modifications, k);
29✔
160
    }
26✔
161

89✔
162
    collection_root_was_deleted = other.collection_root_was_deleted;
89✔
163

84✔
164
    return *this;
84✔
165
}
84✔
166

167

9✔
168
namespace object_store {
9✔
169

9✔
170
bool Dictionary::operator==(const Dictionary& rgt) const noexcept
171
{
274✔
172
    return dict() == rgt.dict();
400✔
173
}
400✔
174

175
bool Dictionary::operator!=(const Dictionary& rgt) const noexcept
126✔
176
{
253✔
177
    return !(*this == rgt);
253✔
178
}
253✔
179

180
Obj Dictionary::insert_embedded(StringData key)
183✔
181
{
203✔
182
    return dict().create_and_insert_linked_object(key);
203✔
183
}
41✔
184

21✔
185
std::pair<size_t, bool> Dictionary::insert_any(StringData key, Mixed value)
21✔
186
{
80✔
187
    auto [it, inserted] = dict().insert(key, value);
80✔
188
    return std::make_pair(it.index(), inserted);
80✔
189
}
59✔
190

126✔
191
void Dictionary::erase(StringData key)
126✔
192
{
415✔
193
    verify_in_transaction();
415✔
194
    dict().erase(key);
289✔
195
}
289✔
196

197
bool Dictionary::try_erase(StringData key)
198
{
185✔
199
    verify_in_transaction();
459✔
200
    return dict().try_erase(key);
459✔
201
}
459✔
202

203
void Dictionary::remove_all()
204
{
374✔
205
    verify_in_transaction();
374✔
206
    dict().clear();
374✔
207
}
247✔
208

209
Obj Dictionary::get_object(StringData key)
20✔
210
{
22✔
211
    auto& dictionary = dict();
22✔
212
    auto obj = dictionary.get_object(key);
2✔
213
    record_audit_read(obj);
2✔
214
    return obj;
67✔
215
}
67✔
216

65✔
217
Mixed Dictionary::get_any(StringData key)
65✔
218
{
83✔
219
    auto value = dict().get(key);
83✔
220
    record_audit_read(value);
372✔
221
    return value;
372✔
222
}
372✔
223

289✔
224
Mixed Dictionary::get_any(size_t ndx) const
225
{
226
    verify_attached();
185✔
227
    auto value = dict().get_any(ndx);
185✔
228
    record_audit_read(value);
185✔
229
    return value;
185✔
230
}
231

232
util::Optional<Mixed> Dictionary::try_get_any(StringData key) const
248✔
233
{
363✔
234
    auto value = dict().try_get(key);
363✔
235
    if (value)
363✔
236
        record_audit_read(*value);
114✔
237
    return value;
115✔
238
}
118✔
239

3✔
240
std::pair<StringData, Mixed> Dictionary::get_pair(size_t ndx) const
3✔
241
{
106✔
242
    verify_attached();
106✔
243
    auto pair = dict().get_pair(ndx);
106✔
244
    record_audit_read(pair.second);
103✔
245
    return {pair.first.get_string(), pair.second};
103✔
246
}
187✔
247

84✔
248
size_t Dictionary::find_any(Mixed value) const
84✔
249
{
330✔
250
    return dict().find_any(value);
330✔
251
}
246✔
252

253
bool Dictionary::contains(StringData key) const
1✔
254
{
490✔
255
    return dict().contains(key);
490✔
256
}
490✔
257

1✔
258
Obj Dictionary::get_object(StringData key) const
1✔
259
{
2✔
260
    auto k = dict().get(key).get<ObjKey>();
2✔
261
    return dict().get_target_table()->get_object(k);
118✔
262
}
118✔
263

116✔
264
Results Dictionary::snapshot() const
115✔
265
{
116✔
266
    return as_results().snapshot();
116✔
267
}
268

269
Results Dictionary::get_keys() const
103✔
270
{
1,283✔
271
    verify_attached();
1,283✔
272
    return Results(m_realm,
1,283✔
273
                   std::make_shared<DictionaryKeyAdapter>(std::dynamic_pointer_cast<realm::Dictionary>(m_coll_base)));
1,283✔
274
}
1,283✔
275

276
Results Dictionary::get_values() const
277
{
1,466✔
278
    return as_results();
1,466✔
279
}
1,466✔
280

281
Dictionary::Iterator Dictionary::begin() const
282
{
570✔
283
    return dict().begin();
570✔
284
}
570✔
285

286
Dictionary::Iterator Dictionary::end() const
287
{
2✔
288
    return dict().end();
2✔
289
}
2✔
290

2✔
291
namespace {
292
class NotificationHandler {
293
public:
294
    NotificationHandler(realm::Dictionary& dict, Dictionary::CBFunc cb)
295
        : m_dict(dict)
296
        , m_prev_rt(static_cast<Transaction*>(dict.get_table()->get_parent_group())->duplicate())
297
        , m_prev_dict(static_cast<realm::Dictionary*>(m_prev_rt->import_copy_of(dict).release()))
298
        , m_cb(std::move(cb))
1,180✔
299
    {
1,203✔
300
    }
1,203✔
301

1,180✔
302
    void operator()(CollectionChangeSet const& c)
1,180✔
303
    {
86✔
304
        size_t max_keys = c.deletions.count() + c.insertions.count() + c.modifications.count();
86✔
305
        DictionaryChangeSet changes(max_keys);
1,307✔
306

1,307✔
307
        if (max_keys) {
1,307✔
308
            for (auto ndx : c.deletions.as_indexes()) {
103✔
309
                changes.add_deletion(m_prev_dict->get_key(ndx));
103✔
310
            }
184✔
311
            for (auto ndx : c.insertions.as_indexes()) {
145✔
312
                changes.add_insertion(m_dict.get_key(ndx));
104✔
313
            }
23✔
314
            for (auto ndx : c.modifications_new.as_indexes()) {
64✔
315
                changes.add_modification(m_dict.get_key(ndx));
21✔
316
            }
21✔
317
        }
64✔
318

86✔
319
        if (c.collection_root_was_deleted) {
86✔
320
            changes.collection_root_was_deleted = true;
21✔
321
            m_prev_rt = nullptr;
21✔
322
        }
21✔
323
        else {
65✔
324
            REALM_ASSERT(m_dict.is_attached());
65✔
325
            auto current_tr = static_cast<Transaction*>(m_dict.get_table()->get_parent_group());
65✔
326
            m_prev_rt->advance_read(current_tr->get_version_of_current_transaction());
65✔
327
        }
110✔
328

131✔
329
        m_cb(std::move(changes));
86✔
330
    }
86✔
331

132✔
332
private:
132✔
333
    realm::Dictionary& m_dict;
132✔
334
    TransactionRef m_prev_rt;
335
    std::unique_ptr<realm::Dictionary> m_prev_dict;
132✔
336
    Dictionary::CBFunc m_cb;
188✔
337
};
188✔
338
} // namespace
188✔
339

24✔
340
NotificationToken Dictionary::add_key_based_notification_callback(CBFunc cb,
24✔
341
                                                                  std::optional<KeyPathArray> key_path_array) &
24✔
342
{
44✔
343
    return add_notification_callback(NotificationHandler(dict(), std::move(cb)), std::move(key_path_array));
44✔
344
}
44✔
345

88✔
346
Dictionary Dictionary::freeze(const std::shared_ptr<Realm>& frozen_realm) const
347
{
143✔
348
    auto frozen_dictionary(frozen_realm->import_copy_of(*m_coll_base));
33✔
349
    if (frozen_dictionary) {
33✔
350
        return Dictionary(frozen_realm, std::move(frozen_dictionary));
32✔
351
    }
120✔
352
    else {
111✔
353
        return Dictionary{};
111✔
354
    }
111✔
355
}
121✔
356

132✔
357
} // namespace object_store
358
} // namespace realm
132✔
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

© 2026 Coveralls, Inc