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

realm / realm-core / jorgen.edelbo_402

21 Aug 2024 11:10AM UTC coverage: 91.054% (-0.03%) from 91.085%
jorgen.edelbo_402

Pull #7803

Evergreen

jedelbo
Small fix to Table::typed_write

When writing the realm to a new file from a write transaction,
the Table may be COW so that the top ref is changed. So don't
use the ref that is present in the group when the operation starts.
Pull Request #7803: Feature/string compression

103494 of 181580 branches covered (57.0%)

1929 of 1999 new or added lines in 46 files covered. (96.5%)

695 existing lines in 51 files now uncovered.

220142 of 241772 relevant lines covered (91.05%)

7344461.76 hits per line

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

94.58
/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,871,654✔
28
    , m_composite(a)
2,871,654✔
29
    , m_ints(a)
2,871,654✔
30
    , m_int_pairs(a)
2,871,654✔
31
    , m_strings(a)
2,871,654✔
32
    , m_refs(a)
2,871,654✔
33
{
5,743,428✔
34
    m_composite.set_parent(this, payload_idx_type);
5,743,428✔
35
}
5,743,428✔
36

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

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

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

63

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

75
    if (value.is_null()) {
422,655✔
76
        set_null(ndx);
1,878✔
77
    }
1,878✔
78
    else {
420,777✔
79
        erase_linked_payload(ndx, destroy_collection);
420,777✔
80
        m_composite.set(ndx, store(value));
420,777✔
81
    }
420,777✔
82

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

94
void ArrayMixed::insert(size_t ndx, Mixed value)
95
{
1,020,972✔
96
    if (value.is_null()) {
1,020,972✔
97
        m_composite.insert(ndx, 0);
173,232✔
98
    }
173,232✔
99
    else {
847,740✔
100
        m_composite.insert(ndx, store(value));
847,740✔
101
    }
847,740✔
102
    if (Array::size() > payload_idx_key) {
1,020,972✔
103
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
1,020,507✔
104
            Array keys(Array::get_alloc());
169,302✔
105
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
169,302✔
106
            keys.init_from_ref(ref);
169,302✔
107
            keys.insert(ndx, 0);
169,302✔
108
        }
169,302✔
109
    }
1,020,507✔
110
}
1,020,972✔
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
std::optional<StringID> ArrayMixed::get_string_id(size_t ndx) const
122
{
1,404✔
123
    int64_t val = m_composite.get(ndx);
1,404✔
124
    if (val) {
1,404✔
125
        const int64_t int_val = val >> s_data_shift;
1,254✔
126
        const size_t payload_ndx{(size_t)int_val};
1,254✔
127
        const DataType type((val & s_data_type_mask) - 1);
1,254✔
128
        if (type == type_String) {
1,254✔
129
            ensure_string_array();
654✔
130
            REALM_ASSERT(size_t(int_val) < m_strings.size());
654✔
131
            return m_strings.get_string_id(payload_ndx);
654✔
132
        }
654✔
133
    }
1,254✔
134
    return {};
750✔
135
}
1,404✔
136

