• 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

88.64
/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/impl/array_writer.hpp>
21
#include <realm/table.hpp>
22
#include <realm/string_interner.hpp>
23
#include <realm/mixed.hpp>
24

25
using namespace realm;
26

27
ArrayString::ArrayString(Allocator& a)
28
    : m_alloc(a)
43,159,008✔
29
{
86,161,596✔
30
    m_arr = new (&m_storage) ArrayStringShort(a, true);
86,161,596✔
31
}
86,161,596✔
32

33
void ArrayString::create()
34
{
551,505✔
35
    static_cast<ArrayStringShort*>(m_arr)->create();
551,505✔
36
}
551,505✔
37

38
void ArrayString::init_from_mem(MemRef mem) noexcept
39
{
79,138,455✔
40
    char* header = mem.get_addr();
79,138,455✔
41

42
    ArrayParent* parent = m_arr->get_parent();
79,138,455✔
43
    size_t ndx_in_parent = m_arr->get_ndx_in_parent();
79,138,455✔
44

45
    bool long_strings = Array::get_hasrefs_from_header(header);
79,138,455✔
46
    if (!long_strings) {
79,138,455✔
47
        // Small strings
48
        bool is_small = Array::get_wtype_from_header(header) == Array::wtype_Multiply;
73,664,769✔
49
        if (is_small) {
73,664,769✔
50
            auto arr = new (&m_storage) ArrayStringShort(m_alloc, m_nullable);
68,115,642✔
51
            arr->init_from_mem(mem);
68,115,642✔
52
            m_type = Type::small_strings;
68,115,642✔
53
        }
68,115,642✔
54
        else {
5,549,127✔
55
            auto arr = new (&m_storage) Array(m_alloc);
5,549,127✔
56
            arr->init_from_mem(mem);
5,549,127✔
57
            // The context flag is used to indicate interned strings vs old enum strings
58
            // (in conjunction with has_refs() == false)
59
            if (arr->get_context_flag_from_header(arr->get_header())) {
5,549,127✔
60
                // init for new interned strings (replacing old enum strings)
61
                m_type = Type::interned_strings;
1,864,014✔
62
                // consider if we want this invariant: REALM_ASSERT_DEBUG(m_string_interner);
63
            }
1,864,014✔
64
            else {
3,685,113✔
65
                // init for old enum strings
66
                m_string_enum_values = std::make_unique<ArrayString>(m_alloc);
3,685,113✔
67
                ArrayParent* p;
3,685,113✔
68
                REALM_ASSERT(m_spec != nullptr);
3,685,113✔
69
                REALM_ASSERT(m_col_ndx != realm::npos);
3,685,113✔
70
                ref_type r = m_spec->get_enumkeys_ref(m_col_ndx, p);
3,685,113✔
71
                m_string_enum_values->init_from_ref(r);
3,685,113✔
72
                m_string_enum_values->set_parent(p, m_col_ndx);
3,685,113✔
73
                m_type = Type::enum_strings;
3,685,113✔
74
            }
3,685,113✔
75
        }
5,549,127✔
76
    }
73,664,769✔
77
    else {
5,473,686✔
78
        bool is_big = Array::get_context_flag_from_header(header);
5,473,686✔
79
        if (!is_big) {
5,473,686✔
80
            auto arr = new (&m_storage) ArraySmallBlobs(m_alloc);
801,468✔
81
            arr->init_from_mem(mem);
801,468✔
82
            m_type = Type::medium_strings;
801,468✔
83
        }
801,468✔
84
        else {
4,672,218✔
85
            auto arr = new (&m_storage) ArrayBigBlobs(m_alloc, m_nullable);
4,672,218✔
86
            arr->init_from_mem(mem);
4,672,218✔
87
            m_type = Type::big_strings;
4,672,218✔
88
        }
4,672,218✔
89
    }
5,473,686✔
90
    m_arr->set_parent(parent, ndx_in_parent);
79,138,455✔
91
}
79,138,455✔
92

