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

realm / realm-core / jorgen.edelbo_333

01 Jul 2024 07:21AM UTC coverage: 90.865% (-0.08%) from 90.948%
jorgen.edelbo_333

Pull #7826

Evergreen

jedelbo
Merge tag 'v14.10.2' into next-major
Pull Request #7826: Merge Next major

102912 of 181138 branches covered (56.81%)

3131 of 3738 new or added lines in 54 files covered. (83.76%)

80 existing lines in 14 files now uncovered.

217498 of 239364 relevant lines covered (90.86%)

6655796.15 hits per line

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

92.5
/src/realm/array_mixed.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2018 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/array_mixed.hpp>
20
#include <realm/array_basic.hpp>
21
#include <realm/dictionary.hpp>
22
#include <realm/impl/array_writer.hpp>
23

24
using namespace realm;
25

26
ArrayMixed::ArrayMixed(Allocator& a)
27
    : Array(a)
372,879✔
28
    , m_composite(a)
372,879✔
29
    , m_ints(a)
372,879✔
30
    , m_int_pairs(a)
372,879✔
31
    , m_strings(a)
372,879✔
32
    , m_refs(a)
372,879✔
33
{
746,328✔
34
    m_composite.set_parent(this, payload_idx_type);
746,328✔
35
}
746,328✔
36

37
void ArrayMixed::create()
38
{
51,030✔
39
    Array::create(type_HasRefs, false, payload_idx_size);
51,030✔
40
    m_composite.create(type_Normal);
51,030✔
41
    m_composite.update_parent();
51,030✔
42
}
51,030✔
43

44
void ArrayMixed::init_from_mem(MemRef mem) noexcept
45
{
495,495✔
46
    Array::init_from_mem(mem);
495,495✔
47
    m_composite.init_from_parent();
495,495✔
48
    m_ints.detach();
495,495✔
49
    m_int_pairs.detach();
495,495✔
50
    m_strings.detach();
495,495✔
51
    m_refs.detach();
495,495✔
52
}
495,495✔
53

54
void ArrayMixed::add(Mixed value)
55
{
168✔
56
    if (value.is_null()) {
168✔
57
        m_composite.add(0);
54✔
58
        return;
54✔
59
    }
54✔
60
    m_composite.add(store(value));
114✔
61
}
114✔
62

63

64
void ArrayMixed::set(size_t ndx, Mixed value)
65
{
37,800✔
66
    auto old_type = get_type(ndx);
37,800✔
67
    // If we replace a collections ref value with one of the
68
    // same type, then it is just an update of of the
69
    // ref stored in the parent. If the new type is a different
70
    // type then it means that we are overwriting a collection
71
    // with some other value and hence the collection must be
72
    // destroyed as well as the possible key.
73
    bool destroy_collection = !value.is_type(old_type);
37,800✔
74

75
    if (value.is_null()) {
37,800✔
76
        set_null(ndx);
1,878✔
77
    }
1,878✔
78
    else {
35,922✔
79
        erase_linked_payload(ndx, destroy_collection);
35,922✔
80
        m_composite.set(ndx, store(value));
35,922✔
81
    }
35,922✔
82

83
    if (destroy_collection && Array::size() > payload_idx_key) {
37,800✔
84
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
19,128✔
85
            Array keys(Array::get_alloc());
1,494✔
86
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
1,494✔
87
            keys.init_from_ref(ref);
1,494✔
88
            if (ndx < keys.size())
1,494✔
89
                keys.set(ndx, 0);
1,446✔
90
        }
1,494✔
91
    }
19,128✔
92
}
37,800✔
93

94
void ArrayMixed::insert(size_t ndx, Mixed value)
95
{
155,643✔
96
    if (value.is_null()) {
155,643✔
97
        m_composite.insert(ndx, 0);
28,146✔
98
    }
28,146✔
99
    else {
127,497✔
100
        m_composite.insert(ndx, store(value));
127,497✔
101
    }
127,497✔
102
    if (Array::size() > payload_idx_key) {
155,643✔
103
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
155,391✔
104
            Array keys(Array::get_alloc());
1,878✔
105
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
1,878✔
106
            keys.init_from_ref(ref);
1,878✔
107
            keys.insert(ndx, 0);
1,878✔
108
        }
1,878✔
109
    }
