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

realm / realm-core / github_pull_request_275914

25 Sep 2023 03:10PM UTC coverage: 92.915% (+1.7%) from 91.215%
github_pull_request_275914

Pull #6073

Evergreen

jedelbo
Merge tag 'v13.21.0' into next-major

"Feature/Bugfix release"
Pull Request #6073: Merge next-major

96928 of 177706 branches covered (0.0%)

8324 of 8714 new or added lines in 122 files covered. (95.52%)

181 existing lines in 28 files now uncovered.

247505 of 266379 relevant lines covered (92.91%)

7164945.17 hits per line

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

99.01
/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

22
using namespace realm;
23

24
ArrayMixed::ArrayMixed(Allocator& a)
25
    : Array(a)
26
    , m_composite(a)
27
    , m_ints(a)
28
    , m_int_pairs(a)
29
    , m_strings(a)
30
{
247,146✔
31
    m_composite.set_parent(this, payload_idx_type);
514,548✔
32
}
514,548✔
33

267,402✔
34
void ArrayMixed::create()
35
{
17,532✔
36
    Array::create(type_HasRefs, false, payload_idx_size);
35,772✔
37
    m_composite.create(type_Normal);
35,772✔
38
    m_composite.update_parent();
35,772✔
39
}
35,772✔
40

18,240✔
41
void ArrayMixed::init_from_mem(MemRef mem) noexcept
42
{
140,142✔
43
    Array::init_from_mem(mem);
293,748✔
44
    m_composite.init_from_parent();
293,748✔
45
    m_ints.detach();
293,748✔
46
    m_int_pairs.detach();
293,748✔
47
    m_strings.detach();
293,748✔
48
}
293,748✔
49

153,606✔
50
void ArrayMixed::add(Mixed value)
153,606✔
51
{
72✔
52
    if (value.is_null()) {
72✔
53
        m_composite.add(0);
102✔
54
        return;
102✔
55
    }
45✔
56
    m_composite.add(store(value));
87✔
57
}
87✔
58

57✔
59

57✔
60
void ArrayMixed::set(size_t ndx, Mixed value)
61
{
9,876✔
62
    if (value.is_null()) {
9,876✔
63
        set_null(ndx);
11,388✔
64
        return;
11,388✔
65
    }
801✔
66
    erase_linked_payload(ndx);
9,075✔
67
    m_composite.set(ndx, store(value));
9,075✔
68
}
9,075✔
69

70
void ArrayMixed::insert(size_t ndx, Mixed value)
71
{
73,848✔
72
    if (value.is_null()) {
63,261✔
73
        m_composite.insert(ndx, 0);
19,767✔
74
        return;
10,005✔
75
    }
10,005✔
76
    m_composite.insert(ndx, store(value));
63,843✔
77
}
63,843✔
78

9,762✔
79
void ArrayMixed::set_null(size_t ndx)
9,762✔
80
{
801✔
81
    auto val = m_composite.get(ndx);
11,388✔
82
    if (val) {
6,714✔
83
        erase_linked_payload(ndx);
732✔
84
        m_composite.set(ndx, 0);
732✔
85
    }
732✔
86
}
891✔
87

