• 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

80.0
/src/realm/array_blobs_small.hpp
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
#ifndef REALM_ARRAY_BLOBS_SMALL_HPP
20
#define REALM_ARRAY_BLOBS_SMALL_HPP
21

22
#include <realm/array_blob.hpp>
23
#include <realm/exceptions.hpp>
24

25
namespace realm {
26

27
/*
28
STORAGE FORMAT
29
---------------------------------------------------------------------------------------
30
ArraySmallBlobs stores binary elements using two ArrayInteger and one ArrayBlob. The ArrayBlob can only store one
31
single concecutive array of bytes (contrary to its 'Array' name that misleadingly indicates it could store multiple
32
elements).
33

34
Assume we have the strings "a", "", "abc", null, "ab". Then the three arrays will contain:
35

36
ArrayInteger    m_offsets   1, 1, 5, 5, 6
37
ArrayBlob       m_blob      aabcab
38
ArrayInteger    m_nulls     0, 0, 0, 1, 0 // 1 indicates null, 0 indicates non-null
39

40
So for each element the ArrayInteger, the ArrayInteger points into the ArrayBlob at the position of the first
41
byte of the next element.
42

43
m_nulls is always present (except for old database files; see below), so any ArraySmallBlobs is always nullable!
44
The nullable property (such as throwing exception upon set(null) on non-nullable column, etc) is handled on
45
column level only.
46

47
DATABASE FILE VERSION CHANGES
48
---------------------------------------------------------------------------------------
49
Old database files do not have any m_nulls array. To be backwardscompatible, many methods will have tests like
50
`if(Array::size() == 3)` and have a backwards compatible code paths for these (e.g. avoid writing to m_nulls
51
in set(), etc). This way no file format upgrade is needed to support nulls for BinaryData.
52
*/
53

54
class ArraySmallBlobs : public Array {
55
public:
56
    explicit ArraySmallBlobs(Allocator&) noexcept;
57
    ~ArraySmallBlobs() noexcept override {}
29,880✔
58

59
    // Disable copying, this is not allowed.
60
    ArraySmallBlobs& operator=(const ArraySmallBlobs&) = delete;
61
    ArraySmallBlobs(const ArraySmallBlobs&) = delete;
62

63
    /// Create a new empty binary array and attach this accessor to
64
    /// it. This does not modify the parent reference information of
65
    /// this accessor.
66
    ///
67
    /// Note that the caller assumes ownership of the allocated
68
    /// underlying node. It is not owned by the accessor.
69
    void create();
70

71
    //@{
72
    /// Overriding functions of Array
73
    void init_from_ref(ref_type) noexcept;
74
    void init_from_mem(MemRef) noexcept;
75
    void init_from_parent() noexcept;
76
    //@}
77

78
    bool is_empty() const noexcept;
79
    size_t size() const noexcept;
80

81
    BinaryData get(size_t ndx) const noexcept;
82
    StringData get_string(size_t ndx) const;
83
    bool is_null(size_t ndx) const;
84

85
    void add(BinaryData value, bool add_zero_term = false);
86
    void set(size_t ndx, BinaryData value, bool add_zero_term = false);
87
    void insert(size_t ndx, BinaryData value, bool add_zero_term = false);
88
    void add_string(StringData value);
89
    void set_string(size_t ndx, StringData value);
90
    void insert_string(size_t ndx, StringData value);
91
    void erase(size_t ndx);
92
    void truncate(size_t new_size);
93
    void clear();
94
    void destroy();
95

96
    size_t find_first(BinaryData value, bool is_string, size_t begin, size_t end) const noexcept;
97

98
    /// Get the specified element without the cost of constructing an
99
    /// array instance. If an array instance is already available, or
100
    /// you need to get multiple values, then this method will be
101
    /// slower.
102
    static BinaryData get(const char* header, size_t ndx, Allocator&) noexcept;
103
    static StringData get_string(const char* header, size_t ndx, Allocator& alloc) noexcept;
104

105
    static size_t get_size_from_header(const char*, Allocator&) noexcept;
106

107
    /// Construct a binary array of the specified size and return just
108
    /// the reference to the underlying memory. All elements will be
109
    /// initialized to the binary value `defaults`, which can be either
110
    /// null or zero-length non-null (value with size > 0 is not allowed as
111
    /// initialization value).
112
    static MemRef create_array(size_t size, Allocator&, BinaryData defaults);
113

114
    void update_from_parent() noexcept;
115

116
private:
117
    friend class ArrayString;
118
    Array m_offsets;
119
    ArrayBlob m_blob;
120
    Array m_nulls;
121

122
    StringData get_string_legacy(size_t ndx) const;
123
};
124

125

126
// Implementation:
127

128
inline ArraySmallBlobs::ArraySmallBlobs(Allocator& allocator) noexcept
129
    : Array(allocator)
5,359,149✔
130
    , m_offsets(allocator)
5,359,149✔
131
    , m_blob(allocator)
5,359,149✔
132
    , m_nulls(allocator)
5,359,149✔
133
{
10,728,900✔
134
    m_offsets.set_parent(this, 0);
10,728,900✔
135
    m_blob.set_parent(this, 1);
10,728,900✔
136
    m_nulls.set_parent(this, 2);
10,728,900✔
137
}
10,728,900✔
138

139
inline void ArraySmallBlobs::create()
140
{
165,246✔
141
    size_t init_size = 0;
165,246✔
142
    BinaryData defaults = BinaryData{};                          // This init value is ignored because size = 0
165,246✔
143
    MemRef mem = create_array(init_size, get_alloc(), defaults); // Throws
165,246✔
144
    init_from_mem(mem);
165,246✔
145
}
165,246✔
146

147
inline void ArraySmallBlobs::init_from_ref(ref_type ref) noexcept
148
{
×
149
    REALM_ASSERT(ref);
×
150
    char* header = get_alloc().translate(ref);
×
151
    init_from_mem(MemRef(header, ref, m_alloc));
×
152
}
×
153

154
inline void ArraySmallBlobs::init_from_parent() noexcept
155
{
×
156
    ref_type ref = get_ref_from_parent();
×
157
    init_from_ref(ref);
×
158
}
×
159

160
inline bool ArraySmallBlobs::is_empty() const noexcept
161
{
2✔
162
    return m_offsets.is_empty();
2✔
163
}
2✔
164

165
inline size_t ArraySmallBlobs::size() const noexcept
166
{
5,688,795✔
167
    return m_offsets.size();
5,688,795✔
168
}
5,688,795✔
169

170
inline BinaryData ArraySmallBlobs::get(size_t ndx) const noexcept
171
{
4,027,260✔
172
    REALM_ASSERT_3(ndx, <, m_offsets.size());
4,027,260✔
173

174
    if (m_nulls.get(ndx)) {
4,027,260✔
175
        return BinaryData();
263,715✔
176
    }
263,715✔
177
    else {
3,763,545✔
178
        size_t begin = ndx ? to_size_t(m_offsets.get(ndx - 1)) : 0;
3,763,545✔
179
        size_t end = to_size_t(m_offsets.get(ndx));
3,763,545✔
180

181
        BinaryData bd = BinaryData(m_blob.get(begin), end - begin);
3,763,545✔
182
        // Old database file (non-nullable column should never return null)
183
        REALM_ASSERT(!bd.is_null());
3,763,545✔
184
        return bd;
3,763,545✔
185
    }
3,763,545✔
186
}
4,027,260✔
187

188
inline bool ArraySmallBlobs::is_null(size_t ndx) const
189
{
39,264✔
190
    REALM_ASSERT_3(ndx, <, m_nulls.size());
39,264✔
191

192
    return m_nulls.get(ndx) != 0;
39,264✔
193
}
39,264✔
194

195
inline StringData ArraySmallBlobs::get_string(size_t ndx) const
196
{
1,133,781✔
197
    BinaryData bin = get(ndx);
1,133,781✔
198
    if (bin.is_null())
1,133,781✔
199
        return realm::null();
29,499✔
200
    else
1,104,282✔
201
        return StringData(bin.data(), bin.size() - 1); // Do not include terminating zero
1,104,282✔
202
}
1,133,781✔
203

204
inline StringData ArraySmallBlobs::get_string(const char* header, size_t ndx, Allocator& alloc) noexcept
205
{
194,808✔
206
    BinaryData bin = get(header, ndx, alloc);
194,808✔
207
    if (bin.is_null())
194,808✔
208
        return realm::null();
12,297✔
209
    else
182,511✔
210
        return StringData(bin.data(), bin.size() - 1); // Do not include terminating zero
182,511✔
211
}
194,808✔
212

213
inline void ArraySmallBlobs::add_string(StringData value)
214
{
50,445✔
215
    add(BinaryData(value.data(), value.size()), true);
50,445✔
216
}
50,445✔
217

218
inline void ArraySmallBlobs::set_string(size_t ndx, StringData value)
219
{
238,395✔
220
    set(ndx, BinaryData(value.data(), value.size()), true);
238,395✔
221
}
238,395✔
222

223
inline void ArraySmallBlobs::insert_string(size_t ndx, StringData value)
224
{
295,611✔
225
    insert(ndx, BinaryData(value.data(), value.size()), true);
295,611✔
226
}
295,611✔
227

228
inline void ArraySmallBlobs::truncate(size_t new_size)
229
{
120✔
230
    REALM_ASSERT(new_size == 0 || new_size < m_offsets.size());
120✔
231

232
    size_t sz = new_size ? to_size_t(m_offsets.get(new_size - 1)) : 0;
120✔
233

234
    m_offsets.truncate(new_size);
120✔
235
    m_blob.truncate(sz);
120✔
236
    m_nulls.truncate(new_size);
120✔
237
}
120✔
238

239
inline void ArraySmallBlobs::clear()
240
{
94,053✔
241
    m_blob.clear();
94,053✔
242
    m_offsets.clear();
94,053✔
243
    m_nulls.clear();
94,053✔
244
}
94,053✔
245

246
inline void ArraySmallBlobs::destroy()
247
{
44,442✔
248
    m_blob.destroy();
44,442✔
249
    m_offsets.destroy();
44,442✔
250
    m_nulls.destroy();
44,442✔
251
    Array::destroy();
44,442✔
252
}
44,442✔
253

254
inline size_t ArraySmallBlobs::get_size_from_header(const char* header, Allocator& alloc) noexcept
UNCOV
255
{
×
256
    ref_type offsets_ref = to_ref(Array::get(header, 0));
×
257
    const char* offsets_header = alloc.translate(offsets_ref);
×
258
    return Array::get_size_from_header(offsets_header);
×
259
}
×
260

261
inline void ArraySmallBlobs::update_from_parent() noexcept
UNCOV
262
{
×
263
    Array::update_from_parent();
×
264
    m_blob.update_from_parent();
×
265
    m_offsets.update_from_parent();
×
266
    m_nulls.update_from_parent();
×
267
}
×
268

269
} // namespace realm
270

271
#endif // REALM_ARRAY_BINARY_HPP
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