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

realm / realm-core / jorgen.edelbo_338

03 Jul 2024 03:00PM UTC coverage: 90.856% (-0.008%) from 90.864%
jorgen.edelbo_338

Pull #7803

Evergreen

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

103028 of 180606 branches covered (57.05%)

1144 of 1267 new or added lines in 33 files covered. (90.29%)

155 existing lines in 24 files now uncovered.

218583 of 240583 relevant lines covered (90.86%)

7959624.7 hits per line

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

94.44
/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)
2,867,976✔
28
    , m_composite(a)
2,867,976✔
29
    , m_ints(a)
2,867,976✔
30
    , m_int_pairs(a)
2,867,976✔
31
    , m_strings(a)
2,867,976✔
32
    , m_refs(a)
2,867,976✔
33
{
5,737,179✔
34
    m_composite.set_parent(this, payload_idx_type);
5,737,179✔
35
}
5,737,179✔
36

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

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

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

63

64
void ArrayMixed::set(size_t ndx, Mixed value)
65
{
421,797✔
66
    auto old_type = get_type(ndx);
421,797✔
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);
421,797✔
74

75
    if (value.is_null()) {
421,797✔
76
        set_null(ndx);
1,878✔
77
    }
1,878✔
78
    else {
419,919✔
79
        erase_linked_payload(ndx, destroy_collection);
419,919✔
80
        m_composite.set(ndx, store(value));
419,919✔
81
    }
419,919✔
82

83
    if (destroy_collection && Array::size() > payload_idx_key) {
421,797✔
84
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
163,125✔
85
            Array keys(Array::get_alloc());
144,906✔
86
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
144,906✔
87
            keys.init_from_ref(ref);
144,906✔
88
            if (ndx < keys.size())
144,906✔
89
                keys.set(ndx, 0);
144,858✔
90
        }
144,906✔
91
    }
163,125✔
92
}
421,797✔
93

94
void ArrayMixed::insert(size_t ndx, Mixed value)
95
{
1,019,511✔
96
    if (value.is_null()) {
1,019,511✔
97
        m_composite.insert(ndx, 0);
172,140✔
98
    }
172,140✔
99
    else {
847,371✔
100
        m_composite.insert(ndx, store(value));
847,371✔
101
    }
847,371✔
102
    if (Array::size() > payload_idx_key) {
1,019,511✔
103
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
1,019,178✔
104
            Array keys(Array::get_alloc());
169,296✔
105
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
169,296✔
106
            keys.init_from_ref(ref);
169,296✔
107
            keys.insert(ndx, 0);
169,296✔
108
        }
169,296✔
109
    }
1,019,178✔
110
}
1,019,511✔
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
{
4,727,343✔
123
    int64_t val = m_composite.get(ndx);
4,727,343✔
124

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

207
    return {};
193,017✔
208
}
4,727,343✔
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
{
165,570✔
233
    erase_linked_payload(ndx, true);
165,570✔
234
    m_composite.erase(ndx);
165,570✔
235
    if (Array::size() > payload_idx_key) {
165,570✔
236
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
165,558✔
237
            Array keys(Array::get_alloc());
144,402✔
238
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
144,402✔
239
            keys.init_from_ref(ref);
144,402✔
240
            keys.erase(ndx);
144,402✔
241
        }
144,402✔
242
    }
165,558✔
243
}
165,570✔
244

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

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

281
    for (size_t i = begin; i < end; i++) {
633,570✔
282
        if (Mixed::data_types_are_comparable(this->get_type(i), type) && get(i) == value) {
630,816✔
283
            return i;
64,254✔
284
        }
64,254✔
285
    }
630,816✔
286
    return realm::npos;
2,754✔
287
}
67,008✔
288

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

297
        return false;
75,426✔
298
    }
75,426✔
299
    return true;
25,998✔
300
}
101,424✔
301

302
size_t ArrayMixed::find_key(int64_t key) const noexcept
303
{
596,070✔
304
    if (ref_type ref = get_as_ref(payload_idx_key)) {
596,070✔
305
        Array keys(Array::get_alloc());
595,839✔
306
        keys.init_from_ref(ref);
595,839✔
307
        return keys.find_first(key);
595,839✔
308
    }
595,839✔
309
    return realm::not_found;
231✔
310
}
596,070✔
311

312
void ArrayMixed::set_key(size_t ndx, int64_t key)
313
{
298,686✔
314
    Array keys(Array::get_alloc());
298,686✔
315
    ensure_array_accessor(keys, payload_idx_key);
298,686✔
316
    while (keys.size() <= ndx) {
352,590✔
317
        keys.add(0);
53,904✔
318
    }
53,904✔
319
    keys.set(ndx, key);
298,686✔
320
}
298,686✔
321