155,391✔
110
}
155,643✔
111

112
void ArrayMixed::set_null(size_t ndx)
113
{
1,878✔
114
    auto val = m_composite.get(ndx);
1,878✔
115
    if (val) {
1,878✔
116
        erase_linked_payload(ndx, true);
1,854✔
117
        m_composite.set(ndx, 0);
1,854✔
118
    }
1,854✔
119
}
1,878✔
120

121
Mixed ArrayMixed::get(size_t ndx) const
122
{
1,821,384✔
123
    int64_t val = m_composite.get(ndx);
1,821,384✔
124

125
    if (val) {
1,821,384✔
126
        int64_t int_val = val >> s_data_shift;
1,773,831✔
127
        size_t payload_ndx = size_t(int_val);
1,773,831✔
128
        DataType type = DataType((val & s_data_type_mask) - 1);
1,773,831✔
129
        switch (type) {
1,773,831✔
130
            case type_Int: {
312,411✔
131
                if (val & s_payload_idx_mask) {
312,411✔
132
                    ensure_int_array();
4,632✔
133
                    return Mixed(m_ints.get(payload_ndx));
4,632✔
134
                }
4,632✔
135
                return Mixed(int_val);
307,779✔
136
            }
312,411✔
137
            case type_Bool:
20,070✔
138
                return Mixed(int_val != 0);
20,070✔
139
            case type_Float:
27,363✔
140
                ensure_int_array();
27,363✔
141
                return Mixed(type_punning<float>(m_ints.get(payload_ndx)));
27,363✔
142
            case type_Double:
59,706✔
143
                ensure_int_array();
59,706✔
144
                return Mixed(type_punning<double>(m_ints.get(payload_ndx)));
59,706✔
145
            case type_String: {
126,420✔
146
                ensure_string_array();
126,420✔
147
                REALM_ASSERT(size_t(int_val) < m_strings.size());
126,420✔
148
                return Mixed(m_strings.get(payload_ndx));
126,420✔
149
            }
312,411✔
150
            case type_Binary: {
20,031✔
151
                ensure_string_array();
20,031✔
152
                REALM_ASSERT(size_t(int_val) < m_strings.size());
20,031✔
153
                auto s = m_strings.get(payload_ndx);
20,031✔
154
                return Mixed(BinaryData(s.data(), s.size()));
20,031✔
155
            }
312,411✔
156
            case type_Timestamp: {
18,177✔
157
                ensure_int_pair_array();
18,177✔
158
                payload_ndx <<= 1;
18,177✔
159
                REALM_ASSERT(payload_ndx + 1 < m_int_pairs.size());
18,177✔
160
                return Mixed(Timestamp(m_int_pairs.get(payload_ndx), int32_t(m_int_pairs.get(payload_ndx + 1))));
18,177✔
161
            }
312,411✔
162
            case type_ObjectId: {
26,856✔
163
                ensure_string_array();
26,856✔
164
                REALM_ASSERT(size_t(int_val) < m_strings.size());
26,856✔
165
                auto s = m_strings.get(payload_ndx);
26,856✔
166
                ObjectId id;
26,856✔
167
                memcpy(&id, s.data(), sizeof(ObjectId));
26,856✔
168
                return Mixed(id);
26,856✔
169
            }
312,411✔
170
            case type_Decimal: {
51,615✔
171
                ensure_int_pair_array();
51,615✔
172
                Decimal128::Bid128 raw;
51,615✔
173
                payload_ndx <<= 1;
51,615✔
174
                REALM_ASSERT(payload_ndx + 1 < m_int_pairs.size());
51,615✔
175
                raw.w[0] = m_int_pairs.get(payload_ndx);
51,615✔
176
                raw.w[1] = m_int_pairs.get(payload_ndx + 1);
51,615✔
177
                return Mixed(Decimal128(raw));
51,615✔
178
            }
312,411✔
179
            case type_Link:
✔
180
                ensure_int_array();
×
181
                return Mixed(ObjKey(m_ints.get(payload_ndx)));
×
182
            case type_TypedLink: {
978,411✔
183
                ensure_int_pair_array();
978,411✔
184
                payload_ndx <<= 1;
978,411✔
185
                REALM_ASSERT(payload_ndx + 1 < m_int_pairs.size());
978,411✔
186
                ObjLink ret{TableKey(uint32_t(m_int_pairs.get(payload_ndx))),
978,411✔
187
                            ObjKey(m_int_pairs.get(payload_ndx + 1))};
978,411✔
188
                return Mixed(ret);
978,411✔
189
            }
312,411✔
190
            case type_UUID: {
29,022✔
191
                ensure_string_array();
29,022✔
192
                REALM_ASSERT(size_t(int_val) < m_strings.size());
29,022✔
193
                auto s = m_strings.get(payload_ndx);
29,022✔
194
                UUID::UUIDBytes bytes{};
29,022✔
195
                std::copy_n(s.data(), bytes.size(), bytes.begin());
29,022✔
196
                return Mixed(UUID(bytes));
29,022✔
197
            }
312,411✔
198
            default:
103,752✔
199
                if (size_t((val & s_payload_idx_mask) >> s_payload_idx_shift) == payload_idx_ref) {
103,752✔
200
                    ensure_ref_array();
103,752✔
201
                    return Mixed(m_refs.get(payload_ndx), CollectionType(int(type)));
103,752✔
202
                }
103,752✔
203
                break;
×
204
        }
1,773,831✔
205
    }
1,773,831✔
206

207
    return {};
47,553✔
208
}
1,821,384✔
209