137
Mixed ArrayMixed::get(size_t ndx) const
138
{
4,731,609✔
139
    int64_t val = m_composite.get(ndx);
4,731,609✔
140

141
    if (val) {
4,731,609✔
142
        int64_t int_val = val >> s_data_shift;
4,537,035✔
143
        size_t payload_ndx = size_t(int_val);
4,537,035✔
144
        DataType type = DataType((val & s_data_type_mask) - 1);
4,537,035✔
145
        switch (type) {
4,537,035✔
146
            case type_Int: {
552,711✔
147
                if (val & s_payload_idx_mask) {
552,711✔
148
                    ensure_int_array();
4,470✔
149
                    return Mixed(m_ints.get(payload_ndx));
4,470✔
150
                }
4,470✔
151
                return Mixed(int_val);
548,241✔
152
            }
552,711✔
153
            case type_Bool:
20,079✔
154
                return Mixed(int_val != 0);
20,079✔
155
            case type_Float:
27,396✔
156
                ensure_int_array();
27,396✔
157
                return Mixed(type_punning<float>(m_ints.get(payload_ndx)));
27,396✔
158
            case type_Double:
59,640✔
159
                ensure_int_array();
59,640✔
160
                return Mixed(type_punning<double>(m_ints.get(payload_ndx)));
59,640✔
161
            case type_String: {
563,223✔
162
                ensure_string_array();
563,223✔
163
                REALM_ASSERT(size_t(int_val) < m_strings.size());
563,223✔
164
                return Mixed(m_strings.get(payload_ndx));
563,223✔
165
            }
552,711✔
166
            case type_Binary: {
20,031✔
167
                ensure_string_array();
20,031✔
168
                REALM_ASSERT(size_t(int_val) < m_strings.size());
20,031✔
169
                auto s = m_strings.get(payload_ndx);
20,031✔
170
                return Mixed(BinaryData(s.data(), s.size()));
20,031✔
171
            }
552,711✔
172
            case type_Timestamp: {
18,180✔
173
                ensure_int_pair_array();
18,180✔
174
                payload_ndx <<= 1;
18,180✔
175
                REALM_ASSERT(payload_ndx + 1 < m_int_pairs.size());
18,180✔
176
                return Mixed(Timestamp(m_int_pairs.get(payload_ndx), int32_t(m_int_pairs.get(payload_ndx + 1))));
18,180✔
177
            }
552,711✔
178
            case type_ObjectId: {
26,841✔
179
                ensure_string_array();
26,841✔
180
                REALM_ASSERT(size_t(int_val) < m_strings.size());
26,841✔
181
                auto s = m_strings.get(payload_ndx);
26,841✔
182
                ObjectId id;
26,841✔
183
                memcpy(&id, s.data(), sizeof(ObjectId));
26,841✔
184
                return Mixed(id);
26,841✔
185
            }
552,711✔
186
            case type_Decimal: {
51,600✔
187
                ensure_int_pair_array();
51,600✔
188
                Decimal128::Bid128 raw;
51,600✔
189
                payload_ndx <<= 1;
51,600✔
190
                REALM_ASSERT(payload_ndx + 1 < m_int_pairs.size());
51,600✔
191
                raw.w[0] = m_int_pairs.get(payload_ndx);
51,600✔
192
                raw.w[1] = m_int_pairs.get(payload_ndx + 1);
51,600✔
193
                return Mixed(Decimal128(raw));
51,600✔
194
            }
552,711✔
195
            case type_Link:
✔
196
                ensure_int_array();
×
197
                return Mixed(ObjKey(m_ints.get(payload_ndx)));
×
198
            case type_TypedLink: {
1,554,354✔
199
                ensure_int_pair_array();
1,554,354✔
200
                payload_ndx <<= 1;
1,554,354✔
201
                REALM_ASSERT(payload_ndx + 1 < m_int_pairs.size());
1,554,354✔
202
                ObjLink ret{TableKey(uint32_t(m_int_pairs.get(payload_ndx))),
1,554,354✔
203
                            ObjKey(m_int_pairs.get(payload_ndx + 1))};
1,554,354✔
204
                return Mixed(ret);
1,554,354✔
205
            }
552,711✔
206
            case type_UUID: {
29,043✔
207
                ensure_string_array();
29,043✔
208
                REALM_ASSERT(size_t(int_val) < m_strings.size());
29,043✔
209
                auto s = m_strings.get(payload_ndx);
29,043✔
210
                UUID::UUIDBytes bytes{};
29,043✔
211
                std::copy_n(s.data(), bytes.size(), bytes.begin());
29,043✔
212
                return Mixed(UUID(bytes));
29,043✔
213
            }
552,711✔
214
            default:
1,615,926✔
215
                if (size_t((val & s_payload_idx_mask) >> s_payload_idx_shift) == payload_idx_ref) {
1,615,929✔
216
                    ensure_ref_array();
1,615,929✔
217
                    return Mixed(m_refs.get(payload_ndx), CollectionType(int(type)));
1,615,929✔
218
                }
1,615,929✔
219
                break;
2,147,483,647✔
220
        }
4,537,035✔
221
    }
4,537,035✔
222

223
    return {};
194,574✔
224
}
4,731,609✔
225