93
void ArrayString::init_from_parent()
94
{
7,152,840✔
95
    ref_type ref = m_arr->get_ref_from_parent();
7,152,840✔
96
    init_from_ref(ref);
7,152,840✔
97
}
7,152,840✔
98

99
void ArrayString::destroy() noexcept
100
{
1,044✔
101
    if (m_arr->is_attached()) {
1,044✔
102
        Array::destroy_deep(m_arr->get_ref(), m_alloc);
468✔
103
        detach();
468✔
104
    }
468✔
105
}
1,044✔
106

107
void ArrayString::detach() noexcept
108
{
4,174,659✔
109
    m_arr->detach();
4,174,659✔
110
    // Make sure the object is in a state like right after construction
111
    // Next call must be to create()
112
    m_arr = new (&m_storage) ArrayStringShort(m_alloc, true);
4,174,659✔
113
    m_type = Type::small_strings;
4,174,659✔
114
}
4,174,659✔
115

116
size_t ArrayString::size() const
117
{
16,272,897✔
118
    switch (m_type) {
16,272,897✔
119
        case Type::small_strings:
6,687,288✔
120
            return static_cast<ArrayStringShort*>(m_arr)->size();
6,687,288✔
121
        case Type::medium_strings:
467,580✔
122
            return static_cast<ArraySmallBlobs*>(m_arr)->size();
467,580✔
123
        case Type::big_strings:
8,746,902✔
124
            return static_cast<ArrayBigBlobs*>(m_arr)->size();
8,746,902✔
125
        case Type::enum_strings:
252✔
126
        case Type::interned_strings:
381,765✔
127
            return static_cast<Array*>(m_arr)->size();
381,765✔
128
    }
16,272,897✔
129
    return {};
×
130
}
16,272,897✔
131

132
void ArrayString::add(StringData value)
133
{
448,866✔
134
    switch (upgrade_leaf(value.size())) {
448,866✔
135
        case Type::small_strings:
389,712✔
136
            static_cast<ArrayStringShort*>(m_arr)->add(value);
389,712✔
137
            break;
389,712✔
138
        case Type::medium_strings:
27,711✔
139
            static_cast<ArraySmallBlobs*>(m_arr)->add_string(value);
27,711✔
140
            break;
27,711✔
141
        case Type::big_strings:
27,864✔
142
            static_cast<ArrayBigBlobs*>(m_arr)->add_string(value);
27,864✔
143
            break;
27,864✔
NEW
144
        case Type::enum_strings:
✔
145
        case Type::interned_strings: {
3,576✔
146
            auto a = static_cast<Array*>(m_arr);
3,576✔
147
            size_t ndx = a->size();
3,576✔
148
            a->add(0);
3,576✔
149
            set(ndx, value);
3,576✔
150
            break;
3,576✔
151
        }
×
152
    }
448,866✔
153
}
448,866✔
154

155
void ArrayString::set(size_t ndx, StringData value)
156
{
4,753,161✔
157
    switch (upgrade_leaf(value.size())) {
4,753,161✔
158
        case Type::small_strings:
467,220✔
159
            static_cast<ArrayStringShort*>(m_arr)->set(ndx, value);
467,220✔
160
            break;
467,220✔
161
        case Type::medium_strings:
220,281✔
162
            static_cast<ArraySmallBlobs*>(m_arr)->set_string(ndx, value);
220,281✔
163
            break;
220,281✔
164
        case Type::big_strings:
820,527✔
165
            static_cast<ArrayBigBlobs*>(m_arr)->set_string(ndx, value);
820,527✔
166
            break;
820,527✔
167
        case Type::interned_strings: {
621,300✔
168
            auto id = m_string_interner->intern(value);
621,300✔
169
            static_cast<Array*>(m_arr)->set(ndx, id);
621,300✔
170
            break;
621,300✔
NEW
171
        }
×
172
        case Type::enum_strings: {
2,625,711✔
173
            size_t sz = m_string_enum_values->size();
2,625,711✔
174
            size_t res = m_string_enum_values->find_first(value, 0, sz);
2,625,711✔
175
            if (res == realm::not_found) {
2,625,711✔
176
                m_string_enum_values->add(value);
9,690✔
177
                res = sz;
9,690✔
178
            }
9,690✔
179
            static_cast<Array*>(m_arr)->set(ndx, res);
2,625,711✔
180
            break;
2,625,711✔
181
        }
×
182
    }
4,753,161✔
183
}
4,753,161✔
184