210
void ArrayMixed::clear()
211
{
690✔
212
    m_composite.clear();
690✔
213
    m_ints.destroy();
690✔
214
    m_int_pairs.destroy();
690✔
215
    m_strings.destroy();
690✔
216
    m_refs.destroy_deep();
690✔
217
    Array::set(payload_idx_int, 0);
690✔
218
    Array::set(payload_idx_pair, 0);
690✔
219
    Array::set(payload_idx_str, 0);
690✔
220
    if (Array::size() > payload_idx_ref) {
690✔
221
        Array::set(payload_idx_ref, 0);
690✔
222
    }
690✔
223
    if (Array::size() > payload_idx_key) {
690✔
224
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
690✔
225
            Array::destroy(ref, m_composite.get_alloc());
6✔
226
            Array::set(payload_idx_key, 0);
6✔
227
        }
6✔
228
    }
690✔
229
}
690✔
230

231
void ArrayMixed::erase(size_t ndx)
232
{
21,396✔
233
    erase_linked_payload(ndx, true);
21,396✔
234
    m_composite.erase(ndx);
21,396✔
235
    if (Array::size() > payload_idx_key) {
21,396✔
236
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
21,384✔
237
            Array keys(Array::get_alloc());
402✔
238
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
402✔
239
            keys.init_from_ref(ref);
402✔
240
            keys.erase(ndx);
402✔
241
        }
402✔
242
    }
21,384✔
243
}
21,396✔
244

245
void ArrayMixed::move(ArrayMixed& dst, size_t ndx)
246
{
6✔
247
    auto sz = size();
6✔
248
    size_t i = ndx;
6✔
249
    while (i < sz) {
60✔
250
        auto val = get(i++);
54✔
251
        dst.add(val);
54✔
252
    }
54✔
253
    if (Array::size() > payload_idx_key) {
6✔
254
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
6✔
255
            dst.ensure_keys();
×
256
            Array keys(Array::get_alloc());
×
257
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
×
258
            keys.init_from_ref(ref);
×
259
            for (size_t j = 0, i = ndx; i < sz; i++, j++) {
×
260
                dst.set_key(j, keys.get(i));
×
261
            }
×
262
            keys.truncate(ndx);
×
263
        }
×
264
    }
6✔
265
    while (i > ndx) {
60✔
266
        erase_linked_payload(--i, false);
54✔
267
    }
54✔
268
    m_composite.truncate(ndx);
6✔
269
}
6✔
270

