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

realm / realm-core / jorgen.edelbo_334

01 Jul 2024 07:22AM UTC coverage: 90.829% (-0.04%) from 90.865%
jorgen.edelbo_334

Pull #7803

Evergreen

jedelbo
Merge branch 'next-major' into feature/string-compression
Pull Request #7803: Feature/string compression

102912 of 180568 branches covered (56.99%)

1141 of 1267 new or added lines in 33 files covered. (90.06%)

172 existing lines in 24 files now uncovered.

218291 of 240332 relevant lines covered (90.83%)

7818396.4 hits per line

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

92.39
/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)
373,092✔
28
    , m_composite(a)
373,092✔
29
    , m_ints(a)
373,092✔
30
    , m_int_pairs(a)
373,092✔
31
    , m_strings(a)
373,092✔
32
    , m_refs(a)
373,092✔
33
{
746,463✔
34
    m_composite.set_parent(this, payload_idx_type);
746,463✔
35
}
746,463✔
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,531✔
46
    Array::init_from_mem(mem);
495,531✔
47
    m_composite.init_from_parent();
495,531✔
48
    m_ints.detach();
495,531✔
49
    m_int_pairs.detach();
495,531✔
50
    m_strings.detach();
495,531✔
51
    m_refs.detach();
495,531✔
52
}
495,531✔
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,646✔
96
    if (value.is_null()) {
155,646✔
97
        m_composite.insert(ndx, 0);
28,146✔
98
    }
28,146✔
99
    else {
127,500✔
100
        m_composite.insert(ndx, store(value));
127,500✔
101
    }
127,500✔
102
    if (Array::size() > payload_idx_key) {
155,646✔
103
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
155,394✔
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,394✔
110
}
155,646✔
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,345✔
123
    int64_t val = m_composite.get(ndx);
1,821,345✔
124

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

207
    return {};
47,559✔
208
}
1,821,345✔
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,390✔
233
    erase_linked_payload(ndx, true);
21,390✔
234
    m_composite.erase(ndx);
21,390✔
235
    if (Array::size() > payload_idx_key) {
21,390✔
236
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
21,378✔
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,378✔
243
}
21,390✔
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✔
328
    return 0;
×
329
}
48,090✔
330

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

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

341
    ArrayRef top(alloc);
74,394✔
342
    top.init_from_ref(top_ref);
74,394✔
343
    size_t sz = top.size();
74,394✔
344
    TempArray written_leaf(sz);
74,394✔
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
366
     4. ref array is actually storing refs to collections. They can only be Lst<Mixed> or Dictionary.
367
     5. key array stores unique identifiers for collections in mixed (integers that can be compressed)
368
     */
369
    Array composite(alloc);
74,394✔
370
    composite.init_from_ref(top.get_as_ref(0));
74,394✔
371
    written_leaf.set_as_ref(0, composite.write(out, true, out.only_modified, false));
74,394✔
372
    for (size_t i = 1; i < sz; ++i) {
446,340✔
373
        auto ref = top.get(i);
371,946✔
374
        ref_type new_ref = ref;
371,946✔
375
        if (ref && !(out.only_modified && alloc.is_read_only(ref))) {
371,946✔
376
            switch (i) {
59,415✔
377
                case payload_idx_int:
8,595✔
378
                    // integer array
379
                    new_ref = Array::write(ref, alloc, out, out.only_modified, out.compress);
8,595✔
380
                    break;
8,595✔
381
                case payload_idx_pair:
18,354✔
382
                    // integer array
383
                    new_ref = Array::write(ref, alloc, out, out.only_modified, out.compress);
18,354✔
384
                    break;
18,354✔
385
                case payload_idx_str:
15,384✔
386
                    new_ref = ArrayString::typed_write(ref, out, alloc);
15,384✔
387
                    break;
15,384✔
388
                case payload_idx_ref: {
10,344✔
389
                    // collection in mixed
390
                    ArrayRef arr_ref(alloc);
10,344✔
391
                    arr_ref.init_from_ref(ref);
10,344✔
392
                    auto ref_sz = arr_ref.size();
10,344✔
393
                    TempArray written_ref_leaf(ref_sz);
10,344✔
394

395
                    for (size_t k = 0; k < ref_sz; k++) {
21,750✔
396
                        ref_type new_sub_ref = 0;
11,406✔
397
                        if (auto sub_ref = arr_ref.get(k)) {
11,406✔
398
                            auto header = alloc.translate(sub_ref);
9,930✔
399
                            // Now we have to find out if the nested collection is a
400
                            // dictionary or a list. If the top array has a size of 2
401
                            // and it is not a BplusTree inner node, then it is a dictionary
402
                            if (NodeHeader::get_size_from_header(header) == 2 &&
9,930✔
403
                                !NodeHeader::get_is_inner_bptree_node_from_header(header)) {
9,930✔
404
                                new_sub_ref = Dictionary::typed_write(sub_ref, out, alloc);
4,764✔
405
                            }
4,764✔
406
                            else {
5,166✔
407
                                new_sub_ref = BPlusTree<Mixed>::typed_write(sub_ref, out, alloc);
5,166✔
408
                            }
5,166✔
409
                        }
9,930✔
410
                        written_ref_leaf.set_as_ref(k, new_sub_ref);
11,406✔
411
                    }
11,406✔
412
                    new_ref = written_ref_leaf.write(out);
10,344✔
413
                    break;
10,344✔
UNCOV
414
                }
×
415
                case payload_idx_key:
6,738✔
416
                    new_ref = Array::write(ref, alloc, out, out.only_modified, out.compress);
6,738✔
417
                    break;
6,738✔
418
            }
59,415✔
419
        }
59,415✔
420
        written_leaf.set(i, new_ref);
371,946✔
421
    }
