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

realm / realm-core / github_pull_request_281750

30 Oct 2023 03:37PM UTC coverage: 90.528% (-1.0%) from 91.571%
github_pull_request_281750

Pull #6073

Evergreen

jedelbo
Log free space and history sizes when opening file
Pull Request #6073: Merge next-major

95488 of 175952 branches covered (0.0%)

8973 of 12277 new or added lines in 149 files covered. (73.09%)

622 existing lines in 51 files now uncovered.

233503 of 257934 relevant lines covered (90.53%)

6533720.56 hits per line

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

81.36
/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
    CollectionBasePtr 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 noexcept override
86
    {
2,850✔
87
        return m_dictionary->has_changed();
2,850✔
88
    }
2,850✔
89

90
    FullPath get_path() const noexcept final
NEW
91
    {
×
NEW
92
        return m_dictionary->get_path();
×
NEW
93
    }
×
94

95
    Path get_short_path() const noexcept final
NEW
96
    {
×
NEW
97
        return m_dictionary->get_short_path();
×
NEW
98
    }
×
99

100
    StablePath get_stable_path() const noexcept final
NEW
101
    {
×
NEW
102
        return m_dictionary->get_stable_path();
×
NEW
103
    }
×
104

105
    // -------------------------------------------------------------------------
106
    // Things not applicable to the adapter
107

108
    // We currently only support string keys which means these aren't reachable
109
    // as Results will handle the type-checks
110
    util::Optional<Mixed> min(size_t* = nullptr) const override
111
    {
×
112
        REALM_TERMINATE("not implemented");
×
113
    }
×
114
    util::Optional<Mixed> max(size_t* = nullptr) const override
115
    {
×
116
        REALM_TERMINATE("not implemented");
×
117
    }
×
118
    util::Optional<Mixed> sum(size_t* = nullptr) const override
119
    {
×
120
        REALM_TERMINATE("not implemented");
×
121
    }
×
122
    util::Optional<Mixed> avg(size_t* = nullptr) const override
123
    {
×
124
        REALM_TERMINATE("not implemented");
×
125
    }
×
126
    void set_owner(const Obj& obj, ColKey ck) override
NEW
127
    {
×
NEW
128
        m_dictionary->set_owner(obj, ck);
×
NEW
129
    }
×
130
    void set_owner(std::shared_ptr<CollectionParent> parent, CollectionParent::Index index) override
NEW
131
    {
×
NEW
132
        m_dictionary->set_owner(std::move(parent), index);
×
NEW
133
    }
×
134
    CollectionType get_collection_type() const noexcept override
NEW
135
    {
×
NEW
136
        return CollectionType::List;
×
NEW
137
    }
×
138

139
private:
140
    std::shared_ptr<Dictionary> m_dictionary;
141
};
142
} // anonymous namespace
143

144
void DictionaryChangeSet::add(std::vector<Mixed>& arr, const Mixed& key)
145
{
942✔
146
    arr.push_back(key);
942✔
147
    if (key.is_type(type_String)) {
942✔
148
        REALM_ASSERT(m_string_store.size() < m_string_store.capacity());
942✔
149
        m_string_store.emplace_back();
942✔
150
        arr.back().use_buffer(m_string_store.back());
942✔
151
    }
942✔
152
}
942✔
153

154
DictionaryChangeSet::DictionaryChangeSet(const DictionaryChangeSet& other)
155
{
18✔
156
    m_string_store.reserve(other.m_string_store.size());
18✔
157
    for (auto k : other.deletions) {
17✔
158
        add(deletions, k);
16✔
159
    }
16✔
160
    for (auto k : other.insertions) {
14✔
161
        add(insertions, k);
10✔
162
    }
10✔
163
    for (auto k : other.modifications) {
9✔
164
        add(modifications, k);
×
165
    }
×
166

9✔
167
    collection_root_was_deleted = other.collection_root_was_deleted;
18✔
168
    collection_was_cleared = other.collection_was_cleared;
18✔
169
}
18✔
170