271
size_t ArrayMixed::find_first(Mixed value, size_t begin, size_t end) const noexcept
272
{
67,464✔
273
    if (value.is_null()) {
67,464✔
274
        return m_composite.find_first(0, begin, end);
468✔
275
    }
468✔
276
    DataType type = value.get_type();
66,996✔
277
    if (end == realm::npos)
66,996✔
278
        end = size();
6✔
279

280
    for (size_t i = begin; i < end; i++) {
633,534✔
281
        if (Mixed::data_types_are_comparable(this->get_type(i), type) && get(i) == value) {
630,780✔
282
            return i;
64,242✔
283
        }
64,242✔
284
    }
630,780✔
285
    return realm::npos;
2,754✔
286
}
66,996✔
287

288
bool ArrayMixed::ensure_keys()
289
{
4,896✔
290
    if (Array::size() < payload_idx_key + 1 || Array::get(payload_idx_key) == 0) {
4,896✔
291
        Array keys(Array::get_alloc());
3,426✔
292
        keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
3,426✔
293
        keys.create(type_Normal, false, size(), 0);
3,426✔
294
        keys.update_parent();
3,426✔
295

296
        return false;
3,426✔
297
    }
3,426✔
298
    return true;
1,470✔
299
}
4,896✔
300

301
size_t ArrayMixed::find_key(int64_t key) const noexcept
302
{
68,076✔
303
    if (ref_type ref = get_as_ref(payload_idx_key)) {
68,076✔
304
        Array keys(Array::get_alloc());
68,052✔
305
        keys.init_from_ref(ref);
68,052✔
306
        return keys.find_first(key);
68,052✔
307
    }
68,052✔
308
    return realm::not_found;
24✔
309
}
68,076✔
310

311
void ArrayMixed::set_key(size_t ndx, int64_t key)
312
{
8,280✔
313
    Array keys(Array::get_alloc());
8,280✔
314
    ensure_array_accessor(keys, payload_idx_key);
8,280✔
315
    while (keys.size() <= ndx) {
11,184✔
316
        keys.add(0);
2,904✔
317
    }
2,904✔
318
    keys.set(ndx, key);
8,280✔
319
}
8,280✔
320

321
int64_t ArrayMixed::get_key(size_t ndx) const
322
{
48,090✔
323
    Array keys(Array::get_alloc());
48,090✔
324
    if (ref_type ref = get_as_ref(payload_idx_key)) {
48,090✔
325
        keys.init_from_ref(ref);
48,090✔
326
        return (ndx < keys.size()) ? keys.get(ndx) : 0;
48,090✔
327
    }
48,090✔
UNCOV
328
    return 0;
×
329
}
48,090✔
330

331
void ArrayMixed::verify() const
332
{
14,946✔
333
    // TODO: Implement
334
}
14,946✔
335