226
void ArrayMixed::clear()
227
{
690✔
228
    m_composite.clear();
690✔
229
    m_ints.destroy();
690✔
230
    m_int_pairs.destroy();
690✔
231
    m_strings.destroy();
690✔
232
    m_refs.destroy_deep();
690✔
233
    Array::set(payload_idx_int, 0);
690✔
234
    Array::set(payload_idx_pair, 0);
690✔
235
    Array::set(payload_idx_str, 0);
690✔
236
    if (Array::size() > payload_idx_ref) {
690✔
237
        Array::set(payload_idx_ref, 0);
690✔
238
    }
690✔
239
    if (Array::size() > payload_idx_key) {
690✔
240
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
690✔
241
            Array::destroy(ref, m_composite.get_alloc());
6✔
242
            Array::set(payload_idx_key, 0);
6✔
243
        }
6✔
244
    }
690✔
245
}
690✔
246

247
void ArrayMixed::erase(size_t ndx)
248
{
165,447✔
249
    erase_linked_payload(ndx, true);
165,447✔
250
    m_composite.erase(ndx);
165,447✔
251
    if (Array::size() > payload_idx_key) {
165,447✔
252
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
165,426✔
253
            Array keys(Array::get_alloc());
144,378✔
254
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
144,378✔
255
            keys.init_from_ref(ref);
144,378✔
256
            keys.erase(ndx);
144,378✔
257
        }
144,378✔
258
    }
165,426✔
259
}
165,447✔
260

261
void ArrayMixed::move(ArrayMixed& dst, size_t ndx)
262
{
534✔
263
    auto sz = size();
534✔
264
    size_t i = ndx;
534✔
265
    const size_t original_dst_size = dst.size();
534✔
266
    while (i < sz) {
49,236✔
267
        auto val = get(i++);
48,702✔
268
        dst.add(val);
48,702✔
269
    }
48,702✔
270
    if (Array::size() > payload_idx_key) {
534✔
271
        if (auto ref = Array::get_as_ref(payload_idx_key)) {
534✔
272
            dst.ensure_keys();
528✔
273
            Array keys(Array::get_alloc());
528✔
274
            keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
528✔
275
            keys.init_from_ref(ref);
528✔
276
            for (size_t j = original_dst_size, i = ndx; i < sz; i++, j++) {
49,176✔
277
                dst.set_key(j, keys.get(i));
48,648✔
278
            }
48,648✔
279
            keys.truncate(ndx);
528✔
280
        }
528✔
281
    }
534✔
282
    while (i > ndx) {
49,236✔
283
        erase_linked_payload(--i, false);
48,702✔
284
    }
48,702✔
285
    m_composite.truncate(ndx);
534✔
286
}
534✔
287

288
size_t ArrayMixed::find_first(Mixed value, size_t begin, size_t end) const noexcept
289
{
67,776✔
290
    if (value.is_null()) {
67,776✔
291
        return m_composite.find_first(0, begin, end);
468✔
292
    }
468✔
293
    DataType type = value.get_type();
67,308✔
294
    if (end == realm::npos)
67,308✔
295
        end = size();
6✔
296

297
    for (size_t i = begin; i < end; i++) {
637,623✔
298
        if (Mixed::data_types_are_comparable(this->get_type(i), type) && get(i) == value) {
634,869✔
299
            return i;
64,554✔
300
        }
64,554✔
301
    }
634,869✔
302
    return realm::npos;
2,754✔
303
}
67,308✔
304

