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

realm / realm-core / jorgen.edelbo_390

12 Aug 2024 12:13PM UTC coverage: 91.108% (+0.02%) from 91.085%
jorgen.edelbo_390

Pull #7979

Evergreen

jedelbo
Create test file in file-format 24
Pull Request #7979: Create test file in file-format 24

102766 of 181590 branches covered (56.59%)

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

1020 existing lines in 55 files now uncovered.

217365 of 238579 relevant lines covered (91.11%)

5621116.99 hits per line

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

91.79
/src/realm/array_integer.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 <vector>
20

21
#include <realm/array_integer_tpl.hpp>
22
#include <realm/impl/destroy_guard.hpp>
23
#include <realm/column_integer.hpp>
24

25
using namespace realm;
26

27
Mixed ArrayInteger::get_any(size_t ndx) const
28
{
20,030,652✔
29
    return Mixed(get(ndx));
20,030,652✔
30
}
20,030,652✔
31

32
size_t ArrayInteger::find_first_in_range(int64_t from, int64_t to, size_t start, size_t end) const
33
{
9,612✔
34
    if (m_ubound >= from && m_lbound <= to) {
9,612✔
35
        while (start < end) {
12,066✔
36
            auto val = get(start);
12,006✔
37
            if (from <= val && val <= to)
12,006✔
38
                return start;
9,546✔
39
            start++;
2,460✔
40
        }
2,460✔
41
    }
9,606✔
42
    return realm::not_found;
66✔
43
}
9,612✔
44

45
Mixed ArrayIntNull::get_any(size_t ndx) const
46
{
12,347,772✔
47
    return Mixed(get(ndx));
12,347,772✔
48
}
12,347,772✔
49

50
MemRef ArrayIntNull::create_array(Type type, bool context_flag, size_t size, Allocator& alloc)
51
{
97,779✔
52
    // Create an array with null value as the first element
53
    return Array::create(type, context_flag, wtype_Bits, size + 1, 0, alloc); // Throws
97,779✔
54
}
97,779✔
55

56

57
void ArrayIntNull::init_from_ref(ref_type ref) noexcept
58
{
86,515,158✔
59
    REALM_ASSERT_DEBUG(ref);
86,515,158✔
60
    char* header = m_alloc.translate(ref);
86,515,158✔
61
    init_from_mem(MemRef{header, ref, m_alloc});
86,515,158✔
62
}
86,515,158✔
63

64
void ArrayIntNull::init_from_mem(MemRef mem) noexcept
65
{
86,571,576✔
66
    Array::init_from_mem(mem);
86,571,576✔
67

68
    // We always have the null value stored at position 0
69
    REALM_ASSERT(m_size > 0);
86,571,576✔
70
}
86,571,576✔
71

72
void ArrayIntNull::init_from_parent() noexcept
73
{
9,633,969✔
74
    init_from_ref(get_ref_from_parent());
9,633,969✔
75
}
9,633,969✔
76

77
namespace {
78
int64_t next_null_candidate(int64_t previous_candidate)
79
{
23,952✔
80
    uint64_t x = static_cast<uint64_t>(previous_candidate);
23,952✔
81
    // Increment by a prime number. This guarantees that we will
82
    // eventually hit every possible integer in the 2^64 range.
83
    x += 0xfffffffbULL;
23,952✔
84
    return int64_t(x);
23,952✔
85
}
23,952✔
86
} // namespace
87

88
int_fast64_t ArrayIntNull::choose_random_null(int64_t incoming) const
89
{
23,946✔
90
    // We just need any number -- it could have been `rand()`, but
91
    // random numbers are hard, and we don't want to risk locking mutices
92
    // or saving state. The top of the stack should be "random enough".
93
    int64_t candidate = reinterpret_cast<int64_t>(&candidate);
23,946✔
94

95
    while (true) {
23,952✔
96
        candidate = next_null_candidate(candidate);
23,952✔
97
        if (candidate == incoming) {
23,952✔
98
            continue;
6✔
99
        }
6✔
100
        if (can_use_as_null(candidate)) {
23,946✔
101
            return candidate;
23,946✔
102
        }
23,946✔
103
    }
23,946✔
104
}
23,946✔
105

106
bool ArrayIntNull::can_use_as_null(int64_t candidate) const
107
{
23,946✔
108
    return find_first(candidate) == npos;
23,946✔
109
}
23,946✔
110

111
void ArrayIntNull::replace_nulls_with(int64_t new_null)
112
{
109,002✔
113
    int64_t old_null = null_value();
109,002✔
114
    Array::set(0, new_null);
109,002✔
115
    size_t i = 1;
109,002✔
116
    while (true) {
154,002✔
117
        size_t found = Array::find_first(old_null, i);
154,002✔
118
        if (found < Array::size()) {
154,002✔
119
            Array::set(found, new_null);
45,000✔
120
            i = found + 1;
45,000✔
121
        }
45,000✔
122
        else {
109,002✔
123
            break;
109,002✔
124
        }
109,002✔
125
    }
154,002✔
126
}
109,002✔
127