336
ref_type ArrayMixed::typed_write(ref_type top_ref, _impl::ArrayWriterBase& out, Allocator& alloc)
337
{
74,397✔
338
    if (out.only_modified && alloc.is_read_only(top_ref))
74,397✔
NEW
339
        return top_ref;
×
340

341
    ArrayRef top(alloc);
74,397✔
342
    top.init_from_ref(top_ref);
74,397✔
343
    size_t sz = top.size();
74,397✔
344
    TempArray written_leaf(sz);
74,397✔
345

346
    /*
347
     Mixed stores things using different arrays. We need to take into account this in order to
348
     understand what we need to compress and what we can instead leave not compressed.
349

350
     The main subarrays are:
351

352
     composite array : index 0
353
     int array : index 1
354
     pair_int array: index 2
355
     string array: index 3
356
     ref array: index 4
357
     key array: index 5
358

359
     Description of each array:
360
     1. composite array: the data stored here is either a small int (< 32 bits) or an offset to one of
361
        the other arrays where the actual data is.
362
     2. int and pair int arrays, they are used for storing integers, timestamps, floats, doubles,
363
     decimals, links. In general we can compress them, but we need to be careful, controlling the col_type
364
     should prevent compressing data that we want to leave in the current format.
365
     3. string array is for strings and binary data (no compression for now)
366
     4. ref array is actually storing refs to collections. they can only be BPlusTree<int, Mixed> or
367
     BPlusTree<string, Mixed>.
368
     5. key array stores unique identifiers for collections in mixed (integers that can be compressed)
369
     */
370
    Array composite(alloc);
74,397✔
371
    composite.init_from_ref(top.get_as_ref(0));
74,397✔
372
    written_leaf.set_as_ref(0, composite.write(out, true, out.only_modified, false));
74,397✔
373
    for (size_t i = 1; i < sz; ++i) {
446,355✔
374
        auto ref = top.get(i);
371,958✔
375
        ref_type new_ref = ref;
371,958✔
376
        if (ref && !(out.only_modified && alloc.is_read_only(ref))) {
371,958✔
377
            if (i < 3) { // int, and pair_int
59,439✔
378
                // integer arrays
379
                new_ref = Array::write(ref, alloc, out, out.only_modified, out.compress);
26,973✔
380
            }
26,973✔
381
            else if (i == 4) { // collection in mixed
32,466✔
382
                ArrayRef arr_ref(alloc);
10,344✔
383
                arr_ref.init_from_ref(ref);
10,344✔
384
                auto ref_sz = arr_ref.size();
10,344✔
385
                TempArray written_ref_leaf(ref_sz);
10,344✔
386

387
                for (size_t k = 0; k < ref_sz; k++) {
21,750✔
388
                    ref_type new_sub_ref = 0;
11,406✔
389
                    if (auto sub_ref = arr_ref.get(k)) {
11,406✔
390
                        auto header = alloc.translate(sub_ref);
9,930✔
391
                        // Now we have to find out if the nested collection is a
392
                        // dictionary or a list. If the top array has a size of 2
393
                        // and it is not a BplusTree inner node, then it is a dictionary
394
                        if (NodeHeader::get_size_from_header(header) == 2 &&
9,930✔
395
                            !NodeHeader::get_is_inner_bptree_node_from_header(header)) {
9,930✔
396
                            new_sub_ref = Dictionary::typed_write(sub_ref, out, alloc);
4,764✔
397
                        }
4,764✔
398
                        else {
5,166✔
399
                            new_sub_ref = BPlusTree<Mixed>::typed_write(sub_ref, out, alloc);
5,166✔
400
                        }
5,166✔
401
                    }
9,930✔
402
                    written_ref_leaf.set_as_ref(k, new_sub_ref);
11,406✔
403
                }
11,406✔
404
                new_ref = written_ref_leaf.write(out);
10,344✔
405
            }
10,344✔
406
            else if (i == 5) { // unique keys associated to collections in mixed
22,122✔
407
                new_ref = Array::write(ref, alloc, out, out.only_modified, out.compress);
6,738✔
408
            }
6,738✔
409
            else {
15,384✔
410
                // all the rest we don't want to compress it, at least for now (strings will be needed)
411
                new_ref = Array::write(ref, alloc, out, out.only_modified, false);
15,384✔
412
            }
15,384✔
413
        }
59,439✔
414
        written_leaf.set(i, new_ref);
371,958✔
415
    }
371,958✔
416
    return written_leaf.write(out);
74,397✔
417
}
74,397✔
418

419
void ArrayMixed::ensure_array_accessor(Array& arr, size_t ndx_in_parent) const
420
{
1,362,573✔
421
    if (!arr.is_attached()) {
1,362,573✔
422
        ref_type ref = get_as_ref(ndx_in_parent);
264,675✔
423
        arr.set_parent(const_cast<ArrayMixed*>(this), ndx_in_parent);
264,675✔
424
        if (ref) {
264,675✔
425
            arr.init_from_ref(ref);
239,076✔
426
        }
239,076✔
427
        else {
25,599✔
428
            arr.create(ndx_in_parent == payload_idx_ref ? type_HasRefs : type_Normal);
25,599✔
429
            arr.update_parent();
25,599✔
430
        }
25,599✔
431
    }
264,675✔
432
}
1,362,573✔
433

434
void ArrayMixed::ensure_int_array() const
435
{
112,914✔
436
    ensure_array_accessor(m_ints, payload_idx_int);
112,914✔
437
}
112,914✔
438

