1 /*************************************************************************
3 * Copyright 2016 Realm Inc.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 **************************************************************************/
19 #ifndef REALM_ARRAY_STRING_HPP
20 #define REALM_ARRAY_STRING_HPP
22 #include <realm/array.hpp>
27 ArrayString stores strings as a concecutive list of fixed-length blocks of m_width bytes. The
28 longest string it can store is (m_width - 1) bytes before it needs to expand.
30 An example of the format for m_width = 4 is following sequence of bytes, where x is payload:
32 xxx0 xx01 x002 0003 0004 (strings "xxx",. "xx", "x", "", realm::null())
34 So each string is 0 terminated, and the last byte in a block tells how many 0s are present, except
35 for a realm::null() which has the byte set to m_width (4). The byte is used to compute the length of a string
38 New: If m_witdh = 0, then all elements are realm::null(). So to add an empty string we must expand m_width
39 New: StringData is null() if-and-only-if StringData::data() == 0.
42 class ArrayString : public Array {
44 static const size_t max_width = 64;
46 typedef StringData value_type;
47 // Constructor defaults to non-nullable because we use non-nullable ArrayString so many places internally in core
48 // (data which isn't user payload) where null isn't needed.
49 explicit ArrayString(Allocator&, bool nullable = false) noexcept;
50 ~ArrayString() noexcept override
54 bool is_null(size_t ndx) const;
55 void set_null(size_t ndx);
56 StringData get(size_t ndx) const noexcept;
58 void add(StringData value);
59 void set(size_t ndx, StringData value);
60 void insert(size_t ndx, StringData value);
61 void erase(size_t ndx);
63 size_t count(StringData value, size_t begin = 0, size_t end = npos) const noexcept;
64 size_t find_first(StringData value, size_t begin = 0, size_t end = npos) const noexcept;
65 void find_all(IntegerColumn& result, StringData value, size_t add_offset = 0, size_t begin = 0,
68 /// Compare two string arrays for equality.
69 bool compare_string(const ArrayString&) const noexcept;
71 /// Get the specified element without the cost of constructing an
72 /// array instance. If an array instance is already available, or
73 /// you need to get multiple values, then this method will be
75 static StringData get(const char* header, size_t ndx, bool nullable) noexcept;
77 ref_type bptree_leaf_insert(size_t ndx, StringData, TreeInsertBase& state);
79 /// Construct a string array of the specified size and return just
80 /// the reference to the underlying memory. All elements will be
81 /// initialized to the empty string.
82 static MemRef create_array(size_t size, Allocator&);
84 /// Create a new empty string array and attach this accessor to
85 /// it. This does not modify the parent reference information of
88 /// Note that the caller assumes ownership of the allocated
89 /// underlying node. It is not owned by the accessor.
92 /// Construct a copy of the specified slice of this string array
93 /// using the specified target allocator.
94 MemRef slice(size_t offset, size_t slice_size, Allocator& target_alloc) const;
97 void string_stats() const;
98 void to_dot(std::ostream&, StringData title = StringData()) const;
102 size_t calc_byte_len(size_t num_items, size_t width) const override;
103 size_t calc_item_count(size_t bytes, size_t width) const noexcept override;
111 // Creates new array (but invalid, call init_from_ref() to init)
112 inline ArrayString::ArrayString(Allocator& allocator, bool nullable) noexcept
114 , m_nullable(nullable)
118 inline void ArrayString::create()
120 size_t init_size = 0;
121 MemRef mem = create_array(init_size, get_alloc()); // Throws
125 inline MemRef ArrayString::create_array(size_t init_size, Allocator& allocator)
127 bool context_flag = false;
128 int_fast64_t value = 0;
129 return Array::create(type_Normal, context_flag, wtype_Multiply, init_size, value, allocator); // Throws
132 inline StringData ArrayString::get(size_t ndx) const noexcept
134 REALM_ASSERT_3(ndx, <, m_size);
136 return m_nullable ? realm::null() : StringData("");
138 const char* data = m_data + (ndx * m_width);
139 size_t array_size = (m_width - 1) - data[m_width - 1];
141 if (array_size == static_cast<size_t>(-1))
142 return m_nullable ? realm::null() : StringData("");
144 REALM_ASSERT_EX(data[array_size] == 0, data[array_size],
145 array_size); // Realm guarantees 0 terminated return strings
146 return StringData(data, array_size);
149 inline void ArrayString::add(StringData value)
151 REALM_ASSERT(!(!m_nullable && value.is_null()));
152 insert(m_size, value); // Throws
155 inline void ArrayString::add()
157 add(m_nullable ? realm::null() : StringData("")); // Throws
160 inline StringData ArrayString::get(const char* header, size_t ndx, bool nullable) noexcept
162 REALM_ASSERT(ndx < get_size_from_header(header));
163 uint_least8_t width = get_width_from_header(header);
164 const char* data = get_data_from_header(header) + (ndx * width);
167 return nullable ? realm::null() : StringData("");
169 size_t size = (width - 1) - data[width - 1];
171 if (size == static_cast<size_t>(-1))
172 return nullable ? realm::null() : StringData("");
174 return StringData(data, size);
180 #endif // REALM_ARRAY_STRING_HPP