81✔
88
Mixed ArrayMixed::get(size_t ndx) const
90✔
89
{
754,641✔
90
    int64_t val = m_composite.get(ndx);
759,315✔
91

748,728✔
92
    if (val) {
748,728✔
93
        int64_t int_val = val >> s_data_shift;
796,248✔
94
        size_t payload_ndx = size_t(int_val);
796,248✔
95
        DataType type = DataType((val & s_data_type_mask) - 1);
741,036✔
96
        switch (type) {
741,036✔
97
            case type_Int: {
183,582✔
98
                if (val & s_payload_idx_mask) {
183,582✔
99
                    ensure_int_array();
57,501✔
100
                    return Mixed(m_ints.get(payload_ndx));
67,152✔
101
                }
67,146✔
102
                return Mixed(int_val);
126,459✔
103
            }
126,459✔
104
            case type_Bool:
126,459✔
105
                return Mixed(int_val != 0);
5,730✔
106
            case type_Float:
126,459✔
107
                ensure_int_array();
79,056✔
108
                return Mixed(type_punning<float>(m_ints.get(payload_ndx)));
79,062✔
109
            case type_Double:
126,081✔
110
                ensure_int_array();
17,022✔
111
                return Mixed(type_punning<double>(m_ints.get(payload_ndx)));
17,847✔
112
            case type_String: {
126,906✔
113
                ensure_string_array();
49,896✔
114
                REALM_ASSERT(size_t(int_val) < m_strings.size());
49,731✔
115
                return Mixed(m_strings.get(payload_ndx));
49,731✔
116
            }
126,741✔
117
            case type_Binary: {
126,906✔
118
                ensure_string_array();
9,984✔
119
                REALM_ASSERT(size_t(int_val) < m_strings.size());
9,984✔
120
                auto s = m_strings.get(payload_ndx);
782,376✔
121
                return Mixed(BinaryData(s.data(), s.size()));
782,376✔
122
            }
126,081✔
123
            case type_Timestamp: {
898,473✔
124
                ensure_int_pair_array();
760,551✔
125
                payload_ndx <<= 1;
760,551✔
126
                REALM_ASSERT(payload_ndx + 1 < m_int_pairs.size());
760,551✔
127
                return Mixed(Timestamp(m_int_pairs.get(payload_ndx), int32_t(m_int_pairs.get(payload_ndx + 1))));
760,551✔
128
            }
263,856✔
129
            case type_ObjectId: {
263,856✔
130
                ensure_string_array();
11,649✔
131
                REALM_ASSERT(size_t(int_val) < m_strings.size());
11,649✔
132
                auto s = m_strings.get(payload_ndx);
11,649✔
133
                ObjectId id;
144,648✔
134
                memcpy(&id, s.data(), sizeof(ObjectId));
144,648✔
135
                return Mixed(id);
14,661✔
136
            }
131,481✔
137
            case type_Decimal: {
139,272✔
138
                ensure_int_pair_array();
27,009✔
139
                Decimal128::Bid128 raw;
27,009✔
140
                payload_ndx <<= 1;
30,903✔
141
                REALM_ASSERT(payload_ndx + 1 < m_int_pairs.size());
30,903✔
142
                raw.w[0] = m_int_pairs.get(payload_ndx);
30,903✔
143
                raw.w[1] = m_int_pairs.get(payload_ndx + 1);
65,454✔
144
                return Mixed(Decimal128(raw));
65,454✔
145
            }
177,717✔
146
            case type_Link:
177,717✔
147
                ensure_int_array();
135,387✔
148
                return Mixed(ObjKey(m_ints.get(payload_ndx)));
9,120✔
149
            case type_TypedLink: {
477,954✔
150
                ensure_int_pair_array();
477,954✔
151
                payload_ndx <<= 1;
477,954✔
152
                REALM_ASSERT(payload_ndx + 1 < m_int_pairs.size());
477,954✔
153
                ObjLink ret{TableKey(uint32_t(m_int_pairs.get(payload_ndx))),
604,221✔
154
                            ObjKey(m_int_pairs.get(payload_ndx + 1))};
473,895✔
155
                return Mixed(ret);
473,895✔
156
            }
131,142✔
157
            case type_UUID: {
131,142✔
158
                ensure_string_array();
15,564✔
159
                REALM_ASSERT(size_t(int_val) < m_strings.size());
145,890✔
160
                auto s = m_strings.get(payload_ndx);
20,013✔
161
                UUID::UUIDBytes bytes{};
20,013✔
162
                std::copy_n(s.data(), bytes.size(), bytes.begin());
20,013✔
163
                return Mixed(UUID(bytes));
20,013✔
164
            }
135,591✔
165
            default:
135,591✔
166
                break;
9,510✔
167
        }
152,730✔
168
    }
31,152✔
169

31,152✔
170
    return {};
31,152✔
171
}
31,152✔
172

13,809✔
173
void ArrayMixed::clear()
13,809✔
174
{
13,815✔
175
    m_composite.clear();
13,815✔
176
    m_ints.destroy();
135,393✔
177
    m_int_pairs.destroy();
6✔
178
    m_strings.destroy();
6✔
179
    Array::set(payload_idx_int, 0);
6✔
180
    Array::set(payload_idx_pair, 0);
477,324✔
181
    Array::set(payload_idx_str, 0);
477,324✔
182
}
477,324✔
183

477,318✔
184
void ArrayMixed::erase(size_t ndx)
477,318✔
185
{
487,569✔
186
    erase_linked_payload(ndx);
487,569✔
187
    m_composite.erase(ndx);
145,638✔
188
}
21,141✔
189

10,890✔
190
void ArrayMixed::truncate_and_destroy_children(size_t ndx)
10,890✔
191
{
10,890✔
192
    for (size_t i = size(); i > ndx; i--) {
10,890✔
193
        erase_linked_payload(i - 1);
10,890✔
194
    }
10,890✔
195
    m_composite.truncate(ndx);
135,387✔
196
}
4,683✔
197