185
void ArrayString::insert(size_t ndx, StringData value)
186
{
4,910,055✔
187
    switch (upgrade_leaf(value.size())) {
4,910,055✔
188
        case Type::small_strings:
1,701,885✔
189
            static_cast<ArrayStringShort*>(m_arr)->insert(ndx, value);
1,701,885✔
190
            break;
1,701,885✔
191
        case Type::medium_strings:
269,802✔
192
            static_cast<ArraySmallBlobs*>(m_arr)->insert_string(ndx, value);
269,802✔
193
            break;
269,802✔
194
        case Type::big_strings:
1,298,817✔
195
            static_cast<ArrayBigBlobs*>(m_arr)->insert_string(ndx, value);
1,298,817✔
196
            break;
1,298,817✔
197
        case Type::enum_strings: {
1,312,806✔
198
            static_cast<Array*>(m_arr)->insert(ndx, 0);
1,312,806✔
199
            set(ndx, value);
1,312,806✔
200
            break;
1,312,806✔
NEW
201
        }
×
202
        case Type::interned_strings: {
328,182✔
203
            static_cast<Array*>(m_arr)->insert(ndx, 0);
328,182✔
204
            set(ndx, value);
328,182✔
205
            break;
328,182✔
UNCOV
206
        }
×
207
    }
4,910,055✔
208
}
4,910,055✔
209

210
StringData ArrayString::get(size_t ndx) const
211
{
87,142,674✔
212
    switch (m_type) {
87,142,674✔
213
        case Type::small_strings:
65,324,853✔
214
            return static_cast<ArrayStringShort*>(m_arr)->get(ndx);
65,324,853✔
215
        case Type::medium_strings:
1,168,209✔
216
            return static_cast<ArraySmallBlobs*>(m_arr)->get_string(ndx);
1,168,209✔
217
        case Type::big_strings:
10,475,241✔
218
            return static_cast<ArrayBigBlobs*>(m_arr)->get_string(ndx);
10,475,241✔
219
        case Type::enum_strings: {
1,139,196✔
220
            size_t index = size_t(static_cast<Array*>(m_arr)->get(ndx));
1,139,196✔
221
            return m_string_enum_values->get(index);
1,139,196✔
222
        }
×
223
        case Type::interned_strings: {
9,114,036✔
224
            size_t id = size_t(static_cast<Array*>(m_arr)->get(ndx));
9,114,036✔
225
            return m_string_interner->get(id);
9,114,036✔
NEW
226
        }
×
227
    }
87,142,674✔
228
    return {};
×
229
}
87,142,674✔
230

231
StringData ArrayString::get_legacy(size_t ndx) const
232
{
×
233
    switch (m_type) {
×
234
        case Type::small_strings:
×
235
            return static_cast<ArrayStringShort*>(m_arr)->get(ndx);
×
236
        case Type::medium_strings:
×
237
            return static_cast<ArraySmallBlobs*>(m_arr)->get_string_legacy(ndx);
×
238
        case Type::big_strings:
×
239
            return static_cast<ArrayBigBlobs*>(m_arr)->get_string(ndx);
×
240
        case Type::enum_strings: {
×
241
            size_t index = size_t(static_cast<Array*>(m_arr)->get(ndx));
×
242
            return m_string_enum_values->get(index);
×
243
        }
×
NEW
244
        case Type::interned_strings: {
×
NEW
245
            size_t id = size_t(static_cast<Array*>(m_arr)->get(ndx));
×
NEW
246
            return m_string_interner->get(id);
×
NEW
247
        }
×
248
    }
×
249
    return {};
×
250
}
×
251

