• 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

96.86
/src/realm/mixed.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/mixed.hpp>
20
#include <realm/decimal128.hpp>
21
#include <realm/unicode.hpp>
22
#include <realm/column_type_traits.hpp>
23
#include <realm/obj.hpp>
24
#include <realm/table.hpp>
25
#include <realm/query_value.hpp>
26
#include <realm/util/serializer.hpp>
27

28
namespace realm {
29
namespace {
30
static const int sorting_rank[19] = {
31
    // Observe! Changing these values breaks the file format for Set<Mixed>
32

33
    -1, // null
34
    1,  // type_Int = 0,
35
    0,  // type_Bool = 1,
36
    2,  // type_String = 2,
37
    -1,
38
    2,  // type_Binary = 4,
39
    -1, // type_OldTable = 5,
40
    -1, // type_Mixed = 6,
41
    -1, // type_OldDateTime = 7,
42
    3,  // type_Timestamp = 8,
43
    1,  // type_Float = 9,
44
    1,  // type_Double = 10,
45
    1,  // type_Decimal = 11,
46
    7,  // type_Link = 12,
47
    -1, // type_LinkList = 13,
48
    -1,
49
    4, // type_ObjectId = 15,
50
    6, // type_TypedLink = 16
51
    5, // type_UUID = 17
52

53
    // Observe! Changing these values breaks the file format for Set<Mixed>
54
};
55

56
int compare_string(StringData a, StringData b)
57
{
5,650,611✔
58
    if (a == b)
5,650,611✔
59
        return 0;
4,958,844✔
60
    return utf8_compare(a, b) ? -1 : 1;
691,767✔
61
}
6,355,515✔
62

5,663,748✔
63
int compare_binary(BinaryData a, BinaryData b)
4,980,945✔
64
{
871,356✔
65
    size_t asz = a.size();
871,356✔
66
    size_t bsz = b.size();
188,553✔
67
    size_t min_sz = std::min(asz, bsz);
188,553✔
68
    int ret = memcmp(a.data(), b.data(), min_sz);
198,123✔
69
    if (ret == 0) {
198,123✔
70
        if (asz > bsz)
15,264✔
71
            ret = 1;
10,083✔
72
        else if (asz < bsz)
14,751✔
73
            ret = -1;
9,993✔
74
    }
11,307✔
75
    return ret;
188,766✔
76
}
193,953✔
77

231✔
78
template <int>
5,613✔
79
struct IntTypeForSize;
9,570✔
80
template <>
9,570✔
81
struct IntTypeForSize<1> {
82
    using type = uint8_t;
83
};
84
template <>
85
struct IntTypeForSize<2> {
86
    using type = uint16_t;
87
};
88
template <>
89
struct IntTypeForSize<4> {
90
    using type = uint32_t;
91
};
92
template <>
93
struct IntTypeForSize<8> {
94
    using type = uint64_t;
95
};
96

97
template <typename Float>
98
int compare_float(Float a_raw, Float b_raw)
99
{
964,491✔
100
    bool a_nan = std::isnan(a_raw);
964,491✔
101
    bool b_nan = std::isnan(b_raw);
964,491✔
102
    if (!a_nan && !b_nan) {
964,491✔
103
        // Just compare as IEEE floats
1,779,948✔
104
        return a_raw == b_raw ? 0 : a_raw < b_raw ? -1 : 1;
1,779,948✔
105
    }
1,779,948✔
106
    if (a_nan && b_nan) {
1,043,835✔
107
        // Compare the nan values as unsigned
19,098✔
108
        using IntType = typename IntTypeForSize<sizeof(Float)>::type;
605,691✔
109
        IntType a = 0, b = 0;
835,692✔
110
        memcpy(&a, &a_raw, sizeof(Float));
132,150✔
111
        memcpy(&b, &b_raw, sizeof(Float));
19,098✔
112
        return a == b ? 0 : a < b ? -1 : 1;
38,280✔
113
    }
38,280✔
114
    // One is nan, the other is not
114,273✔
115
    // nans are treated as being less than all non-nan values
114,273✔
116
    return a_nan ? -1 : 1;
105,105✔
117
}
114,273✔
118

119
template <typename T>
120
int compare_generic(T lhs, T rhs)
93,870✔
121
{
18,351,651✔
122
    return lhs == rhs ? 0 : lhs < rhs ? -1 : 1;
18,257,781✔
123
}
18,257,781✔
124

125
// This is the tricky one. Needs to support the following cases:
18,399,852✔
126
// * Doubles with a fractional component.
17,162,844✔
127
// * Longs that can't be precisely represented as a double.
18,399,852✔
128
// * Doubles outside of the range of Longs (including +/- Inf).
129
// * NaN (defined by us as less than all Longs)
130
// * Return value is always -1, 0, or 1 to ensure it is safe to negate.
131
int compare_long_to_double(int64_t lhs, double rhs)
132
{
167,799✔
133
    // All Longs are > NaN
167,799✔
134
    if (std::isnan(rhs))
167,799✔
135
        return 1;
3✔
136

330,909✔
137
    // Ints with magnitude <= 2**53 can be precisely represented as doubles.
167,796✔
138
    // Additionally, doubles outside of this range can't have a fractional component.
330,909✔
139
    static const int64_t kEndOfPreciseDoubles = 1ll << 53;
167,799✔
140
    if (lhs <= kEndOfPreciseDoubles && lhs >= -kEndOfPreciseDoubles) {
167,796✔
141
        return compare_float(double(lhs), rhs);
167,781✔
142
    }
167,781✔
143

163,125✔
144
    // Large magnitude doubles (including +/- Inf) are strictly > or < all Longs.
163,125✔
145
    static const double kBoundOfLongRange = -static_cast<double>(LLONG_MIN); // positive 2**63
163,107✔
146
    if (rhs >= kBoundOfLongRange)
163,107✔
147
        return -1; // Can't be represented in a Long.
3✔
148
    if (rhs < -kBoundOfLongRange)
12✔
149
        return 1; // Can be represented in a Long.
21✔
150

27✔
151
    // Remaining Doubles can have their integer component precisely represented as long longs.
12✔
152
    // If they have a fractional component, they must be strictly > or < lhs even after
24✔
153
    // truncation of the fractional component since low-magnitude lhs were handled above.
12✔
154
    return compare_generic(lhs, int64_t(rhs));
9✔
155
}
9✔
156
} // anonymous namespace
157

158
Mixed::Mixed(const Obj& obj) noexcept
12✔
159
    : Mixed(ObjLink(obj.get_table()->get_key(), obj.get_key()))
12✔
160
{
45✔
161
}
45✔
162

163
bool Mixed::types_are_comparable(const Mixed& lhs, const Mixed& rhs)
164
{
1,593,381✔
165
    if (lhs.m_type == rhs.m_type)
1,593,381✔
166
        return lhs.m_type != 0;
1,050,582✔
167

542,751✔
168
    if (lhs.is_null() || rhs.is_null())
1,949,139✔
169
        return false;
1,579,104✔
170

1,425,003✔
171
    DataType l_type = lhs.get_type();
370,035✔
172
    DataType r_type = rhs.get_type();
721,455✔
173
    return data_types_are_comparable(l_type, r_type);
540,708✔
174
}
370,035✔
175

180,747✔
176
bool Mixed::data_types_are_comparable(DataType l_type, DataType r_type)
180,747✔
177
{
913,647✔
178
    if (l_type == r_type)
913,647✔
179
        return true;
350,277✔
180

382,623✔
181
    if (is_numeric(l_type, r_type)) {
976,578✔
182
        return true;
763,527✔
183
    }
569,214✔
184
    if ((l_type == type_String && r_type == type_Binary) || (r_type == type_String && l_type == type_Binary)) {
213,051✔
185
        return true;
375,867✔
186
    }
346,662✔
187
    if (l_type == type_Mixed || r_type == type_Mixed) {
196,605✔
188
        return true; // Mixed is comparable with any type
29,529✔
189
    }
717✔
190
    return false;
31,566✔
191
}
59,985✔
192

28,812✔
193
bool Mixed::accumulate_numeric_to(Decimal128& destination) const noexcept
194
{
13,902✔
195
    bool did_accumulate = false;
27,840✔
196
    if (!is_null()) {
27,840✔
197
        switch (get_type()) {
27,588✔
198
            case type_Int:
22,560✔
199
                destination += Decimal128(get_int());
17,820✔
200
                did_accumulate = true;
17,820✔
201
                break;
17,820✔
202
            case type_Double:
9,492✔
203
                destination += Decimal128(get_double());
1,164✔
204
                did_accumulate = true;
1,164✔
205
                break;
1,164✔
206
            case type_Float:
1,464✔
207
                destination += Decimal128(get_float());
1,764✔
208
                did_accumulate = true;
1,764✔
209
                break;
1,764✔
210
            case type_Decimal: {
1,758✔
211
                auto val = get_decimal();
1,752✔
212
                if (!val.is_nan()) {
1,752✔
213
                    destination += val;
1,434✔
214
                    did_accumulate = true;
1,116✔
215
                }
1,116✔
216
                break;
1,434✔
217
            }
876✔
218
            default:
2,400✔
219
                break;
4,800✔
220
        }
16,302✔
221
    }
27,840✔
222
    return did_accumulate;
27,840✔
223
}
27,840✔
224

13,938✔
225
int Mixed::compare(const Mixed& b) const noexcept
226
{
25,798,989✔
227
    // Observe! Changing this function breaks the file format for Set<Mixed>
51,673,155✔
228

25,798,989✔
229
    if (is_null()) {
25,798,989✔
230
        return b.is_null() ? 0 : -1;
26,320,278✔
231
    }
740,160✔
232
    if (b.is_null())
25,796,604✔
233
        return 1;
25,620,630✔
234

25,348,941✔
235
    // None is null
25,162,686✔
236
    auto type = get_type();
25,162,686✔
237
    switch (type) {
50,406,870✔
238
        case type_Bool: {
25,859,970✔
239
            if (b.get_type() == type_Bool) {
1,233,291✔
240
                return compare_generic(bool_val, b.bool_val);
1,232,976✔
241
            }
1,232,649✔
242
            break;
617,493✔
243
        }
642✔
244
        case type_Int:
17,238,993✔
245
            switch (b.get_type()) {
34,560,489✔
246
                case type_Int:
34,446,879✔
247
                    return compare_generic(int_val, b.int_val);
34,332,531✔
248
                case type_Float:
17,242,503✔
249
                    return compare_long_to_double(int_val, b.float_val);
64,533✔
250
                case type_Double:
107,727✔
251
                    return compare_long_to_double(int_val, b.double_val);
156,534✔
252
                case type_Decimal:
80,634✔
253
                    return Decimal128(int_val).compare(b.decimal_val);
5,022✔
254
                default:
5,079✔
255
                    break;
6,645✔
256
            }
6,645✔
257
            break;
6,645✔
258
        case type_String:
5,648,577✔
259
            if (b.get_type() == type_String)
11,311,887✔
260
                return compare_string(get<StringData>(), b.get<StringData>());
11,312,271✔
261
            [[fallthrough]];
2,153,145,862✔
262
        case type_Binary:
2,147,489,008✔
263
            if (b.get_type() == type_String || b.get_type() == type_Binary)
201,657✔
264
                return compare_binary(get<BinaryData>(), b.get<BinaryData>());
200,724✔
265
            break;
10,503✔
266
        case type_Float:
374,331✔
267
            switch (b.get_type()) {
743,178✔
268
                case type_Int:
376,308✔
269
                    return -compare_long_to_double(b.int_val, float_val);
9,918✔
270
                case type_Float:
364,479✔
271
                    return compare_float(float_val, b.float_val);
719,463✔
272
                case type_Double:
362,745✔
273
                    return compare_float(double(float_val), b.double_val);
5,376✔
274
                case type_Decimal:
4,866✔
275
                    return Decimal128(float_val).compare(b.decimal_val);
4,053✔
276
                default:
4,413✔
277
                    break;
4,368✔
278
            }
4,368✔
279
            break;
4,368✔
280
        case type_Double:
491,421✔
281
            switch (b.get_type()) {
949,458✔
282
                case type_Int:
509,547✔
283
                    return -compare_long_to_double(b.int_val, double_val);
99,933✔
284
                case type_Float:
53,454✔
285
                    return compare_float(double_val, double(b.float_val));
6,243✔
286
                case type_Double:
434,481✔
287
                    return compare_float(double_val, b.double_val);
832,266✔
288
                case type_Decimal:
403,632✔
289
                    return Decimal128(double_val).compare(b.decimal_val);
5,688✔
290
                default:
5,301✔
291
                    break;
5,343✔
292
            }
5,343✔
293
            break;
5,343✔
294
        case type_Timestamp:
296,496✔
295
            if (b.get_type() == type_Timestamp) {
588,870✔
296
                return compare_generic(date_val, b.date_val);
588,693✔
297
            }
588,507✔
298
            break;
295,275✔
299
        case type_ObjectId:
43,899✔
300
            if (b.get_type() == type_ObjectId) {
88,641✔
301
                return compare_generic(id_val, b.id_val);
85,389✔
302
            }
82,269✔
303
            break;
45,060✔
304
        case type_Decimal:
230,073✔
305
            switch (b.get_type()) {
455,271✔
306
                case type_Int:
235,140✔
307
                    return decimal_val.compare(Decimal128(b.int_val));
13,671✔
308
                case type_Float:
9,120✔
309
                    return decimal_val.compare(Decimal128(b.float_val));
4,575✔
310
                case type_Double:
5,103✔
311
                    return decimal_val.compare(Decimal128(b.double_val));
5,646✔
312
                case type_Decimal:
215,892✔
313
                    return decimal_val.compare(b.decimal_val);
427,335✔
314
                default:
216,306✔
315
                    break;
4,044✔
316
            }
4,044✔
317
            break;
4,044✔
318
        case type_Link:
4,746✔
319
            if (b.get_type() == type_Link) {
5,541✔
320
                return compare_generic(int_val, b.int_val);
5,541✔
321
            }
5,541✔
322
            break;
2,823✔
323
        case type_TypedLink:
8,091✔
324
            if (b.is_type(type_TypedLink)) {
63,405✔
325
                return compare_generic(link_val, b.link_val);
63,357✔
326
            }
63,294✔
327
            break;
55,299✔
328
        case type_UUID:
153,480✔
329
            if (b.get_type() == type_UUID) {
314,625✔
330
                return compare_generic(uuid_val, b.uuid_val);
313,299✔
331
            }
312,123✔
332
            break;
161,358✔
333
        default:
32,184✔
334
            if (type == type_TypeOfValue && b.get_type() == type_TypeOfValue) {
61,809✔
335
                return TypeOfValue(int_val).matches(TypeOfValue(b.int_val)) ? 0 : compare_generic(int_val, b.int_val);
61,809✔
336
            }
51,906✔
337
            REALM_ASSERT_RELEASE(false && "Compare not supported for this column type");
30,774✔
338
            break;
27✔
339
    }
19,938✔
340

19,947✔
341
    // Comparing rank of types as a fallback makes it possible to sort of a list of Mixed
19,920✔
342
    REALM_ASSERT(sorting_rank[m_type] != sorting_rank[b.m_type]);
19,920✔
343
    // Using rank table will ensure that all numeric values are kept together
43,284✔
344
    return (sorting_rank[m_type] > sorting_rank[b.m_type]) ? 1 : -1;
19,920✔
345

19,920✔
346
    // Observe! Changing this function breaks the file format for Set<Mixed>
43,284✔
347
}
19,920✔
348

13,320✔
349
int Mixed::compare_signed(const Mixed& b) const noexcept
350
{
10,605✔
351
    if (is_type(type_String) && b.is_type(type_String)) {
33,969✔
352
        auto a_val = get_string();
10,521✔
353
        auto b_val = b.get_string();
10,521✔
354
        return a_val == b_val ? 0 : a_val < b_val ? -1 : 1;
21,645✔
355
    }
21,645✔
356
    return compare(b);
11,100✔
357
}
11,100✔
358

11,004✔
359
template <>
11,016✔
360
int64_t Mixed::export_to_type() const noexcept
108✔
361
{
7,033,776✔
362
    // If the common type is Int, then both values must be Int
7,033,668✔
363
    REALM_ASSERT(get_type() == type_Int);
7,033,668✔
364
    return int_val;
7,033,668✔
365
}
14,457,018✔
366

367
template <>
7,423,350✔
368
float Mixed::export_to_type() const noexcept
7,423,350✔
369
{
7,424,076✔
370
    // If the common type is Float, then values must be either Int or Float
726✔
371
    REALM_ASSERT(m_type);
726✔
372
    switch (get_type()) {
726✔
373
        case type_Int:
1,065✔
374
            return float(int_val);
339✔
375
        case type_Float:
1,113✔
376
            return float_val;
1,113✔
377
        default:
339✔
378
            REALM_ASSERT(false);
339✔
379
            break;
387✔
380
    }
387✔
381
    return 0.;
✔
382
}
×
383

384
template <>
385
double Mixed::export_to_type() const noexcept
386
{
1,296✔
387
    // If the common type is Double, then values must be either Int, Float or Double
1,296✔
388
    REALM_ASSERT(m_type);
1,296✔
389
    switch (get_type()) {
1,296✔
390
        case type_Int:
1,944✔
391
            return double(int_val);
648✔
392
        case type_Float:
1,296✔
393
            return double(float_val);
1,296✔
394
        case type_Double:
1,296✔
395
            return double_val;
1,296✔
396
        default:
✔
397
            REALM_ASSERT(false);
×
398
            break;
648✔
399
    }
648✔
400
    return 0.;
✔
401
}
×
402

403
template <>
404
Decimal128 Mixed::export_to_type() const noexcept
405
{
96✔
406
    REALM_ASSERT(m_type);
96✔
407
    switch (get_type()) {
96✔
408
        case type_Int:
48✔
409
            return Decimal128(int_val);
144✔
410
        case type_Float:
96✔
411
            return Decimal128(float_val);
96✔
412
        case type_Double:
48✔
413
            return Decimal128(double_val);
48✔
414
        case type_Decimal:
48✔
415
            return decimal_val;
48✔
416
        default:
✔
417
            REALM_ASSERT(false);
×
418
            break;
48✔
419
    }
48✔
420
    return {};
✔
421
}
×
422

423
template <>
424
util::Optional<int64_t> Mixed::get<util::Optional<int64_t>>() const noexcept
425
{
204✔
426
    if (is_null()) {
204✔
427
        return {};
428
    }
429
    return get<int64_t>();
942✔
430
}
942✔
431

738✔
432
template <>
720✔
433
util::Optional<bool> Mixed::get<util::Optional<bool>>() const noexcept
720✔
434
{
42✔
435
    if (is_null()) {
42✔
436
        return {};
18✔
NEW
437
    }
×
438
    return get<bool>();
24✔
439
}
24✔
440

441
template <>
442
util::Optional<float> Mixed::get<util::Optional<float>>() const noexcept
648✔
443
{
708✔
444
    if (is_null()) {
708✔
445
        return {};
384✔
446
    }
384✔
447
    return get<float>();
324✔
448
}
324✔
449

264✔
450
template <>
451
util::Optional<double> Mixed::get<util::Optional<double>>() const noexcept
452
{
60✔
453
    if (is_null()) {
60✔
454
        return {};
455
    }
204✔
456
    return get<double>();
264✔
457
}
60✔
458

459
template <>
204✔
460
util::Optional<ObjectId> Mixed::get<util::Optional<ObjectId>>() const noexcept
204✔
461
{
48✔
462
    if (is_null()) {
48✔
463
        return {};
464
    }
24✔
465
    return get<ObjectId>();
72✔
466
}
48✔
467

468
template <>
24✔
469
util::Optional<UUID> Mixed::get<util::Optional<UUID>>() const noexcept
24✔
470
{
48✔
471
    if (is_null()) {
48✔
472
        return {};
473
    }
60✔
474
    return get<UUID>();
108✔
475
}
48✔
476

477
static DataType get_common_type(DataType t1, DataType t2) noexcept
60✔
478
{
3,519,783✔
479
    // It might be by accident that this works, but it finds the most advanced type
3,519,723✔
480
    DataType common = std::max(t1, t2);
3,519,723✔
481
    return common;
3,519,723✔
482
}
3,519,783✔
483

60✔
484
Mixed Mixed::operator+(const Mixed& rhs) const noexcept
485
{
1,880,136✔
486
    if (!is_null() && !rhs.is_null()) {
1,880,196✔
487
        auto common_type = get_common_type(get_type(), rhs.get_type());
1,879,272✔
488
        switch (common_type) {
1,879,212✔
489
            case type_Int:
1,879,914✔
490
                return export_to_type<Int>() + rhs.export_to_type<Int>();
1,879,914✔
491
            case type_Float:
234✔
492
                return export_to_type<float>() + rhs.export_to_type<float>();
234✔
493
            case type_Double:
57✔
494
                return export_to_type<double>() + rhs.export_to_type<double>();
57✔
495
            case type_Decimal:
48✔
496
                return export_to_type<Decimal128>() + rhs.export_to_type<Decimal128>();
48✔
497
            default:
24✔
498
                break;
24✔
499
        }
948✔
500
    }
996✔
501
    return {};
996✔
502
}
948✔
503

504
Mixed Mixed::operator-(const Mixed& rhs) const noexcept
48✔
505
{
910,296✔
506
    if (!is_null() && !rhs.is_null()) {
910,248✔
507
        auto common_type = get_common_type(get_type(), rhs.get_type());
910,248✔
508
        switch (common_type) {
4,623,006✔
509
            case type_Int:
910,200✔
510
                return export_to_type<Int>() - rhs.export_to_type<Int>();
4,622,958✔
511
            case type_Float:
3,712,806✔
512
                return export_to_type<float>() - rhs.export_to_type<float>();
3,712,806✔
513
            case type_Double:
514
                return export_to_type<double>() - rhs.export_to_type<double>();
515
            case type_Decimal:
1,976,712✔
516
                return export_to_type<Decimal128>() - rhs.export_to_type<Decimal128>();
1,976,712✔
517
            default:
1,976,670✔
518
                break;
1,976,670✔
519
        }
1,976,403✔
520
    }
1,976,403✔
521
    return {};
186✔
522
}
186✔
523

57✔
524
Mixed Mixed::operator*(const Mixed& rhs) const noexcept
57✔
525
{
365,547✔
526
    if (!is_null() && !rhs.is_null()) {
365,547✔
527
        auto common_type = get_common_type(get_type(), rhs.get_type());
365,571✔
528
        switch (common_type) {
365,571✔
529
            case type_Int:
365,151✔
530
                return export_to_type<Int>() * rhs.export_to_type<Int>();
365,151✔
531
            case type_Float:
66✔
532
                return export_to_type<float>() * rhs.export_to_type<float>();
66✔
533
            case type_Double:
462✔
534
                return export_to_type<double>() * rhs.export_to_type<double>();
462✔
535
            case type_Decimal:
963,228✔
536
                return export_to_type<Decimal128>() * rhs.export_to_type<Decimal128>();
963,228✔
537
            default:
963,228✔
538
                break;
963,228✔
539
        }
963,180✔
540
    }
963,180✔
541
    return {};
48✔
542
}
48✔
543

2✔
544
Mixed Mixed::operator/(const Mixed& rhs) const noexcept
545
{
364,929✔
546
    if (!is_null() && !rhs.is_null()) {
364,929✔
547
        auto common_type = get_common_type(get_type(), rhs.get_type());
364,929✔
548
        switch (common_type) {
364,929✔
549
            case type_Int: {
364,623✔
550
                auto dividend = export_to_type<Int>();
364,623✔
551
                auto divisor = rhs.export_to_type<Int>();
364,623✔
552
                // We don't want to throw here. This is usually used as part of a query
364,623✔
553
                // and in this case we would just expect a no match
364,623✔
554
                if (divisor == 0)
364,623✔
555
                    return dividend < 0 ? std::numeric_limits<int64_t>::min() : std::numeric_limits<int64_t>::max();
387,051✔
556
                return dividend / divisor;
751,050✔
557
            }
751,050✔
558
            case type_Float:
751,050✔
559
                static_assert(std::numeric_limits<float>::is_iec559); // Infinity is supported
386,406✔
560
                return export_to_type<float>() / rhs.export_to_type<float>();
386,406✔
561
            case type_Double:
364,311✔
562
                static_assert(std::numeric_limits<double>::is_iec559); // Infinity is supported
129✔
563
                return export_to_type<double>() / rhs.export_to_type<double>();
591✔
564
            case type_Decimal:
364,773✔
565
                return export_to_type<Decimal128>() / rhs.export_to_type<Decimal128>();
48✔
566
            default:
364,311✔
567
                break;
✔
568
        }
×
569
    }
×
570
    return {};
×
571
}
×
572

573
size_t Mixed::hash() const
574
{
21,558✔
575
    if (is_null())
407,679✔
576
        return 0;
388,281✔
577

405,519✔
578
    size_t hash = 0;
405,519✔
579
    switch (get_type()) {
405,213✔
580
        case type_Int:
387,297✔
581
            hash = size_t(int_val);
387,297✔
582
            break;
1,482✔
583
        case type_Bool:
873✔
584
            hash = bool_val ? 0xdeadbeef : 0xcafebabe;
386,688✔
585
            break;
1,185✔
586
        case type_Float: {
385,503✔
587
            auto unsigned_data = reinterpret_cast<const unsigned char*>(&float_val);
385,503✔
588
            hash = murmur2_or_cityhash(unsigned_data, sizeof(float));
129✔
589
            break;
129✔
590
        }
129✔
591
        case type_Double: {
3,063✔
592
            auto unsigned_data = reinterpret_cast<const unsigned char*>(&double_val);
3,063✔
593
            hash = murmur2_or_cityhash(unsigned_data, sizeof(double));
3,063✔
594
            break;
2,982✔
595
        }
48✔
596
        case type_String:
8,154✔
597
            hash = get<StringData>().hash();
8,154✔
598
            break;
8,154✔
599
        case type_Binary: {
378✔
600
            auto bin = get<BinaryData>();
378✔
601
            StringData str(bin.data(), bin.size());
378✔
602
            hash = str.hash();
378✔
603
            break;
378✔
604
        }
20,169✔
605
        case type_Timestamp:
21,615✔
606
            hash = get<Timestamp>().hash();
3,300✔
607
            break;
1,446✔
608
        case type_ObjectId:
19,692✔
609
            hash = get<ObjectId>().hash();
19,692✔
610
            break;
2,841✔
611
        case type_UUID: {
2,841✔
612
            hash = get<UUID>().hash();
2,841✔
613
            break;
2,250✔
614
        }
447✔
615
        case type_TypedLink: {
873✔
616
            auto unsigned_data = reinterpret_cast<const unsigned char*>(&link_val);
✔
617
            hash = murmur2_or_cityhash(unsigned_data, 12);
×
618
            break;
×
619
        }
×
620
        case type_Decimal: {
1,377✔
621
            auto value = get<Decimal128>();
4,305✔
622
            auto unsigned_data = reinterpret_cast<const unsigned char*>(value.raw());
4,305✔
623
            hash = murmur2_or_cityhash(unsigned_data, sizeof(Decimal128::Bid128));
4,305✔
624
            break;
4,305✔
625
        }
×
626
        case type_Mixed:
5,400✔
627
        case type_Link:
5,400✔
628
        case type_LinkList:
5,400✔
629
            REALM_ASSERT_RELEASE(false && "Hash not supported for this column type");
2,124✔
630
            break;
2,124✔
631
    }
21,522✔
632

21,522✔
633
    return hash;
21,522✔
634
}
19,398✔
635

1,404✔
636
StringData Mixed::get_index_data(std::array<char, 16>& buffer) const noexcept
1,404✔
637
{
3,183,705✔
638
    if (is_null()) {
3,183,675✔
639
        return {};
230,643✔
640
    }
230,643✔
641
    switch (get_type()) {
2,954,406✔
642
        case type_Int: {
1,833,846✔
643
            int64_t i = get_int();
1,833,846✔
644
            const char* c = reinterpret_cast<const char*>(&i);
1,832,472✔
645
            realm::safe_copy_n(c, sizeof(int64_t), buffer.data());
1,832,472✔
646
            return StringData{buffer.data(), sizeof(int64_t)};
1,832,472✔
647
        }
×
648
        case type_Bool: {
17,505✔
649
            int64_t i = get_bool() ? 1 : 0;
17,505✔
650
            return Mixed(i).get_index_data(buffer);
18,879✔
651
        }
1,374✔
652
        case type_Float: {
1,386✔
653
            auto v2 = get_float();
1,386✔
654
            int i = int(v2);
1,386✔
655
            if (i == v2) {
12✔
656
                return Mixed(i).get_index_data(buffer);
✔
657
            }
✔
658
            const char* src = reinterpret_cast<const char*>(&v2);
12✔
659
            realm::safe_copy_n(src, sizeof(float), buffer.data());
12✔
660
            return StringData{buffer.data(), sizeof(float)};
12✔
661
        }
18,327✔
662
        case type_Double: {
24✔
663
            auto v2 = get_double();
18,339✔
664
            int i = int(v2);
18,339✔
665
            if (i == v2) {
24✔
666
                return Mixed(i).get_index_data(buffer);
12✔
667
            }
3,257,511✔
668
            const char* src = reinterpret_cast<const char*>(&v2);
3,257,511✔
669
            realm::safe_copy_n(src, sizeof(double), buffer.data());
227,847✔
670
            return StringData{buffer.data(), sizeof(double)};
227,847✔
671
        }
3,029,676✔
672
        case type_String:
2,541,741✔
673
            return get_string();
2,541,741✔
674
        case type_Binary: {
1,897,842✔
675
            auto bin = get_binary();
1,897,836✔
676
            return {bin.data(), bin.size()};
1,897,836✔
677
        }
12✔
678
        case type_Timestamp: {
41,025✔
679
            auto dt = get<Timestamp>();
33,546✔
680
            int64_t s = dt.get_seconds();
41,025✔
681
            int32_t ns = dt.get_nanoseconds();
23,685✔
682
            constexpr size_t index_size = sizeof(s) + sizeof(ns);
23,697✔
683
            const char* s_buf = reinterpret_cast<const char*>(&s);
23,697✔
684
            const char* ns_buf = reinterpret_cast<const char*>(&ns);
23,697✔
685
            realm::safe_copy_n(s_buf, sizeof(s), buffer.data());
23,697✔
686
            realm::safe_copy_n(ns_buf, sizeof(ns), buffer.data() + sizeof(s));
23,685✔
687
            return StringData{buffer.data(), index_size};
23,685✔
688
        }
24✔
689
        case type_ObjectId: {
424,545✔
690
            auto id = get<ObjectId>();
424,545✔
691
            memcpy(&buffer, &id, sizeof(ObjectId));
424,545✔
692
            return StringData{buffer.data(), sizeof(ObjectId)};
424,557✔
693
        }
36✔
694
        case type_Decimal: {
39✔
695
            auto v2 = this->get_decimal();
39✔
696
            int64_t i;
27✔
697
            if (v2.to_int(i)) {
27✔
698
                return Mixed(i).get_index_data(buffer);
21✔
699
            }
21✔
700
            const char* src = reinterpret_cast<const char*>(&v2);
18✔
701
            realm::safe_copy_n(src, sizeof(v2), buffer.data());
18✔
702
            return StringData{buffer.data(), sizeof(v2)};
648,504✔
703
        }
648,504✔
704
        case type_UUID: {
12,756✔
705
            auto id = get<UUID>();
12,756✔
706
            const auto bytes = id.to_bytes();
12,756✔
707
            std::copy_n(bytes.data(), bytes.size(), buffer.begin());
12,753✔
708
            return StringData{buffer.data(), bytes.size()};
36,072✔
709
        }
23,337✔
710
        case type_TypedLink: {
23,358✔
711
            auto link = get<ObjLink>();
23,358✔
712
            uint32_t k1 = link.get_table_key().value;
23,358✔
713
            int64_t k2 = link.get_obj_key().value;
23,358✔
714
            const char* src = reinterpret_cast<const char*>(&k1);
23,358✔
715
            realm::safe_copy_n(src, sizeof(k1), buffer.data());
23,358✔
716
            src = reinterpret_cast<const char*>(&k2);
23,358✔
717
            realm::safe_copy_n(src, sizeof(k2), buffer.data() + sizeof(k1));
23,358✔
718
            return StringData{buffer.data(), sizeof(k1) + sizeof(k2)};
39✔
719
        }
430,170✔
720
        case type_Mixed:
430,170✔
721
        case type_Link:
430,164✔
722
        case type_LinkList:
430,164✔
723
            break;
12✔
724
    }
15✔
725
    REALM_ASSERT_RELEASE(false && "Index not supported for this column type");
15✔
726
    return {};
15✔
727
}
15✔
728

9✔
729
void Mixed::use_buffer(std::string& buf) noexcept
9✔
730
{
1,604,229✔
731
    if (is_null()) {
1,604,229✔
732
        return;
1,584,399✔
733
    }
1,584,399✔
734
    switch (get_type()) {
32,571✔
735
        case type_String:
17,418✔
736
            buf = std::string(string_val);
17,418✔
737
            string_val = StringData(buf);
17,418✔
738
            break;
17,418✔
739
        case type_Binary:
117✔
740
            buf = std::string(binary_val);
138✔
741
            binary_val = BinaryData(buf);
138✔
742
            break;
138✔
743
        default:
15,075✔
744
            break;
15,075✔
745
    }
19,857✔
746
}
19,857✔
747

27✔
748
// LCOV_EXCL_START
27✔
749
std::ostream& operator<<(std::ostream& out, const Mixed& m)
6✔
750
{
12,978✔
751
    if (m.is_null()) {
12,978✔
752
        out << "null";
132✔
753
    }
132✔
754
    else {
12,846✔
755
        switch (m.get_type()) {
12,846✔
756
            case type_Int:
4,290✔
757
                out << m.int_val;
4,290✔
758
                break;
4,290✔
759
            case type_Bool:
441✔
760
                out << (m.bool_val ? "true" : "false");
468✔
761
                break;
468✔
762
            case type_Float:
474✔
763
                out << m.float_val;
453✔
764
                break;
453✔
765
            case type_Double:
747✔
766
                out << m.double_val;
747✔
767
                break;
747✔
768
            case type_String:
1,173✔
769
                out << util::serializer::print_value(m.string_val);
1,173✔
770
                break;
1,176✔
771
            case type_Binary:
444✔
772
                out << util::serializer::print_value(m.binary_val);
444✔
773
                break;
459✔
774
            case type_Timestamp:
438✔
775
                out << util::serializer::print_value(m.date_val);
438✔
776
                break;
513✔
777
            case type_Decimal:
522✔
778
                out << m.decimal_val;
522✔
779
                break;
522✔
780
            case type_ObjectId:
3,972✔
781
                out << util::serializer::print_value(m.id_val);
3,894✔
782
                break;
3,897✔
783
            case type_Link:
9✔
784
                out << util::serializer::print_value(ObjKey(m.int_val));
9✔
785
                break;
6✔
786
            case type_TypedLink:
3✔
787
                out << util::serializer::print_value(m.link_val);
81✔
788
                break;
81✔
789
            case type_UUID:
618✔
790
                out << util::serializer::print_value(m.uuid_val);
540✔
791
                break;
540✔
792
            case type_Mixed:
3✔
793
            case type_LinkList:
78✔
794
                REALM_ASSERT(false);
78✔
795
        }
12,849✔
796
    }
12,849✔
797
    return out;
12,981✔
798
}
12,981✔
799
// LCOV_EXCL_STOP
3✔
800

18✔
801

3✔
802
} // namespace realm
3✔
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

© 2026 Coveralls, Inc