4,683✔
198
void ArrayMixed::move(ArrayMixed& dst, size_t ndx)
4,683✔
199
{
4,686✔
200
    auto sz = size();
4,686✔
201
    size_t i = ndx;
3✔
202
    while (i < sz) {
755,508✔
203
        auto val = get(i++);
755,505✔
204
        dst.add(val);
27✔
205
    }
16,941✔
206
    while (i > ndx) {
16,944✔
207
        erase_linked_payload(--i);
27✔
208
    }
27✔
209
    m_composite.truncate(ndx);
9✔
210
}
9✔
211

6✔
212
size_t ArrayMixed::find_first(Mixed value, size_t begin, size_t end) const noexcept
6✔
213
{
2,367✔
214
    if (value.is_null()) {
2,367✔
215
        return m_composite.find_first(0, begin, end);
237✔
216
    }
237✔
217
    DataType type = value.get_type();
2,136✔
218
    if (end == realm::npos)
2,136✔
219
        end = size();
9✔
220
    for (size_t i = begin; i < end; i++) {
13,980✔
221
        if (Mixed::data_types_are_comparable(this->get_type(i), type) && get(i) == value) {
13,866✔
222
            return i;
12,270✔
223
        }
12,270✔
224
    }
24,120✔
225
    return realm::npos;
12,384✔
226
}
12,378✔
227

18✔
228
void ArrayMixed::verify() const
18✔
229
{
6,108✔
230
    // TODO: Implement
6,108✔
231
}
6,108✔
232

10,248✔
233
void ArrayMixed::ensure_array_accessor(Array& arr, size_t ndx_in_parent) const
10,254✔
234
{
557,034✔
235
    if (!arr.is_attached()) {
557,034✔
236
        ref_type ref = get_as_ref(ndx_in_parent);
66,297✔
237
        arr.set_parent(const_cast<ArrayMixed*>(this), ndx_in_parent);
66,297✔
238
        if (ref) {
66,297✔
239
            arr.init_from_ref(ref);
58,755✔
240
        }
58,752✔
241
        else {
7,596✔
242
            arr.create(type_Normal);
7,596✔
243
            arr.update_parent();
7,572✔
244
        }
7,572✔
245
    }
66,294✔
246
}
557,034✔
247

248
void ArrayMixed::ensure_int_array() const
249
{
44,484!
250
    ensure_array_accessor(m_ints, payload_idx_int);
44,484✔
251
}
44,484✔
252

253
void ArrayMixed::ensure_int_pair_array() const
254
{
512,556✔
255
    ensure_array_accessor(m_int_pairs, payload_idx_pair);
512,583✔
256
}
512,580✔
257

27✔
258
void ArrayMixed::ensure_string_array() const
3✔
259
{
102,192✔
260
    if (!m_strings.is_attached()) {
102,189✔
261
        ref_type ref = get_as_ref(payload_idx_str);
31,536✔
262
        m_strings.set_parent(const_cast<ArrayMixed*>(this), payload_idx_str);
56,268✔
263
        if (ref) {
56,268✔
264
            m_strings.init_from_ref(ref);
24,018✔
265
        }
24,018✔
266
        else {
32,250✔
267
            m_strings.create();
32,250✔
268
            m_strings.update_parent();
7,752✔
269
        }
70,923✔
270
    }
94,572✔
271
}
126,552✔
272

24,363✔
273
void ArrayMixed::replace_index(size_t old_ndx, size_t new_ndx, size_t payload_arr_index)
63,036✔
274
{
6,102✔
275
    if (old_ndx != new_ndx) {
30,465✔
276
        size_t sz = m_composite.size();
5,964✔
277
        for (size_t i = 0; i != sz; i++) {
397,146✔
278
            int64_t val = m_composite.get(i);
397,479✔
279
            if (size_t((val & s_payload_idx_mask) >> s_payload_idx_shift) == payload_arr_index &&
397,479✔
280
                (val >> s_data_shift) == int64_t(old_ndx)) {
397,296✔
281
                m_composite.set(i, int64_t(new_ndx << s_data_shift) | (val & 0xff));
6,114✔
282
                return;
6,114✔
283
            }
6,114✔
284
        }
397,146✔
285
    }
6,114✔
286
}
6,114✔
287