439
void ArrayMixed::ensure_int_pair_array() const
440
{
1,104,429✔
441
    ensure_array_accessor(m_int_pairs, payload_idx_pair);
1,104,429✔
442
}
1,104,429✔
443

444
void ArrayMixed::ensure_string_array() const
445
{
252,357✔
446
    if (!m_strings.is_attached()) {
252,357✔
447
        ref_type ref = get_as_ref(payload_idx_str);
80,376✔
448
        m_strings.set_parent(const_cast<ArrayMixed*>(this), payload_idx_str);
80,376✔
449
        if (ref) {
80,376✔
450
            m_strings.init_from_ref(ref);
61,542✔
451
        }
61,542✔
452
        else {
18,834✔
453
            m_strings.create();
18,834✔
454
            m_strings.update_parent();
18,834✔
455
        }
18,834✔
456
    }
80,376✔
457
}
252,357✔
458

459
void ArrayMixed::ensure_ref_array() const
460
{
136,956✔
461
    while (Array::size() < payload_idx_ref + 1) {
136,956✔
462
        const_cast<ArrayMixed*>(this)->Array::add(0);
×
463
    }
×
464
    ensure_array_accessor(m_refs, payload_idx_ref);
136,956✔
465
}
136,956✔
466

467
void ArrayMixed::replace_index(size_t old_ndx, size_t new_ndx, size_t payload_arr_index)
468
{
13,035✔
469
    if (old_ndx != new_ndx) {
13,035✔
470
        size_t sz = m_composite.size();
13,035✔
471
        for (size_t i = 0; i != sz; i++) {
765,531✔
472
            int64_t val = m_composite.get(i);
765,531✔
473
            if (size_t((val & s_payload_idx_mask) >> s_payload_idx_shift) == payload_arr_index &&
765,531✔
474
                (val >> s_data_shift) == int64_t(old_ndx)) {
765,531✔
475
                m_composite.set(i, int64_t(new_ndx << s_data_shift) | (val & 0xff));
13,035✔
476
                return;
13,035✔
477
            }
13,035✔
478
        }
765,531✔
479
    }
13,035✔
480
}
13,035✔
481

482
void ArrayMixed::erase_linked_payload(size_t ndx, bool free_linked_arrays)
483
{
59,226✔
484
    auto val = m_composite.get(ndx);
59,226✔
485
    auto payload_arr_index = size_t((val & s_payload_idx_mask) >> s_payload_idx_shift);
59,226✔
486

487
    if (payload_arr_index) {
59,226✔
488
        // A value is stored in one of the payload arrays
489
        size_t last_ndx = 0;
35,856✔
490
        size_t erase_ndx = size_t(val >> s_data_shift);
35,856✔
491
        // Clean up current value by moving last over
492
        switch (payload_arr_index) {
35,856✔
493
            case payload_idx_int: {
4,518✔
494
                ensure_int_array();
4,518✔
495
                last_ndx = m_ints.size() - 1;
4,518✔
496
                if (erase_ndx != last_ndx) {
4,518✔
497
                    m_ints.set(erase_ndx, m_ints.get(last_ndx));
3,297✔
498
                    replace_index(last_ndx, erase_ndx, payload_arr_index);
3,297✔
499
                }
3,297✔
500
                m_ints.erase(last_ndx);
4,518✔
501
                break;
4,518✔
502
            }
×
503
            case payload_idx_str: {
6,072✔
504
                ensure_string_array();
6,072✔
505
                last_ndx = m_strings.size() - 1;
6,072✔
506
                if (erase_ndx != last_ndx) {
6,072✔
507
                    StringData tmp = m_strings.get(last_ndx);
3,336✔
508
                    std::string tmp_val(tmp.data(), tmp.size());
3,336✔
509
                    m_strings.set(erase_ndx, StringData(tmp_val));
3,336✔
510
                    replace_index(last_ndx, erase_ndx, payload_arr_index);
3,336✔
511
                }
3,336✔
512
                m_strings.erase(last_ndx);
6,072✔
513
                break;
6,072✔
514
            }
×
515
            case payload_idx_pair: {
12,084✔
516
                ensure_int_pair_array();
12,084✔
517
                last_ndx = m_int_pairs.size() - 2;
12,084✔
518
                erase_ndx <<= 1;
12,084✔
519
                if (erase_ndx != last_ndx) {
12,084✔
520
                    m_int_pairs.set(erase_ndx, m_int_pairs.get(last_ndx));
5,382✔
521
                    m_int_pairs.set(erase_ndx + 1, m_int_pairs.get(last_ndx + 1));
5,382✔
522
                    replace_index(last_ndx >> 1, erase_ndx >> 1, payload_arr_index);
5,382✔
523
                }
5,382✔
524
                m_int_pairs.truncate(last_ndx);
12,084✔
525
                break;
12,084✔
526
            }
×
527
            case payload_idx_ref: {
13,182✔
528
                ensure_ref_array();
13,182✔
529
                last_ndx = m_refs.size() - 1;
13,182✔
530
                auto old_ref = m_refs.get(erase_ndx);
13,182✔
531
                if (erase_ndx != last_ndx) {
13,182✔
532
                    m_refs.set(erase_ndx, m_refs.get(last_ndx));
1,020✔
533
                    replace_index(last_ndx, erase_ndx, payload_arr_index);
1,020✔
534
                }
1,020✔
535
                m_refs.erase(last_ndx);
13,182✔
536
                if (old_ref && free_linked_arrays)
13,182✔
537
                    Array::destroy_deep(old_ref, m_composite.get_alloc());
1,020✔
538
                break;
13,182✔
539
            }
×
540
            default:
✔
541
                break;
×
542
        }
35,856✔
543
    }
35,856✔
544
}
59,226✔
545

