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

realm / realm-core / 2591

30 Aug 2024 01:09AM UTC coverage: 91.107% (-0.01%) from 91.117%
2591

push

Evergreen

web-flow
Add basic translation of NSExceptions to Status (#8010)

When the Swift API is misused from within a callback from core a NSException
may escape, which we want to propagate. Since this is always a fatal error that
cannot be programmatically handled by the user, we can always translate this to
UnknownError rather than trying to preserve the original error code.

102828 of 181618 branches covered (56.62%)

1 of 1 new or added line in 1 file covered. (100.0%)

45 existing lines in 13 files now uncovered.

217355 of 238570 relevant lines covered (91.11%)

5738574.33 hits per line

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

88.03
/src/realm/array_string.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2016 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_string.hpp>
20
#include <realm/spec.hpp>
21
#include <realm/mixed.hpp>
22

23
using namespace realm;
24

25
ArrayString::ArrayString(Allocator& a)
26
    : m_alloc(a)
9,977,142✔
27
{
20,187,567✔
28
    m_arr = new (&m_storage) ArrayStringShort(a, true);
20,187,567✔
29
}
20,187,567✔
30

31
void ArrayString::create()
32
{
577,266✔
33
    static_cast<ArrayStringShort*>(m_arr)->create();
577,266✔
34
}
577,266✔
35

36
void ArrayString::init_from_mem(MemRef mem) noexcept
37
{
13,053,744✔
38
    char* header = mem.get_addr();
13,053,744✔
39

40
    ArrayParent* parent = m_arr->get_parent();
13,053,744✔
41
    size_t ndx_in_parent = m_arr->get_ndx_in_parent();
13,053,744✔
42

43
    bool long_strings = Array::get_hasrefs_from_header(header);
13,053,744✔
44
    if (!long_strings) {
13,053,744✔
45
        // Small strings
46
        bool is_small = Array::get_wtype_from_header(header) == Array::wtype_Multiply;
10,240,869✔
47
        if (is_small) {
10,240,869✔
48
            auto arr = new (&m_storage) ArrayStringShort(m_alloc, m_nullable);
6,536,751✔
49
            arr->init_from_mem(mem);
6,536,751✔
50
            m_type = Type::small_strings;
6,536,751✔
51
        }
6,536,751✔
52
        else {
3,704,118✔
53
            auto arr = new (&m_storage) Array(m_alloc);
3,704,118✔
54
            arr->init_from_mem(mem);
3,704,118✔
55
            m_string_enum_values = std::make_unique<ArrayString>(m_alloc);
3,704,118✔
56
            ArrayParent* p;
3,704,118✔
57
            REALM_ASSERT(m_spec != nullptr);
3,704,118✔
58
            REALM_ASSERT(m_col_ndx != realm::npos);
3,704,118✔
59
            ref_type r = m_spec->get_enumkeys_ref(m_col_ndx, p);
3,704,118✔
60
            m_string_enum_values->init_from_ref(r);
3,704,118✔
61
            m_string_enum_values->set_parent(p, m_col_ndx);
3,704,118✔
62
            m_type = Type::enum_strings;
3,704,118✔
63
        }
3,704,118✔
64
    }
10,240,869✔
65
    else {
2,812,875✔
66
        bool is_big = Array::get_context_flag_from_header(header);
2,812,875✔
67
        if (!is_big) {
2,812,875✔
68
            auto arr = new (&m_storage) ArraySmallBlobs(m_alloc);
699,417✔
69
            arr->init_from_mem(mem);
699,417✔
70
            m_type = Type::medium_strings;
699,417✔
71
        }
699,417✔
72
        else {
2,113,458✔
73
            auto arr = new (&m_storage) ArrayBigBlobs(m_alloc, m_nullable);
2,113,458✔
74
            arr->init_from_mem(mem);
2,113,458✔
75
            m_type = Type::big_strings;
2,113,458✔
76
        }
2,113,458✔
77
    }
2,812,875✔
78
    m_arr->set_parent(parent, ndx_in_parent);
13,053,744✔
79
}
13,053,744✔
80

81
void ArrayString::init_from_parent()
82
{
6,090,552✔
83
    ref_type ref = m_arr->get_ref_from_parent();
6,090,552✔
84
    init_from_ref(ref);
6,090,552✔
85
}
6,090,552✔
86

87
void ArrayString::destroy() noexcept
88
{
1,044✔
89
    if (m_arr->is_attached()) {
1,044✔
90
        Array::destroy_deep(m_arr->get_ref(), m_alloc);
468✔
91
        detach();
468✔
92
    }
468✔
93
}
1,044✔
94

95
void ArrayString::detach() noexcept
96
{
4,192,752✔
97
    m_arr->detach();
4,192,752✔
98
    // Make sure the object is in a state like right after construction
99
    // Next call must be to create()
100
    m_arr = new (&m_storage) ArrayStringShort(m_alloc, true);
4,192,752✔
101
    m_type = Type::small_strings;
4,192,752✔
102
}
4,192,752✔
103

104
size_t ArrayString::size() const
105
{
16,084,023✔
106
    switch (m_type) {
16,084,023✔
107
        case Type::small_strings:
6,918,537✔
108
            return static_cast<ArrayStringShort*>(m_arr)->size();
6,918,537✔
109
        case Type::medium_strings:
467,625✔
110
            return static_cast<ArraySmallBlobs*>(m_arr)->size();
467,625✔
111
        case Type::big_strings:
8,710,890✔
112
            return static_cast<ArrayBigBlobs*>(m_arr)->size();
8,710,890✔
113
        case Type::enum_strings:
246✔
114
            return static_cast<Array*>(m_arr)->size();
246✔
115
    }
16,084,023✔
116
    return {};
×
117
}
16,084,023✔
118

119
void ArrayString::add(StringData value)
120
{
446,547✔
121
    switch (upgrade_leaf(value.size())) {
446,547✔
122
        case Type::small_strings:
390,432✔
123
            static_cast<ArrayStringShort*>(m_arr)->add(value);
390,432✔
124
            break;
390,432✔
125
        case Type::medium_strings:
28,428✔
126
            static_cast<ArraySmallBlobs*>(m_arr)->add_string(value);
28,428✔
127
            break;
28,428✔
128
        case Type::big_strings:
27,690✔
129
            static_cast<ArrayBigBlobs*>(m_arr)->add_string(value);
27,690✔
130
            break;
27,690✔
131
        case Type::enum_strings: {
✔
132
            auto a = static_cast<Array*>(m_arr);
×
133
            size_t ndx = a->size();
×
134
            a->add(0);
×
135
            set(ndx, value);
×
136
            break;
×
137
        }
×
138
    }
446,547✔
139
}
446,547✔
140

141
void ArrayString::set(size_t ndx, StringData value)
142
{
3,819,024✔
143
    switch (upgrade_leaf(value.size())) {
3,819,024✔
144
        case Type::small_strings:
572,223✔
145
            static_cast<ArrayStringShort*>(m_arr)->set(ndx, value);
572,223✔
146
            break;
572,223✔
147
        case Type::medium_strings:
238,674✔
148
            static_cast<ArraySmallBlobs*>(m_arr)->set_string(ndx, value);
238,674✔
149
            break;
238,674✔
150
        case Type::big_strings:
384,609✔
151
            static_cast<ArrayBigBlobs*>(m_arr)->set_string(ndx, value);
384,609✔
152
            break;
384,609✔
153
        case Type::enum_strings: {
2,625,963✔
154
            size_t sz = m_string_enum_values->size();
2,625,963✔
155
            size_t res = m_string_enum_values->find_first(value, 0, sz);
2,625,963✔
156
            if (res == realm::not_found) {
2,625,963✔
157
                m_string_enum_values->add(value);
9,678✔
158
                res = sz;
9,678✔
159
            }
9,678✔
160
            static_cast<Array*>(m_arr)->set(ndx, res);
2,625,963✔
161
            break;
2,625,963✔
162
        }
×
163
    }
3,819,024✔
164
}
3,819,024✔
165

166
void ArrayString::insert(size_t ndx, StringData value)
167
{
4,442,964✔
168
    switch (upgrade_leaf(value.size())) {
4,442,964✔
169
        case Type::small_strings:
1,969,359✔
170
            static_cast<ArrayStringShort*>(m_arr)->insert(ndx, value);
1,969,359✔
171
            break;
1,969,359✔
172
        case Type::medium_strings:
295,998✔
173
            static_cast<ArraySmallBlobs*>(m_arr)->insert_string(ndx, value);
295,998✔
174
            break;
295,998✔
175
        case Type::big_strings:
866,496✔
176
            static_cast<ArrayBigBlobs*>(m_arr)->insert_string(ndx, value);
866,496✔
177
            break;
866,496✔
178
        case Type::enum_strings: {
1,312,917✔
179
            static_cast<Array*>(m_arr)->insert(ndx, 0);
1,312,917✔
180
            set(ndx, value);
1,312,917✔
181
        }
1,312,917✔
182
    }
4,442,964✔
183
}
4,442,964✔
184

185
StringData ArrayString::get(size_t ndx) const
186
{
20,594,016✔
187
    switch (m_type) {
20,594,016✔
188
        case Type::small_strings:
11,046,102✔
189
            return static_cast<ArrayStringShort*>(m_arr)->get(ndx);
11,046,102✔
190
        case Type::medium_strings:
893,583✔
191
            return static_cast<ArraySmallBlobs*>(m_arr)->get_string(ndx);
893,583✔
192
        case Type::big_strings:
7,515,006✔
193
            return static_cast<ArrayBigBlobs*>(m_arr)->get_string(ndx);
7,515,006✔
194
        case Type::enum_strings: {
1,147,410✔
195
            size_t index = size_t(static_cast<Array*>(m_arr)->get(ndx));
1,147,410✔
196
            return m_string_enum_values->get(index);
1,147,410✔
197
        }
×
198
    }
20,594,016✔
199
    return {};
×
200
}
20,594,016✔
201

202
StringData ArrayString::get_legacy(size_t ndx) const
203
{
×
204
    switch (m_type) {
×
205
        case Type::small_strings:
×
206
            return static_cast<ArrayStringShort*>(m_arr)->get(ndx);
×
207
        case Type::medium_strings:
×
208
            return static_cast<ArraySmallBlobs*>(m_arr)->get_string_legacy(ndx);
×
209
        case Type::big_strings:
×
210
            return static_cast<ArrayBigBlobs*>(m_arr)->get_string(ndx);
×
211
        case Type::enum_strings: {
×
212
            size_t index = size_t(static_cast<Array*>(m_arr)->get(ndx));
×
213
            return m_string_enum_values->get(index);
×
214
        }
×
215
    }
×
216
    return {};
×
217
}
×
218

219
Mixed ArrayString::get_any(size_t ndx) const
220
{
132,987✔
221
    return Mixed(get(ndx));
132,987✔
222
}
132,987✔
223

224
bool ArrayString::is_null(size_t ndx) const
225
{
3,822,336✔
226
    switch (m_type) {
3,822,336✔
227
        case Type::small_strings:
643,623✔
228
            return static_cast<ArrayStringShort*>(m_arr)->is_null(ndx);
643,623✔
229
        case Type::medium_strings:
19,053✔
230
            return static_cast<ArraySmallBlobs*>(m_arr)->is_null(ndx);
19,053✔
231
        case Type::big_strings:
3,159,681✔
232
            return static_cast<ArrayBigBlobs*>(m_arr)->is_null(ndx);
3,159,681✔
233
        case Type::enum_strings: {
✔
234
            size_t index = size_t(static_cast<Array*>(m_arr)->get(ndx));
×
235
            return m_string_enum_values->is_null(index);
×
236
        }
×
237
    }
3,822,336✔
238
    return {};
×
239
}
3,822,336✔
240

241
void ArrayString::erase(size_t ndx)
242
{
480,978✔
243
    switch (m_type) {
480,978✔
244
        case Type::small_strings:
389,136✔
245
            static_cast<ArrayStringShort*>(m_arr)->erase(ndx);
389,136✔
246
            break;
389,136✔
247
        case Type::medium_strings:
57,963✔
248
            static_cast<ArraySmallBlobs*>(m_arr)->erase(ndx);
57,963✔
249
            break;
57,963✔
250
        case Type::big_strings:
25,608✔
251
            static_cast<ArrayBigBlobs*>(m_arr)->erase(ndx);
25,608✔
252
            break;
25,608✔
253
        case Type::enum_strings:
8,304✔
254
            static_cast<Array*>(m_arr)->erase(ndx);
8,304✔
255
            break;
8,304✔
256
    }
480,978✔
257
}
480,978✔
258

259
void ArrayString::move(ArrayString& dst, size_t ndx)
260
{
1,074✔
261
    size_t sz = size();
1,074✔
262
    for (size_t i = ndx; i < sz; i++) {
115,860✔
263
        dst.add(get(i));
114,786✔
264
    }
114,786✔
265

266
    switch (m_type) {
1,074✔
267
        case Type::small_strings:
1,008✔
268
            static_cast<ArrayStringShort*>(m_arr)->truncate(ndx);
1,008✔
269
            break;
1,008✔
270
        case Type::medium_strings:
60✔
271
            static_cast<ArraySmallBlobs*>(m_arr)->truncate(ndx);
60✔
272
            break;
60✔
273
        case Type::big_strings:
6✔
274
            static_cast<ArrayBigBlobs*>(m_arr)->truncate(ndx);
6✔
275
            break;
6✔
276
        case Type::enum_strings:
✔
277
            // this operation will never be called for enumerated columns
278
            REALM_UNREACHABLE();
279
            break;
×
280
    }
1,074✔
281
}
1,074✔
282

283
void ArrayString::clear()
284
{
381✔
285
    switch (m_type) {
381✔
286
        case Type::small_strings:
327✔
287
            static_cast<ArrayStringShort*>(m_arr)->clear();
327✔
288
            break;
327✔
289
        case Type::medium_strings:
6✔
290
            static_cast<ArraySmallBlobs*>(m_arr)->clear();
6✔
291
            break;
6✔
292
        case Type::big_strings:
48✔
293
            static_cast<ArrayBigBlobs*>(m_arr)->clear();
48✔
294
            break;
48✔
295
        case Type::enum_strings:
✔
296
            static_cast<Array*>(m_arr)->clear();
×
297
            break;
×
298
    }
381✔
299
}
381✔
300

301
size_t ArrayString::find_first(StringData value, size_t begin, size_t end) const noexcept
302
{
4,125,834✔
303
    switch (m_type) {
4,125,834✔
304
        case Type::small_strings:
3,148,989✔
305
            return static_cast<ArrayStringShort*>(m_arr)->find_first(value, begin, end);
3,148,989✔
306
        case Type::medium_strings: {
124,374✔
307
            BinaryData as_binary(value.data(), value.size());
124,374✔
308
            return static_cast<ArraySmallBlobs*>(m_arr)->find_first(as_binary, true, begin, end);
124,374✔
309
            break;
×
310
        }
×
311
        case Type::big_strings: {
256,230✔
312
            BinaryData as_binary(value.data(), value.size());
256,230✔
313
            return static_cast<ArrayBigBlobs*>(m_arr)->find_first(as_binary, true, begin, end);
256,230✔
314
            break;
×
315
        }
×
316
        case Type::enum_strings: {
596,271✔
317
            size_t sz = m_string_enum_values->size();
596,271✔
318
            size_t res = m_string_enum_values->find_first(value, 0, sz);
596,271✔
319
            if (res != realm::not_found) {
596,271✔
320
                return static_cast<Array*>(m_arr)->find_first(res, begin, end);
596,271✔
321
            }
596,271✔
UNCOV
322
            break;
×
323
        }
596,271✔
324
    }
4,125,834✔
325
    return not_found;
×
326
}
4,125,834✔
327

328
namespace {
329

330
template <class T>
331
inline StringData get_string(const T* arr, size_t ndx)
332
{
437,337✔
333
    return arr->get_string(ndx);
437,337✔
334
}
437,337✔
335

336
template <>
337
inline StringData get_string(const ArrayStringShort* arr, size_t ndx)
338
{
93,684✔
339
    return arr->get(ndx);
93,684✔
340
}
93,684✔
341

342
template <class T, class U>
343
size_t lower_bound_string(const T* arr, U value)
344
{
234,912✔
345
    size_t i = 0;
234,912✔
346
    size_t sz = arr->size();
234,912✔
347
    while (0 < sz) {
765,933✔
348
        size_t half = sz / 2;
531,021✔
349
        size_t mid = i + half;
531,021✔
350
        auto probe = get_string(arr, mid);
531,021✔
351
        if (probe < value) {
531,021✔
352
            i = mid + 1;
190,848✔
353
            sz -= half + 1;
190,848✔
354
        }
190,848✔
355
        else {
340,173✔
356
            sz = half;
340,173✔
357
        }
340,173✔
358
    }
531,021✔
359
    return i;
234,912✔
360
}
234,912✔
361
} // namespace
362

363
size_t ArrayString::lower_bound(StringData value)
364
{
234,912✔
365
    switch (m_type) {
234,912✔
366
        case Type::small_strings:
58,434✔
367
            return lower_bound_string(static_cast<ArrayStringShort*>(m_arr), value);
58,434✔
368
        case Type::medium_strings:
68,418✔
369
            return lower_bound_string(static_cast<ArraySmallBlobs*>(m_arr), value);
68,418✔
370
        case Type::big_strings:
108,060✔
371
            return lower_bound_string(static_cast<ArrayBigBlobs*>(m_arr), value);
108,060✔
372
        case Type::enum_strings:
✔
373
            break;
×
374
    }
234,912✔
375
    return realm::npos;
×
376
}
234,912✔
377

378
ArrayString::Type ArrayString::upgrade_leaf(size_t value_size)
379
{
8,703,675✔
380
    if (m_type == Type::big_strings)
8,703,675✔
381
        return Type::big_strings;
1,258,113✔
382

383
    if (m_type == Type::enum_strings)
7,445,562✔
384
        return Type::enum_strings;
3,938,877✔
385

386
    if (m_type == Type::medium_strings) {
3,506,685✔
387
        if (value_size <= medium_string_max_size)
533,718✔
388
            return Type::medium_strings;
533,196✔
389

390
        // Upgrade root leaf from medium to big strings
391
        auto string_medium = static_cast<ArraySmallBlobs*>(m_arr);
522✔
392
        ArrayBigBlobs big_blobs(m_alloc, true);
522✔
393
        big_blobs.create(); // Throws
522✔
394

395
        size_t n = string_medium->size();
522✔
396
        for (size_t i = 0; i < n; i++) {
10,044✔
397
            big_blobs.add_string(string_medium->get_string(i)); // Throws
9,522✔
398
        }
9,522✔
399
        auto parent = string_medium->get_parent();
522✔
400
        auto ndx_in_parent = string_medium->get_ndx_in_parent();
522✔
401
        string_medium->destroy();
522✔
402

403
        auto arr = new (&m_storage) ArrayBigBlobs(m_alloc, true);
522✔
404
        arr->init_from_mem(big_blobs.get_mem());
522✔
405
        arr->set_parent(parent, ndx_in_parent);
522✔
406
        arr->update_parent();
522✔
407

408
        m_type = Type::big_strings;
522✔
409
        return Type::big_strings;
522✔
410
    }
533,718✔
411

412
    // m_type == Type::small
413
    if (value_size <= small_string_max_size)
2,972,967✔
414
        return Type::small_strings;
2,931,498✔
415

416
    if (value_size <= medium_string_max_size) {
41,469✔
417
        // Upgrade root leaf from small to medium strings
418
        auto string_short = static_cast<ArrayStringShort*>(m_arr);
29,889✔
419
        ArraySmallBlobs string_long(m_alloc);
29,889✔
420
        string_long.create(); // Throws
29,889✔
421

422
        size_t n = string_short->size();
29,889✔
423
        for (size_t i = 0; i < n; i++) {
52,044✔
424
            string_long.add_string(string_short->get(i)); // Throws
22,155✔
425
        }
22,155✔
426
        auto parent = string_short->get_parent();
29,889✔
427
        auto ndx_in_parent = string_short->get_ndx_in_parent();
29,889✔
428
        string_short->destroy();
29,889✔
429

430
        auto arr = new (&m_storage) ArraySmallBlobs(m_alloc);
29,889✔
431
        arr->init_from_mem(string_long.get_mem());
29,889✔
432
        arr->set_parent(parent, ndx_in_parent);
29,889✔
433
        arr->update_parent();
29,889✔
434

435
        m_type = Type::medium_strings;
29,889✔
436
    }
29,889✔
437
    else {
11,580✔
438
        // Upgrade root leaf from small to big strings
439
        auto string_short = static_cast<ArrayStringShort*>(m_arr);
11,580✔
440
        ArrayBigBlobs big_blobs(m_alloc, true);
11,580✔
441
        big_blobs.create(); // Throws
11,580✔
442

443
        size_t n = string_short->size();
11,580✔
444
        for (size_t i = 0; i < n; i++) {
32,004✔
445
            big_blobs.add_string(string_short->get(i)); // Throws
20,424✔
446
        }
20,424✔
447
        auto parent = string_short->get_parent();
11,580✔
448
        auto ndx_in_parent = string_short->get_ndx_in_parent();
11,580✔
449
        string_short->destroy();
11,580✔
450

451
        auto arr = new (&m_storage) ArrayBigBlobs(m_alloc, true);
11,580✔
452
        arr->init_from_mem(big_blobs.get_mem());
11,580✔
453
        arr->set_parent(parent, ndx_in_parent);
11,580✔
454
        arr->update_parent();
11,580✔
455

456
        m_type = Type::big_strings;
11,580✔
457
    }
11,580✔
458

459
    return m_type;
41,469✔
460
}
2,972,967✔
461

462
void ArrayString::verify() const
463
{
196,872✔
464
#ifdef REALM_DEBUG
196,872✔
465
    switch (m_type) {
196,872✔
466
        case Type::small_strings:
190,575✔
467
            static_cast<ArrayStringShort*>(m_arr)->verify();
190,575✔
468
            break;
190,575✔
469
        case Type::medium_strings:
945✔
470
            static_cast<ArraySmallBlobs*>(m_arr)->verify();
945✔
471
            break;
945✔
472
        case Type::big_strings:
5,106✔
473
            static_cast<ArrayBigBlobs*>(m_arr)->verify();
5,106✔
474
            break;
5,106✔
475
        case Type::enum_strings:
246✔
476
            static_cast<Array*>(m_arr)->verify();
246✔
477
            break;
246✔
478
    }
196,872✔
479
#endif
196,872✔
480
}
196,872✔
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