252
Mixed ArrayString::get_any(size_t ndx) const
253
{
132,822✔
254
    return Mixed(get(ndx));
132,822✔
255
}
132,822✔
256

257
bool ArrayString::is_null(size_t ndx) const
258
{
4,053,972✔
259
    switch (m_type) {
4,053,972✔
260
        case Type::small_strings:
451,161✔
261
            return static_cast<ArrayStringShort*>(m_arr)->is_null(ndx);
451,161✔
262
        case Type::medium_strings:
23,118✔
263
            return static_cast<ArraySmallBlobs*>(m_arr)->is_null(ndx);
23,118✔
264
        case Type::big_strings:
3,341,514✔
265
            return static_cast<ArrayBigBlobs*>(m_arr)->is_null(ndx);
3,341,514✔
266
        case Type::enum_strings: {
✔
NEW
267
            size_t id = size_t(static_cast<Array*>(m_arr)->get(ndx));
×
NEW
268
            return m_string_enum_values->is_null(id);
×
NEW
269
        }
×
270
        case Type::interned_strings: {
238,821✔
271
            size_t id = size_t(static_cast<Array*>(m_arr)->get(ndx));
238,821✔
272
            return id == 0;
238,821✔
UNCOV
273
        }
×
274
    }
4,053,972✔
275
    return {};
×
276
}
4,053,972✔
277

278
void ArrayString::erase(size_t ndx)
279
{
409,983✔
280
    switch (m_type) {
409,983✔
281
        case Type::small_strings:
296,517✔
282
            static_cast<ArrayStringShort*>(m_arr)->erase(ndx);
296,517✔
283
            break;
296,517✔
284
        case Type::medium_strings:
54,801✔
285
            static_cast<ArraySmallBlobs*>(m_arr)->erase(ndx);
54,801✔
286
            break;
54,801✔
287
        case Type::big_strings:
22,101✔
288
            static_cast<ArrayBigBlobs*>(m_arr)->erase(ndx);
22,101✔
289
            break;
22,101✔
290
        case Type::interned_strings:
28,281✔
291
        case Type::enum_strings:
36,585✔
292
            static_cast<Array*>(m_arr)->erase(ndx);
36,585✔
293
            break;
36,585✔
294
    }
409,983✔
295
}
409,983✔
296

297
void ArrayString::move(ArrayString& dst, size_t ndx)
298
{
1,074✔
299
    size_t sz = size();
1,074✔
300
    for (size_t i = ndx; i < sz; i++) {
117,864✔
301
        dst.add(get(i));
116,790✔
302
    }
116,790✔
303

304
    switch (m_type) {
1,074✔
305
        case Type::small_strings:
1,008✔
306
            static_cast<ArrayStringShort*>(m_arr)->truncate(ndx);
1,008✔
307
            break;
1,008✔
308
        case Type::medium_strings:
60✔
309
            static_cast<ArraySmallBlobs*>(m_arr)->truncate(ndx);
60✔
310
            break;
60✔
311
        case Type::big_strings:
6✔
312
            static_cast<ArrayBigBlobs*>(m_arr)->truncate(ndx);
6✔
313
            break;
6✔
314
        case Type::enum_strings:
✔
315
            // this operation will never be called for enumerated columns
316
            REALM_UNREACHABLE();
317
            break;
×
NEW
318
        case Type::interned_strings:
✔
NEW
319
            m_arr->truncate(ndx);
×
NEW
320
            break;
×
321
    }
1,074✔
322
}
1,074✔
323

324
void ArrayString::clear()
325
{
354✔
326
    switch (m_type) {
354✔
327
        case Type::small_strings:
174✔
328
            static_cast<ArrayStringShort*>(m_arr)->clear();
174✔
329
            break;
174✔
330
        case Type::medium_strings:
6✔
331
            static_cast<ArraySmallBlobs*>(m_arr)->clear();
6✔
332
            break;
6✔
333
        case Type::big_strings:
48✔
334
            static_cast<ArrayBigBlobs*>(m_arr)->clear();
48✔
335
            break;
48✔
336
        case Type::enum_strings:
✔
337
        case Type::interned_strings:
126✔
338
            static_cast<Array*>(m_arr)->clear();
126✔
339
            break;
126✔
340
    }
354✔
341
}
354✔
342