183✔
288
void ArrayMixed::erase_linked_payload(size_t ndx)
183✔
289
{
19,995✔
290
    auto val = m_composite.get(ndx);
19,995✔
291
    auto payload_arr_index = size_t((val & s_payload_idx_mask) >> s_payload_idx_shift);
22,290✔
292

22,290✔
293
    if (payload_arr_index) {
22,290✔
294
        // A value is stored in one of the payload arrays
14,148✔
295
        size_t last_ndx = 0;
14,148✔
296
        size_t erase_ndx = size_t(val >> s_data_shift);
11,853✔
297
        // Clean up current value by moving last over
11,853✔
298
        switch (payload_arr_index) {
12,327✔
299
            case payload_idx_int: {
3,150✔
300
                ensure_int_array();
3,150✔
301
                last_ndx = m_ints.size() - 1;
3,264✔
302
                if (erase_ndx != last_ndx) {
2,790✔
303
                    m_ints.set(erase_ndx, m_ints.get(last_ndx));
1,941✔
304
                    replace_index(last_ndx, erase_ndx, payload_arr_index);
2,301✔
305
                }
2,301✔
306
                m_ints.erase(last_ndx);
2,676✔
307
                break;
2,676✔
308
            }
2,637✔
309
            case payload_idx_str: {
6,279✔
310
                ensure_string_array();
6,279✔
311
                last_ndx = m_strings.size() - 1;
6,225✔
312
                if (erase_ndx != last_ndx) {
6,225✔
313
                    StringData tmp = m_strings.get(last_ndx);
4,542✔
314
                    std::string tmp_val(tmp.data(), tmp.size());
2,013✔
315
                    m_strings.set(erase_ndx, StringData(tmp_val));
2,013✔
316
                    replace_index(last_ndx, erase_ndx, payload_arr_index);
1,959✔
317
                }
1,959✔
318
                m_strings.erase(last_ndx);
9,747✔
319
                break;
3,642✔
320
            }
6,105✔
321
            case payload_idx_pair: {
5,535✔
322
                ensure_int_pair_array();
5,535✔
323
                last_ndx = m_int_pairs.size() - 2;
579,594✔
324
                erase_ndx <<= 1;
579,594✔
325
                if (erase_ndx != last_ndx) {
83,187✔
326
                    m_int_pairs.set(erase_ndx, m_int_pairs.get(last_ndx));
79,830✔
327
                    m_int_pairs.set(erase_ndx + 1, m_int_pairs.get(last_ndx + 1));
79,830✔
328
                    replace_index(last_ndx >> 1, erase_ndx >> 1, payload_arr_index);
71,751✔
329
                }
71,751✔
330
                m_int_pairs.truncate(last_ndx);
13,614✔
331
                break;
13,347✔
332
            }
8,079✔
333
            default:
8,079✔
334
                break;
77,652✔
335
        }
585,912✔
336
    }
11,853✔
337
}
19,995✔
338