371,946✔
422
    return written_leaf.write(out);
74,394✔
423
}
74,394✔
424

425
void ArrayMixed::ensure_array_accessor(Array& arr, size_t ndx_in_parent) const
426
{
1,362,495✔
427
    if (!arr.is_attached()) {
1,362,495✔
428
        ref_type ref = get_as_ref(ndx_in_parent);
264,633✔
429
        arr.set_parent(const_cast<ArrayMixed*>(this), ndx_in_parent);
264,633✔
430
        if (ref) {
264,633✔
431
            arr.init_from_ref(ref);
239,031✔
432
        }
239,031✔
433
        else {
25,602✔
434
            arr.create(ndx_in_parent == payload_idx_ref ? type_HasRefs : type_Normal);
25,602✔
435
            arr.update_parent();
25,602✔
436
        }
25,602✔
437
    }
264,633✔
438
}
1,362,495✔
439

440
void ArrayMixed::ensure_int_array() const
441
{
112,893✔
442
    ensure_array_accessor(m_ints, payload_idx_int);
112,893✔
443
}
112,893✔
444

445
void ArrayMixed::ensure_int_pair_array() const
446
{
1,104,396✔
447
    ensure_array_accessor(m_int_pairs, payload_idx_pair);
1,104,396✔
448
}
1,104,396✔
449

450
void ArrayMixed::ensure_string_array() const
451
{
252,366✔
452
    if (!m_strings.is_attached()) {
252,366✔
453
        ref_type ref = get_as_ref(payload_idx_str);
80,376✔
454
        m_strings.set_parent(const_cast<ArrayMixed*>(this), payload_idx_str);
80,376✔
455
        if (ref) {
80,376✔
456
            m_strings.init_from_ref(ref);
61,542✔
457
        }
61,542✔
458
        else {
18,834✔
459
            m_strings.create();
18,834✔
460
            m_strings.update_parent();
18,834✔
461
        }
18,834✔
462
    }
80,376✔
463
}
252,366✔
464

465
void ArrayMixed::ensure_ref_array() const
466
{
136,950✔
467
    while (Array::size() < payload_idx_ref + 1) {
136,950✔
468
        const_cast<ArrayMixed*>(this)->Array::add(0);
×
469
    }
×
470
    ensure_array_accessor(m_refs, payload_idx_ref);
136,950✔
471
}
136,950✔
472

473
void ArrayMixed::replace_index(size_t old_ndx, size_t new_ndx, size_t payload_arr_index)
474
{
13,053✔
475
    if (old_ndx != new_ndx) {
13,053✔
476
        size_t sz = m_composite.size();
13,053✔
477
        for (size_t i = 0; i != sz; i++) {
806,466✔
478
            int64_t val = m_composite.get(i);
806,466✔
479
            if (size_t((val & s_payload_idx_mask) >> s_payload_idx_shift) == payload_arr_index &&
806,466✔
480
                (val >> s_data_shift) == int64_t(old_ndx)) {
806,466✔
481
                m_composite.set(i, int64_t(new_ndx << s_data_shift) | (val & 0xff));
13,053✔
482
                return;
13,053✔
483
            }
13,053✔
484
        }
806,466✔
485
    }
13,053✔
486
}
13,053✔
487

488
void ArrayMixed::erase_linked_payload(size_t ndx, bool free_linked_arrays)
489
{
59,214✔
490
    auto val = m_composite.get(ndx);
59,214✔
491
    auto payload_arr_index = size_t((val & s_payload_idx_mask) >> s_payload_idx_shift);
59,214✔
492

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

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