343
size_t ArrayString::find_first(StringData value, size_t begin, size_t end) const noexcept
344
{
4,089,513✔
345
    switch (m_type) {
4,089,513✔
346
        case Type::small_strings:
3,085,149✔
347
            return static_cast<ArrayStringShort*>(m_arr)->find_first(value, begin, end);
3,085,149✔
348
        case Type::medium_strings: {
94,902✔
349
            BinaryData as_binary(value.data(), value.size());
94,902✔
350
            return static_cast<ArraySmallBlobs*>(m_arr)->find_first(as_binary, true, begin, end);
94,902✔
351
            break;
×
352
        }
×
353
        case Type::big_strings: {
255,483✔
354
            BinaryData as_binary(value.data(), value.size());
255,483✔
355
            return static_cast<ArrayBigBlobs*>(m_arr)->find_first(as_binary, true, begin, end);
255,483✔
356
            break;
×
357
        }
×
358
        case Type::enum_strings: {
596,865✔
359
            size_t sz = m_string_enum_values->size();
596,865✔
360
            size_t res = m_string_enum_values->find_first(value, 0, sz);
596,865✔
361
            if (res != realm::not_found) {
596,865✔
362
                return static_cast<Array*>(m_arr)->find_first(res, begin, end);
596,865✔
363
            }
596,865✔
364
            break;
×
365
        }
596,865✔
366
        case Type::interned_strings: {
57,234✔
367
            // we need a way to avoid this lookup for each leaf array. The lookup must appear
368
            // higher up the call stack and passed down.
369
            auto id = m_string_interner->lookup(value);
57,234✔
370
            if (id) {
57,234✔
371
                return static_cast<Array*>(m_arr)->find_first(*id, begin, end);
54,018✔
372
            }
54,018✔
373
            break;
3,216✔
374
        }
57,234✔
375
    }
4,089,513✔
376
    return not_found;
3,216✔
377
}
4,089,513✔
378

379
namespace {
380

381
template <class T>
382
inline StringData get_string(const T* arr, size_t ndx)
383
{
437,337✔
384
    return arr->get_string(ndx);
437,337✔
385
}
437,337✔
386

387
template <>
388
inline StringData get_string(const ArrayStringShort* arr, size_t ndx)
389
{
93,693✔
390
    return arr->get(ndx);
93,693✔
391
}
93,693✔
392

393
template <class T, class U>
394
size_t lower_bound_string(const T* arr, U value)
395
{
234,912✔
396
    size_t i = 0;
234,912✔
397
    size_t sz = arr->size();
234,912✔
398
    while (0 < sz) {
765,942✔
399
        size_t half = sz / 2;
531,030✔
400
        size_t mid = i + half;
531,030✔
401
        auto probe = get_string(arr, mid);
531,030✔
402
        if (probe < value) {
531,030✔
403
            i = mid + 1;
191,121✔
404
            sz -= half + 1;
191,121✔
405
        }
191,121✔
406
        else {
339,909✔
407
            sz = half;
339,909✔
408
        }
339,909✔
409
    }
531,030✔
410
    return i;
234,912✔
411
}
234,912✔
412
} // namespace
413

414
size_t ArrayString::lower_bound(StringData value)
415
{
234,912✔
416
    switch (m_type) {
234,912✔
417
        case Type::small_strings:
58,434✔
418
            return lower_bound_string(static_cast<ArrayStringShort*>(m_arr), value);
58,434✔
419
        case Type::medium_strings:
68,418✔
420
            return lower_bound_string(static_cast<ArraySmallBlobs*>(m_arr), value);
68,418✔
421
        case Type::big_strings:
108,060✔
422
            return lower_bound_string(static_cast<ArrayBigBlobs*>(m_arr), value);
108,060✔
423
        case Type::enum_strings:
✔
424
            break;
×
NEW
425
        case Type::interned_strings:
✔
426
            REALM_UNREACHABLE();
NEW
427
            break;
×
428
    }
234,912✔
429
    return realm::npos;
×
430
}
234,912✔
431