322
int64_t ArrayMixed::get_key(size_t ndx) const
323
{
1,559,646✔
324
    Array keys(Array::get_alloc());
1,559,646✔
325
    if (ref_type ref = get_as_ref(payload_idx_key)) {
1,559,646✔
326
        keys.init_from_ref(ref);
1,559,220✔
327
        return (ndx < keys.size()) ? keys.get(ndx) : 0;
2,148,263,239✔
328
    }
1,559,220✔
329
    return 0;
426✔
330
}
1,559,646✔
331

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

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

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

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

351
     The main subarrays are:
352

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

360
     Description of each array:
361
     1. composite array: the data stored here is either a small int (< 32 bits) or an offset to one of
362
        the other arrays where the actual data is.
363
     2. int and pair int arrays, they are used for storing integers, timestamps, floats, doubles,
364
     decimals, links. In general we can compress them, but we need to be careful, controlling the col_type
365
     should prevent compressing data that we want to leave in the current format.
366
     3. string array is for strings and binary data
367
     4. ref array is actually storing refs to collections. They can only be Lst<Mixed> or Dictionary.
368
     5. key array stores unique identifiers for collections in mixed (integers that can be compressed)
369
     */
370
    Array composite(alloc);
74,391✔
371
    composite.init_from_ref(top.get_as_ref(0));
74,391✔
372
    written_leaf.set_as_ref(0, composite.write(out, true, out.only_modified, false));
74,391✔
373
    for (size_t i = 1; i < sz; ++i) {
446,310✔
374
        auto ref = top.get(i);
371,919✔
375
        ref_type new_ref = ref;
371,919✔
376
        if (ref && !(out.only_modified && alloc.is_read_only(ref))) {
371,919✔
377
            switch (i) {
59,370✔
378
                case payload_idx_int:
8,550✔
379
                    // integer array
380
                    new_ref = Array::write(ref, alloc, out, out.only_modified, out.compress);
8,550✔
381
                    break;
8,550✔
382
                case payload_idx_pair:
18,354✔
383
                    // integer array
384
                    new_ref = Array::write(ref, alloc, out, out.only_modified, out.compress);
18,354✔
385
                    break;
18,354✔
386
                case payload_idx_str:
15,384✔
387
                    new_ref = ArrayString::typed_write(ref, out, alloc);
15,384✔
388
                    break;
15,384✔
389
                case payload_idx_ref: {
10,344✔
390
                    // collection in mixed
391
                    ArrayRef arr_ref(alloc);
10,344✔
392
                    arr_ref.init_from_ref(ref);
10,344✔
393
                    auto ref_sz = arr_ref.size();
10,344✔
394
                    TempArray written_ref_leaf(ref_sz);
10,344✔
395

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

426
void ArrayMixed::ensure_array_accessor(Array& arr, size_t ndx_in_parent) const
427
{
4,992,924✔
428
    if (!arr.is_attached()) {
4,992,924✔
429
        ref_type ref = get_as_ref(ndx_in_parent);
2,929,908✔
430
        arr.set_parent(const_cast<ArrayMixed*>(this), ndx_in_parent);
2,929,908✔
431
        if (ref) {
2,929,908✔
432
            arr.init_from_ref(ref);
2,591,148✔
433
        }
2,591,148✔
434
        else {
338,760✔
435
            arr.create(ndx_in_parent == payload_idx_ref ? type_HasRefs : type_Normal);
338,760✔
436
            arr.update_parent();
338,760✔
437
        }
338,760✔
438
    }
2,929,908✔
439
}
4,992,924✔
440

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

446
void ArrayMixed::ensure_int_pair_array() const
447
{
1,968,474✔
448
    ensure_array_accessor(m_int_pairs, payload_idx_pair);
1,968,474✔
449
}
1,968,474✔
450

451
void ArrayMixed::ensure_string_array() const
452
{
900,270✔
453
    if (!m_strings.is_attached()) {
900,270✔
454
        ref_type ref = get_as_ref(payload_idx_str);
476,295✔
455
        m_strings.set_parent(const_cast<ArrayMixed*>(this), payload_idx_str);
476,295✔
456
        if (ref) {
476,295✔
457
            m_strings.init_from_ref(ref);
325,539✔
458
        }
325,539✔
459
        else {
150,756✔
460
            m_strings.create();
150,756✔
461
            m_strings.update_parent();
150,756✔
462
        }
150,756✔
463
    }
476,295✔
464
}
900,270✔
465

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

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

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

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

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