43,806✔
339
int64_t ArrayMixed::store(const Mixed& value)
43,806✔
340
{
107,016✔
341
    DataType type = value.get_type();
63,210✔
342
    int64_t val;
63,210✔
343
    switch (type) {
584,496✔
344
        case type_Int: {
537,858✔
345
            int64_t int_val = value.get_int();
537,858✔
346
            if (std::numeric_limits<int32_t>::min() <= int_val && int_val <= std::numeric_limits<int32_t>::max()) {
16,572✔
347
                val = (static_cast<uint64_t>(int_val) << s_data_shift);
14,541✔
348
            }
119,280✔
349
            else {
106,770✔
350
                ensure_int_array();
34,359✔
351
                size_t ndx = m_ints.size();
34,359✔
352
                m_ints.add(int_val);
34,359✔
353
                val = int64_t(ndx << s_data_shift) | (payload_idx_int << s_payload_idx_shift);
26,460✔
354
            }
26,460✔
355
            break;
24,471✔
356
        }
7,899✔
357
        case type_Bool:
9,243✔
358
            val = (value.get_bool() << s_data_shift);
9,243✔
359
            break;
33,672✔
360
        case type_Float: {
107,850✔
361
            ensure_int_array();
3,111✔
362
            size_t ndx = m_ints.size();
3,111✔
363
            m_ints.add(type_punning<int64_t>(value.get_float()));
9,309✔
364
            val = int64_t(ndx << s_data_shift) | (payload_idx_int << s_payload_idx_shift);
9,309✔
365
            break;
3,111✔
NEW
366
        }
×
367
        case type_Double: {
9,357✔
368
            ensure_int_array();
9,357✔
369
            size_t ndx = m_ints.size();
3,159✔
370
            m_ints.add(type_punning<int64_t>(value.get_double()));
3,159✔
371
            val = int64_t(ndx << s_data_shift) | (payload_idx_int << s_payload_idx_shift);
9,255✔
372
            break;
9,255✔
373
        }
6,096✔
374
        case type_String: {
397,701✔
375
            ensure_string_array();
397,701✔
376
            size_t ndx = m_strings.size();
397,701✔
377
            m_strings.add(value.get_string());
302,082✔
378
            val = int64_t(ndx << s_data_shift) | (payload_idx_str << s_payload_idx_shift);
18,834✔
379
            break;
18,834✔
380
        }
6,096✔
381
        case type_Binary: {
387,546✔
382
            ensure_string_array();
8,679✔
383
            size_t ndx = m_strings.size();
8,679✔
384
            auto bin = value.get<Binary>();
2,583✔
385
            m_strings.add(StringData(bin.data(), bin.size()));
2,583✔
386
            val = int64_t(ndx << s_data_shift) | (payload_idx_str << s_payload_idx_shift);
23,286✔
387
            break;
23,286✔
388
        }
20,703✔
389
        case type_Timestamp: {
1,686✔
390
            ensure_int_pair_array();
22,389✔
391
            size_t ndx = m_int_pairs.size() / 2;
1,686✔
392
            auto t = value.get_timestamp();
14,091✔
393
            m_int_pairs.add(t.get_seconds());
14,091✔
394
            m_int_pairs.add(t.get_nanoseconds());
1,686✔
395
            val = int64_t(ndx << s_data_shift) | (payload_idx_pair << s_payload_idx_shift);
14,091✔
396
            break;
4,401✔
397
        }
2,715✔
398
        case type_ObjectId: {
4,503✔
399
            ensure_string_array();
4,503✔
400
            size_t ndx = m_strings.size();
3,651✔
401
            auto id = value.get<ObjectId>();
3,651✔
402
            char buffer[sizeof(ObjectId)];
3,651✔
403
            memcpy(buffer, &id, sizeof(ObjectId));
4,503✔
404
            m_strings.add(StringData(buffer, sizeof(ObjectId)));
4,503✔
405
            val = int64_t(ndx << s_data_shift) | (payload_idx_str << s_payload_idx_shift);
1,788✔
406
            break;
5,433✔
407
        }
3,645✔
408
        case type_Decimal: {
6,366✔
409
            ensure_int_pair_array();
6,366✔
410
            size_t ndx = m_int_pairs.size() / 2;
4,683✔
411
            auto t = value.get<Decimal128>();
4,683✔
412
            m_int_pairs.add(t.raw()->w[0]);
4,683✔
413
            m_int_pairs.add(t.raw()->w[1]);
4,683✔
414
            val = int64_t(ndx << s_data_shift) | (payload_idx_pair << s_payload_idx_shift);
4,683✔
415
            break;
6,366✔
416
        }
3,645✔
417
        case type_Link: {
×
418
            ensure_int_array();
5,508✔
419
            size_t ndx = m_ints.size();
5,508✔
420
            m_ints.add(value.get<ObjKey>().value);
5,508✔
421
            val = int64_t(ndx << s_data_shift) | (payload_idx_int << s_payload_idx_shift);
5,508✔
422
            break;
5,508✔
423
        }
2,160✔
424
        case type_TypedLink: {
17,046✔
425
            ensure_int_pair_array();
17,046✔
426
            size_t ndx = m_int_pairs.size() / 2;
17,046✔
427
            auto t = value.get<ObjLink>();
20,394✔
428
            m_int_pairs.add(int64_t(t.get_table_key().value));
20,394✔
429
            m_int_pairs.add(t.get_obj_key().value);
14,886✔
430
            val = int64_t(ndx << s_data_shift) | (payload_idx_pair << s_payload_idx_shift);
15,423✔
431
            break;
15,423✔
432
        }
537✔
433
        case type_UUID: {
3,162✔
434
            ensure_string_array();
3,162✔
435
            size_t ndx = m_strings.size();
2,736✔
436
            auto id = value.get<UUID>();
2,736✔
437
            const auto uuid_bytes = id.to_bytes();
2,736✔
438
            m_strings.add(StringData(reinterpret_cast<const char*>(uuid_bytes.data()), uuid_bytes.size()));
3,162✔
439
            val = int64_t(ndx << s_data_shift) | (payload_idx_str << s_payload_idx_shift);
3,162✔
440
            break;
2,682✔
441
        }
537✔
NEW
442
        default:
×
443
            val = 0;
✔
444
            break;
×
445
    }
75,618✔
446
    return val + int(type) + 1;
75,618✔
447
}
83,916✔
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