546
int64_t ArrayMixed::store(const Mixed& value)
547
{
163,533✔
548
    DataType type = value.get_type();
163,533✔
549
    int64_t val;
163,533✔
550
    switch (type) {
163,533✔
551
        case type_Int: {
40,047✔
552
            int64_t int_val = value.get_int();
40,047✔
553
            if (std::numeric_limits<int32_t>::min() <= int_val && int_val <= std::numeric_limits<int32_t>::max()) {
40,047✔
554
                val = (static_cast<uint64_t>(int_val) << s_data_shift);
35,886✔
555
            }
35,886✔
556
            else {
4,161✔
557
                ensure_int_array();
4,161✔
558
                size_t ndx = m_ints.size();
4,161✔
559
                m_ints.add(int_val);
4,161✔
560
                val = int64_t(ndx << s_data_shift) | (payload_idx_int << s_payload_idx_shift);
4,161✔
561
            }
4,161✔
562
            break;
40,047✔
563
        }
×
564
        case type_Bool:
2,832✔
565
            val = (value.get_bool() << s_data_shift);
2,832✔
566
            break;
2,832✔
567
        case type_Float: {
6,006✔
568
            ensure_int_array();
6,006✔
569
            size_t ndx = m_ints.size();
6,006✔
570
            m_ints.add(type_punning<int64_t>(value.get_float()));
6,006✔
571
            val = int64_t(ndx << s_data_shift) | (payload_idx_int << s_payload_idx_shift);
6,006✔
572
            break;
6,006✔
573
        }
×
574
        case type_Double: {
6,528✔
575
            ensure_int_array();
6,528✔
576
            size_t ndx = m_ints.size();
6,528✔
577
            m_ints.add(type_punning<int64_t>(value.get_double()));
6,528✔
578
            val = int64_t(ndx << s_data_shift) | (payload_idx_int << s_payload_idx_shift);
6,528✔
579
            break;
6,528✔
580
        }
×
581
        case type_String: {
30,168✔
582
            ensure_string_array();
30,168✔
583
            size_t ndx = m_strings.size();
30,168✔
584
            m_strings.add(value.get_string());
30,168✔
585
            val = int64_t(ndx << s_data_shift) | (payload_idx_str << s_payload_idx_shift);
30,168✔
586
            break;
30,168✔
587
        }
×
588
        case type_Binary: {
5,052✔
589
            ensure_string_array();
5,052✔
590
            size_t ndx = m_strings.size();
5,052✔
591
            auto bin = value.get<Binary>();
5,052✔
592
            m_strings.add(StringData(bin.data(), bin.size()));
5,052✔
593
            val = int64_t(ndx << s_data_shift) | (payload_idx_str << s_payload_idx_shift);
5,052✔
594
            break;
5,052✔
595
        }
×
596
        case type_Timestamp: {
3,528✔
597
            ensure_int_pair_array();
3,528✔
598
            size_t ndx = m_int_pairs.size() / 2;
3,528✔
599
            auto t = value.get_timestamp();
3,528✔
600
            m_int_pairs.add(t.get_seconds());
3,528✔
601
            m_int_pairs.add(t.get_nanoseconds());
3,528✔
602
            val = int64_t(ndx << s_data_shift) | (payload_idx_pair << s_payload_idx_shift);
3,528✔
603
            break;
3,528✔
604
        }
×
605
        case type_ObjectId: {
3,684✔
606
            ensure_string_array();
3,684✔
607
            size_t ndx = m_strings.size();
3,684✔
608
            auto id = value.get<ObjectId>();
3,684✔
609
            char buffer[sizeof(ObjectId)];
3,684✔
610
            memcpy(buffer, &id, sizeof(ObjectId));
3,684✔
611
            m_strings.add(StringData(buffer, sizeof(ObjectId)));
3,684✔
612
            val = int64_t(ndx << s_data_shift) | (payload_idx_str << s_payload_idx_shift);
3,684✔
613
            break;
3,684✔
614
        }
×
615
        case type_Decimal: {
5,538✔
616
            ensure_int_pair_array();
5,538✔
617
            size_t ndx = m_int_pairs.size() / 2;
5,538✔
618
            auto t = value.get<Decimal128>();
5,538✔
619
            m_int_pairs.add(t.raw()->w[0]);
5,538✔
620
            m_int_pairs.add(t.raw()->w[1]);
5,538✔
621
            val = int64_t(ndx << s_data_shift) | (payload_idx_pair << s_payload_idx_shift);
5,538✔
622
            break;
5,538✔
623
        }
×
624
        case type_Link: {
✔
625
            ensure_int_array();
×
626
            size_t ndx = m_ints.size();
×
627
            m_ints.add(value.get<ObjKey>().value);
×
628
            val = int64_t(ndx << s_data_shift) | (payload_idx_int << s_payload_idx_shift);
×
629
            break;
×
630
        }
×
631
        case type_TypedLink: {
35,076✔
632
            ensure_int_pair_array();
35,076✔
633
            size_t ndx = m_int_pairs.size() / 2;
35,076✔
634
            auto t = value.get<ObjLink>();
35,076✔
635
            m_int_pairs.add(int64_t(t.get_table_key().value));
35,076✔
636
            m_int_pairs.add(t.get_obj_key().value);
35,076✔
637
            val = int64_t(ndx << s_data_shift) | (payload_idx_pair << s_payload_idx_shift);
35,076✔
638
            break;
35,076✔
639
        }
×
640
        case type_UUID: {
5,052✔
641
            ensure_string_array();
5,052✔
642
            size_t ndx = m_strings.size();
5,052✔
643
            auto id = value.get<UUID>();
5,052✔
644
            const auto uuid_bytes = id.to_bytes();
5,052✔
645
            m_strings.add(StringData(reinterpret_cast<const char*>(uuid_bytes.data()), uuid_bytes.size()));
5,052✔
646
            val = int64_t(ndx << s_data_shift) | (payload_idx_str << s_payload_idx_shift);
5,052✔
647
            break;
5,052✔
648
        }
×
649
        default:
20,022✔
650
            REALM_ASSERT(type == type_List || type == type_Dictionary);
20,022✔
651
            ensure_ref_array();
20,022✔
652
            size_t ndx = m_refs.size();
20,022✔
653
            m_refs.add(value.get_ref());
20,022✔
654
            val = int64_t(ndx << s_data_shift) | (payload_idx_ref << s_payload_idx_shift);
20,022✔
655
            break;
20,022✔
656
    }
163,533✔
657
    return val + int(type) + 1;
163,530✔
658
}
163,533✔
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