305
bool ArrayMixed::ensure_keys()
306
{
101,424✔
307
    if (Array::size() < payload_idx_key + 1 || Array::get(payload_idx_key) == 0) {
101,424✔
308
        Array keys(Array::get_alloc());
75,426✔
309
        keys.set_parent(const_cast<ArrayMixed*>(this), payload_idx_key);
75,426✔
310
        keys.create(type_Normal, false, size(), 0);
75,426✔
311
        keys.update_parent();
75,426✔
312

313
        return false;
75,426✔
314
    }
75,426✔
315
    return true;
25,998✔
316
}
101,424✔
317

318
size_t ArrayMixed::find_key(int64_t key) const noexcept
319
{
596,145✔
320
    if (ref_type ref = get_as_ref(payload_idx_key)) {
596,145✔
321
        Array keys(Array::get_alloc());
596,061✔
322
        keys.init_from_ref(ref);
596,061✔
323
        return keys.find_first(key);
596,061✔
324
    }
596,061✔
325
    return realm::not_found;
84✔
326
}
596,145✔
327

328
void ArrayMixed::set_key(size_t ndx, int64_t key)
329
{
296,922✔
330
    Array keys(Array::get_alloc());
296,922✔
331
    ensure_array_accessor(keys, payload_idx_key);
296,922✔
332
    while (keys.size() <= ndx) {
349,050✔
333
        keys.add(0);
52,128✔
334
    }
52,128✔
335
    keys.set(ndx, key);
296,922✔
336
}
296,922✔
337

338
int64_t ArrayMixed::get_key(size_t ndx) const
339
{
1,559,970✔
340
    Array keys(Array::get_alloc());
1,559,970✔
341
    if (ref_type ref = get_as_ref(payload_idx_key)) {
1,559,970✔
342
        keys.init_from_ref(ref);
1,559,352✔
343
        return (ndx < keys.size()) ? keys.get(ndx) : 0;
1,559,352✔
344
    }
1,559,352✔
345
    return 0;
618✔
346
}
1,559,970✔
347

348
void ArrayMixed::verify() const
349
{
15,246✔
350
    // TODO: Implement
351
}
15,246✔
352