171
DictionaryChangeSet& DictionaryChangeSet::operator=(const DictionaryChangeSet& other)
172
{
252✔
173
    m_string_store.reserve(other.m_string_store.size());
252✔
174

126✔
175
    m_string_store.clear();
252✔
176
    deletions.clear();
252✔
177
    insertions.clear();
252✔
178
    modifications.clear();
252✔
179

126✔
180
    for (auto k : other.deletions) {
366✔
181
        add(deletions, k);
366✔
182
    }
366✔
183
    for (auto k : other.insertions) {
147✔
184
        add(insertions, k);
42✔
185
    }
42✔
186
    for (auto k : other.modifications) {
147✔
187
        add(modifications, k);
42✔
188
    }
42✔
189

126✔
190
    collection_root_was_deleted = other.collection_root_was_deleted;
252✔
191
    collection_was_cleared = other.collection_was_cleared;
252✔
192
    return *this;
252✔
193
}
252✔
194

195

196
namespace object_store {
197

198
bool Dictionary::operator==(const Dictionary& rgt) const noexcept
199
{
548✔
200
    return dict() == rgt.dict();
548✔
201
}
548✔
202

203
bool Dictionary::operator!=(const Dictionary& rgt) const noexcept
204
{
254✔
205
    return !(*this == rgt);
254✔
206
}
254✔
207

208
Obj Dictionary::insert_embedded(StringData key)
209
{
40✔
210
    return dict().create_and_insert_linked_object(key);
40✔
211
}
40✔
212

213
std::pair<size_t, bool> Dictionary::insert_any(StringData key, Mixed value)
214
{
130✔
215
    auto [it, inserted] = dict().insert(key, value);
130✔
216
    return std::make_pair(it.index(), inserted);
130✔
217
}
130✔
218

219
void Dictionary::erase(StringData key)
220
{
578✔
221
    verify_in_transaction();
578✔
222
    dict().erase(key);
578✔
223
}
578✔
224

225
bool Dictionary::try_erase(StringData key)
226
{
370✔
227
    verify_in_transaction();
370✔
228
    return dict().try_erase(key);
370✔
229
}
370✔
230

231
void Dictionary::remove_all()
232
{
500✔
233
    verify_in_transaction();
500✔
234
    dict().clear();
500✔
235
}
500✔
236

237
Obj Dictionary::get_object(StringData key)
238
{
5✔
239
    auto& dictionary = dict();
5✔
240
    auto obj = dictionary.get_object(key);
5✔
241
    record_audit_read(obj);
5✔
242
    return obj;
5✔
243
}
5✔
244

245
Mixed Dictionary::get_any(StringData key)
246
{
167✔
247
    auto value = dict().get(key);
167✔
248
    record_audit_read(value);
167✔
249
    return value;
167✔
250
}
167✔
251

252
Mixed Dictionary::get_any(size_t ndx) const
253
{
1✔
254
    verify_attached();
1✔
255
    auto value = dict().get_any(ndx);
1✔
256
    record_audit_read(value);
1✔
257
    return value;
1✔
258
}
1✔
259

260
util::Optional<Mixed> Dictionary::try_get_any(StringData key) const
261
{
231✔
262
    auto value = dict().try_get(key);
231✔
263
    if (value)
231✔
264
        record_audit_read(*value);
229✔
265
    return value;
231✔
266
}
231✔
267

268
std::pair<StringData, Mixed> Dictionary::get_pair(size_t ndx) const
269
{
206✔
270
    verify_attached();
206✔
271
    auto pair = dict().get_pair(ndx);
206✔
272
    record_audit_read(pair.second);
206✔
273
    return {pair.first.get_string(), pair.second};
206✔
274
}
206✔
275

276
size_t Dictionary::find_any(Mixed value) const
277
{
492✔
278
    return dict().find_any(value);
492✔
279
}
492✔
280

281
bool Dictionary::contains(StringData key) const
282
{
978✔
283
    return dict().contains(key);
978✔
284
}
978✔
285

286
Obj Dictionary::get_object(StringData key) const
287
{
4✔
288
    auto k = dict().get(key).get<ObjKey>();
4✔
289
    return dict().get_target_table()->get_object(k);
4✔
290
}
4✔
291

292
Results Dictionary::snapshot() const
293
{
×
294
    return as_results().snapshot();
×
295
}
×
296

297
Results Dictionary::get_keys() const
298
{
2,360✔
299
    verify_attached();
2,360✔
300
    return Results(m_realm,
2,360✔
301
                   std::make_shared<DictionaryKeyAdapter>(std::dynamic_pointer_cast<realm::Dictionary>(m_coll_base)));
2,360✔
302
}
2,360✔
303

304
Results Dictionary::get_values() const
305
{
2,442✔
306
    return as_results();
2,442✔
307
}
2,442✔
308

309
Dictionary::Iterator Dictionary::begin() const
310
{
162✔
311
    return dict().begin();
162✔
312
}
162✔
313

314
Dictionary::Iterator Dictionary::end() const
315
{
×
316
    return dict().end();
×
317
}
×
318

319
namespace {
320
class NotificationHandler {
321
public:
322
    NotificationHandler(realm::Dictionary& dict, Dictionary::CBFunc cb)
323
        : m_dict(dict)
324
        , m_prev_rt(static_cast<Transaction*>(dict.get_table()->get_parent_group())->duplicate())
325
        , m_prev_dict(std::dynamic_pointer_cast<realm::Dictionary>(m_prev_rt->import_copy_of(dict)))
326
        , m_cb(std::move(cb))
327
    {
90✔
328
    }
90✔
329

330
    void operator()(CollectionChangeSet const& c)
331
    {
264✔
332
        size_t max_keys = c.deletions.count() + c.insertions.count() + c.modifications.count();
264✔
333
        DictionaryChangeSet changes(max_keys);
264✔
334

132✔
335
        if (max_keys) {
264✔
336
            for (auto ndx : c.deletions.as_indexes()) {
376✔
337
                changes.add_deletion(m_prev_dict->get_key(ndx));
376✔
338
            }
376✔
339
            for (auto ndx : c.insertions.as_indexes()) {
112✔
340
                changes.add_insertion(m_dict.get_key(ndx));
48✔
341
            }
48✔
342
            for (auto ndx : c.modifications_new.as_indexes()) {
109✔
343
                changes.add_modification(m_dict.get_key(ndx));
42✔
344
            }
42✔
345
        }
176✔
346

132✔
347
        if (c.collection_root_was_deleted) {
264✔
348
            changes.collection_root_was_deleted = true;
44✔
349
            m_prev_rt = nullptr;
44✔
350
        }
44✔
351
        else {
220✔
352
            REALM_ASSERT(m_dict.is_attached());
220✔
353
            auto current_tr = static_cast<Transaction*>(m_dict.get_table()->get_parent_group());
220✔
354
            m_prev_rt->advance_read(current_tr->get_version_of_current_transaction());
220✔
355
        }
220✔
356
        changes.collection_was_cleared = c.collection_was_cleared;
264✔
357

132✔
358
        m_cb(std::move(changes));
264✔
359
    }
264✔
360

361
private:
362
    realm::Dictionary& m_dict;
363
    TransactionRef m_prev_rt;
364
    DictionaryPtr m_prev_dict;
365
    Dictionary::CBFunc m_cb;
366
};
367
} // namespace
368

369
NotificationToken Dictionary::add_key_based_notification_callback(CBFunc cb,
370
                                                                  std::optional<KeyPathArray> key_path_array) &
371
{
90✔
372
    return add_notification_callback(NotificationHandler(dict(), std::move(cb)), std::move(key_path_array));
90✔
373
}
90✔
374

375
Dictionary Dictionary::freeze(const std::shared_ptr<Realm>& frozen_realm) const
376
{
22✔
377
    auto frozen_dictionary(frozen_realm->import_copy_of(*m_coll_base));
22✔
378
    if (frozen_dictionary) {
22✔
379
        return Dictionary(frozen_realm, std::move(frozen_dictionary));
20✔
380
    }
20✔
381
    else {
2✔
382
        return Dictionary{};
2✔
383
    }
2✔
384
}
22✔
385

386
} // namespace object_store
387
} // namespace realm
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