432
ArrayString::Type ArrayString::upgrade_leaf(size_t value_size)
433
{
10,106,250✔
434
    if (m_type == Type::big_strings)
10,106,250✔
435
        return Type::big_strings;
2,141,277✔
436

437
    if (m_type == Type::enum_strings)
7,964,973✔
438
        return Type::enum_strings;
3,938,496✔
439

440
    if (m_type == Type::interned_strings)
4,026,477✔
441
        return Type::interned_strings;
953,049✔
442

443
    if (m_type == Type::medium_strings) {
3,073,428✔
444
        if (value_size <= medium_string_max_size)
501,678✔
445
            return Type::medium_strings;
501,168✔
446

447
        // Upgrade root leaf from medium to big strings
448
        auto string_medium = static_cast<ArraySmallBlobs*>(m_arr);
510✔
449
        ArrayBigBlobs big_blobs(m_alloc, true);
510✔
450
        big_blobs.create(); // Throws
510✔
451

452
        size_t n = string_medium->size();
510✔
453
        for (size_t i = 0; i < n; i++) {
10,197✔
454
            big_blobs.add_string(string_medium->get_string(i)); // Throws
9,687✔
455
        }
9,687✔
456
        auto parent = string_medium->get_parent();
510✔
457
        auto ndx_in_parent = string_medium->get_ndx_in_parent();
510✔
458
        string_medium->destroy();
510✔
459

460
        auto arr = new (&m_storage) ArrayBigBlobs(m_alloc, true);
510✔
461
        arr->init_from_mem(big_blobs.get_mem());
510✔
462
        arr->set_parent(parent, ndx_in_parent);
510✔
463
        arr->update_parent();
510✔
464

465
        m_type = Type::big_strings;
510✔
466
        return Type::big_strings;
510✔
467
    }
501,678✔
468

469
    // m_type == Type::small
470
    if (value_size <= small_string_max_size)
2,571,750✔
471
        return Type::small_strings;
2,558,271✔
472

473
    if (value_size <= medium_string_max_size) {
16,626✔
474
        // Upgrade root leaf from small to medium strings
475
        auto string_short = static_cast<ArrayStringShort*>(m_arr);
16,626✔
476
        ArraySmallBlobs string_long(m_alloc);
16,626✔
477
        string_long.create(); // Throws
16,626✔
478

479
        size_t n = string_short->size();
16,626✔
480
        for (size_t i = 0; i < n; i++) {
38,829✔
481
            string_long.add_string(string_short->get(i)); // Throws
22,203✔
482
        }
22,203✔
483
        auto parent = string_short->get_parent();
16,626✔
484
        auto ndx_in_parent = string_short->get_ndx_in_parent();
16,626✔
485
        string_short->destroy();
16,626✔
486

487
        auto arr = new (&m_storage) ArraySmallBlobs(m_alloc);
16,626✔
488
        arr->init_from_mem(string_long.get_mem());
16,626✔
489
        arr->set_parent(parent, ndx_in_parent);
16,626✔
490
        arr->update_parent();
16,626✔
491

492
        m_type = Type::medium_strings;
16,626✔
493
    }
16,626✔
494
    else {
4,294,967,294✔
495
        // Upgrade root leaf from small to big strings
496
        auto string_short = static_cast<ArrayStringShort*>(m_arr);
4,294,967,294✔
497
        ArrayBigBlobs big_blobs(m_alloc, true);
4,294,967,294✔
498
        big_blobs.create(); // Throws
4,294,967,294✔
499

500
        size_t n = string_short->size();
4,294,967,294✔
501
        for (size_t i = 0; i < n; i++) {
4,294,967,294✔
502
            big_blobs.add_string(string_short->get(i)); // Throws
5,292✔
503
        }
5,292✔
504
        auto parent = string_short->get_parent();
4,294,967,294✔
505
        auto ndx_in_parent = string_short->get_ndx_in_parent();
4,294,967,294✔
506
        string_short->destroy();
4,294,967,294✔
507

508
        auto arr = new (&m_storage) ArrayBigBlobs(m_alloc, true);
4,294,967,294✔
509
        arr->init_from_mem(big_blobs.get_mem());
4,294,967,294✔
510
        arr->set_parent(parent, ndx_in_parent);
4,294,967,294✔
511
        arr->update_parent();
4,294,967,294✔
512

513
        m_type = Type::big_strings;
4,294,967,294✔
514
    }
4,294,967,294✔
515

516
    return m_type;
13,479✔
517
}
2,571,750✔
518