353
ref_type ArrayMixed::typed_write(ref_type top_ref, _impl::ArrayWriterBase& out, Allocator& alloc)
354
{
74,850✔
355
    if (out.only_modified && alloc.is_read_only(top_ref))
74,850✔
356
        return top_ref;
×
357

358
    ArrayRef top(alloc);
74,850✔
359
    top.init_from_ref(top_ref);
74,850✔
360
    size_t sz = top.size();
74,850✔
361
    TempArray written_leaf(sz);
74,850✔
362

363
    /*
364
     Mixed stores things using different arrays. We need to take into account this in order to
365
     understand what we need to compress and what we can instead leave not compressed.
366

367
     The main subarrays are:
368

369
     composite array : index 0
370
     int array : index 1
371
     pair_int array: index 2
372
     string array: index 3
373
     ref array: index 4
374
     key array: index 5
375

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

412
                    for (size_t k = 0; k < ref_sz; k++) {
21,750✔
413
                        ref_type new_sub_ref = 0;
11,406✔
414
                        if (auto sub_ref = arr_ref.get(k)) {
11,406✔
415
                            auto header = alloc.translate(sub_ref);
9,930✔
416
                            // Now we have to find out if the nested collection is a
417
                            // dictionary or a list. If the top array has a size of 2
418
                            // and it is not a BplusTree inner node, then it is a dictionary
419
                            if (NodeHeader::get_size_from_header(header) == 2 &&
9,930✔
420
                                !NodeHeader::get_is_inner_bptree_node_from_header(header)) {
9,930✔
421
                                new_sub_ref = Dictionary::typed_write(sub_ref, out, alloc);
4,764✔
422
                            }
4,764✔
423
                            else {
5,166✔
424
                                new_sub_ref = BPlusTree<Mixed>::typed_write(sub_ref, out, alloc);
5,166✔
425
                            }
5,166✔
426
                        }
9,930✔
427
                        written_ref_leaf.set_as_ref(k, new_sub_ref);
11,406✔
428
                    }
11,406✔
429
                    new_ref = written_ref_leaf.write(out);
10,344✔
430
                    break;
10,344✔
UNCOV
431
                }
×
432
                case payload_idx_key:
6,738✔
433
                    new_ref = Array::write(ref, alloc, out, out.only_modified, out.compress);
6,738✔
434
                    break;
6,738✔
435
            }
59,568✔
436
        }
59,568✔
437
        written_leaf.set(i, new_ref);
374,226✔
438
    }
374,226✔
439
    return written_leaf.write(out);
74,850✔
440
}
74,850✔
441

442
void ArrayMixed::ensure_array_accessor(Array& arr, size_t ndx_in_parent) const
443
{
4,985,862✔
444
    if (!arr.is_attached()) {
4,985,862✔
445
        ref_type ref = get_as_ref(ndx_in_parent);
2,928,252✔
446
        arr.set_parent(const_cast<ArrayMixed*>(this), ndx_in_parent);
2,928,252✔
447
        if (ref) {
2,928,252✔
448
            arr.init_from_ref(ref);
2,588,955✔
449
        }
2,588,955✔
450
        else {
339,297✔
451
            arr.create(ndx_in_parent == payload_idx_ref ? type_HasRefs : type_Normal);
339,297✔
452
            arr.update_parent();
339,297✔
453
        }
339,297✔
454
    }
2,928,252✔
455
}
4,985,862✔
456

457
void ArrayMixed::ensure_int_array() const
458
{
112,485✔
459
    ensure_array_accessor(m_ints, payload_idx_int);
112,485✔
460
}
112,485✔
461

462
void ArrayMixed::ensure_int_pair_array() const
463
{
1,968,327✔
464
    ensure_array_accessor(m_int_pairs, payload_idx_pair);
1,968,327✔
465
}
1,968,327✔
466

467
void ArrayMixed::ensure_string_array() const
468
{
906,693✔
469
    if (!m_strings.is_attached()) {
906,693✔
470
        ref_type ref = get_as_ref(payload_idx_str);
478,704✔
471
        m_strings.set_parent(const_cast<ArrayMixed*>(this), payload_idx_str);
478,704✔
472
        if (ref) {
478,704✔
473
            m_strings.init_from_ref(ref);
327,831✔
474
        }
327,831✔
475
        else {
150,873✔
476
            m_strings.create();
150,873✔
477
            m_strings.update_parent();
150,873✔
478
        }
150,873✔
479
    }
478,704✔
480
}
906,693✔
481

482
void ArrayMixed::ensure_ref_array() const
483
{
2,609,715✔
484
    while (Array::size() < payload_idx_ref + 1) {
2,609,715✔
485
        const_cast<ArrayMixed*>(this)->Array::add(0);
×
486
    }
×
487
    ensure_array_accessor(m_refs, payload_idx_ref);
2,609,715✔
488
}
2,609,715✔
489

490
void ArrayMixed::replace_index(size_t old_ndx, size_t new_ndx, size_t payload_arr_index)
491
{
201,687✔
492
    if (old_ndx != new_ndx) {
201,687✔
493
        size_t sz = m_composite.size();
201,687✔
494
        for (size_t i = 0; i != sz; i++) {
19,890,393✔
495
            int64_t val = m_composite.get(i);
19,890,393✔
496
            if (size_t((val & s_payload_idx_mask) >> s_payload_idx_shift) == payload_arr_index &&
19,890,393✔
497
                (val >> s_data_shift) == int64_t(old_ndx)) {
19,890,393✔
498
                m_composite.set(i, int64_t(new_ndx << s_data_shift) | (val & 0xff));
201,687✔
499
                return;
201,687✔
500
            }
201,687✔
501
        }
19,890,393✔
502
    }
201,687✔
503
}
201,687✔
504

505
void ArrayMixed::erase_linked_payload(size_t ndx, bool free_linked_arrays)
506
{
636,723✔
507
    auto val = m_composite.get(ndx);
636,723✔
508
    auto payload_arr_index = size_t((val & s_payload_idx_mask) >> s_payload_idx_shift);
636,723✔
509

510
    if (payload_arr_index) {
636,723✔
511
        // A value is stored in one of the payload arrays
512
        size_t last_ndx = 0;
468,381✔
513
        size_t erase_ndx = size_t(val >> s_data_shift);
468,381✔
514
        // Clean up current value by moving last over
515
        switch (payload_arr_index) {
468,381✔
516
            case payload_idx_int: {
4,437✔
517
                ensure_int_array();
4,437✔
518
                last_ndx = m_ints.size() - 1;
4,437✔
519
                if (erase_ndx != last_ndx) {
4,437✔
520
                    m_ints.set(erase_ndx, m_ints.get(last_ndx));
3,189✔
521
                    replace_index(last_ndx, erase_ndx, payload_arr_index);
3,189✔
522
                }
3,189✔
523
                m_ints.erase(last_ndx);
4,437✔
524
                break;
4,437✔
525
            }
×
526
            case payload_idx_str: {
6,072✔
527
                ensure_string_array();
6,072✔
528
                last_ndx = m_strings.size() - 1;
6,072✔
529
                if (erase_ndx != last_ndx) {
6,072✔
530
                    StringData tmp = m_strings.get(last_ndx);
3,336✔
531
                    std::string tmp_val(tmp.data(), tmp.size());
3,336✔
532
                    m_strings.set(erase_ndx, StringData(tmp_val));
3,336✔
533
                    replace_index(last_ndx, erase_ndx, payload_arr_index);
3,336✔
534
                }
3,336✔
535
                m_strings.erase(last_ndx);
6,072✔
536
                break;
6,072✔
537
            }
×
538
            case payload_idx_pair: {
12,102✔
539
                ensure_int_pair_array();
12,102✔
540
                last_ndx = m_int_pairs.size() - 2;
12,102✔
541
                erase_ndx <<= 1;
12,102✔
542
                if (erase_ndx != last_ndx) {
12,102✔
543
                    m_int_pairs.set(erase_ndx, m_int_pairs.get(last_ndx));
5,394✔
544
                    m_int_pairs.set(erase_ndx + 1, m_int_pairs.get(last_ndx + 1));
5,394✔
545
                    replace_index(last_ndx >> 1, erase_ndx >> 1, payload_arr_index);
5,394✔
546
                }
5,394✔
547
                m_int_pairs.truncate(last_ndx);
12,102✔
548
                break;
12,102✔
549
            }
×
550
            case payload_idx_ref: {
445,776✔
551
                ensure_ref_array();
445,776✔
552
                last_ndx = m_refs.size() - 1;
445,776✔
553
                auto old_ref = m_refs.get(erase_ndx);
445,776✔
554
                if (erase_ndx != last_ndx) {
445,776✔
555
                    m_refs.set(erase_ndx, m_refs.get(last_ndx));
189,753✔
556
                    replace_index(last_ndx, erase_ndx, payload_arr_index);
189,753✔
557
                }
189,753✔
558
                m_refs.erase(last_ndx);
445,776✔
559
                if (old_ref && free_linked_arrays)
445,776✔
560
                    Array::destroy_deep(old_ref, m_composite.get_alloc());
145,017✔
561
                break;
445,776✔
562
            }
×
563
            default:
✔
564
                break;
×
565
        }
468,381✔
566
    }
468,381✔
567
}
636,723✔
568

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