128

129
void ArrayIntNull::avoid_null_collision(int64_t value)
130
{
5,132,049✔
131
    if (m_width == 64) {
5,132,049✔
132
        if (value == null_value()) {
184,800✔
133
            int_fast64_t new_null = choose_random_null(value);
6✔
134
            replace_nulls_with(new_null);
6✔
135
        }
6✔
136
    }
184,800✔
137
    else {
4,947,249✔
138
        if (value < m_lbound || value >= m_ubound) {
4,947,249✔
139
            size_t new_width = bit_width(value);
108,996✔
140
            int64_t new_upper_bound = Array::ubound_for_width(new_width);
108,996✔
141

142
            // We're using upper bound as magic NULL value, so we have to check
143
            // explicitly that the incoming value doesn't happen to be the new
144
            // NULL value. If it is, we upgrade one step further.
145
            if (new_width < 64 && value == new_upper_bound) {
108,996✔
146
                new_width = (new_width == 0 ? 1 : new_width * 2);
48,579✔
147
                new_upper_bound = Array::ubound_for_width(new_width);
48,579✔
148
            }
48,579✔
149

150
            int64_t new_null;
108,996✔
151
            if (new_width == 64) {
108,996✔
152
                // Width will be upgraded to 64, so we need to pick a random NULL.
153
                new_null = choose_random_null(value);
23,940✔
154
            }
23,940✔
155
            else {
85,056✔
156
                new_null = new_upper_bound;
85,056✔
157
            }
85,056✔
158

159
            replace_nulls_with(new_null); // Expands array
108,996✔
160
        }
108,996✔
161
    }
4,947,249✔
162
}
5,132,049✔
163

164
void ArrayIntNull::find_all(IntegerColumn* result, value_type value, size_t col_offset, size_t begin,
165
                            size_t end) const
166
{
6✔
167
    // FIXME: We can't use the fast Array::find_all here, because it would put the wrong indices
168
    // in the result column. Since find_all may be invoked many times for different leaves in the
169
    // B+tree with the same result column, we also can't simply adjust indices after finding them
170
    // (because then the first indices would be adjusted multiple times for each subsequent leaf)
171

172
    if (end == npos) {
6✔
173
        end = size();
6✔
174
    }
6✔
175

176
    for (size_t i = begin; i < end; ++i) {
612✔
177
        if (get(i) == value) {
606✔
178
            result->add(col_offset + i);
12✔
179
        }
12✔
180
    }
606✔
181
}
6✔
182

183
bool ArrayIntNull::find(int cond, value_type value, size_t start, size_t end, QueryStateBase* state) const
UNCOV
184
{
×
UNCOV
185
    return find_impl(cond, value, start, end, state);
×
UNCOV
186
}
×
187

188
size_t ArrayIntNull::find_first(value_type value, size_t begin, size_t end) const
189
{
35,664✔
190
    return find_first<Equal>(value, begin, end);
35,664✔
191
}
35,664✔
192

193
size_t ArrayIntNull::find_first_in_range(int64_t from, int64_t to, size_t start, size_t end) const
194
{
1,950✔
195
    if (m_ubound >= from && m_lbound <= to) {
1,950✔
196
        for (size_t i = start; i < end; i++) {
6,390✔
197
            auto val = get(i);
6,282✔
198
            if (val && *val >= from && *val <= to)
6,282✔
199
                return i;
1,836✔
200
        }
6,282✔
201
    }
1,944✔
202
    return realm::not_found;
114✔
203
}
1,950✔
204

205
void ArrayIntNull::get_chunk(size_t ndx, value_type res[8]) const noexcept
UNCOV
206
{
×
207
    // FIXME: Optimize this
UNCOV
208
    int64_t tmp[8];
×
UNCOV
209
    Array::get_chunk(ndx + 1, tmp);
×
UNCOV
210
    int64_t null = null_value();
×
211
    for (size_t i = 0; i < 8; ++i) {
×
UNCOV
212
        res[i] = tmp[i] == null ? util::Optional<int64_t>() : tmp[i];
×
213
    }
×
214
}
×
215

216
void ArrayIntNull::move(ArrayIntNull& dst, size_t ndx)
217
{
9,723✔
218
    size_t sz = size();
9,723✔
219
    for (size_t i = ndx; i < sz; i++) {
1,086,891✔
220
        dst.add(get(i));
1,077,168✔
221
    }
1,077,168✔
222
    truncate(ndx + 1);
9,723✔
223
}
9,723✔
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