519
void ArrayString::verify() const
520
{
192,234✔
521
#ifdef REALM_DEBUG
192,234✔
522
    switch (m_type) {
192,234✔
523
        case Type::small_strings:
25,722✔
524
            static_cast<ArrayStringShort*>(m_arr)->verify();
25,722✔
525
            break;
25,722✔
526
        case Type::medium_strings:
708✔
527
            static_cast<ArraySmallBlobs*>(m_arr)->verify();
708✔
528
            break;
708✔
529
        case Type::big_strings:
5,466✔
530
            static_cast<ArrayBigBlobs*>(m_arr)->verify();
5,466✔
531
            break;
5,466✔
532
        case Type::enum_strings:
252✔
533
        case Type::interned_strings:
160,341✔
534
            static_cast<Array*>(m_arr)->verify();
160,341✔
535
            break;
160,341✔
536
    }
192,234✔
537
#endif
192,234✔
538
}
192,234✔
539

540
template <>
541
ref_type ArrayString::typed_write(ref_type ref, _impl::ArrayWriterBase& out, Allocator& alloc)
542
{
308,814✔
543
    Array leaf(alloc);
308,814✔
544
    leaf.init_from_ref(ref);
308,814✔
545
    ref_type ret_val;
308,814✔
546
    auto header = leaf.get_header();
308,814✔
547
    if (NodeHeader::get_hasrefs_from_header(header) ||
308,814✔
548
        NodeHeader::get_wtype_from_header(header) == NodeHeader::wtype_Multiply) {
308,814✔
549
        // We're interning these strings
550
        ArrayString as(alloc);
174,015✔
551
        as.init_from_ref(ref);
174,015✔
552
        StringInterner* interner = out.table->get_string_interner(out.col_key);
174,015✔
553
        auto sz = as.size();
174,015✔
554
        Array interned(Allocator::get_default());
174,015✔
555
        interned.create(NodeHeader::type_Normal, true, sz);
174,015✔
556
        for (size_t i = 0; i < sz; ++i) {
1,651,047✔
557
            interned.set(i, interner->intern(as.get(i)));
1,477,032✔
558
        }
1,477,032✔
559
        ret_val = interned.write(out, false, false, out.compress);
174,015✔
560
        interned.destroy();
174,015✔
561
        // in a transactional setting:
562
        // Destroy all sub-arrays if present, in order to release memory in file
563
        // This is contrary to the rest of the handling in this function, but needed
564
        // here since sub-arrays may not have been COW'ed and therefore not freed in file.
565
        // We rely on 'only_modified' to indicate that we're in a transactional setting.
566
        if (out.only_modified)
174,015✔
567
            leaf.destroy_deep(true);
173,937✔
568
    }
174,015✔
569
    else {
134,799✔
570
        // whether it's the old enum strings or the new interned strings,
571
        // just write out the array using integer leaf compression
572
        ret_val = leaf.write(out, false, out.only_modified, out.compress);
134,799✔
573
    }
134,799✔
574
    return ret_val;
308,814✔
575
}
308,814✔
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