added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / array_string.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_STRING_HPP
20 #define REALM_ARRAY_STRING_HPP
21
22 #include <realm/array.hpp>
23
24 namespace realm {
25
26 /*
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.
29
30 An example of the format for m_width = 4 is following sequence of bytes, where x is payload:
31
32 xxx0 xx01 x002 0003 0004 (strings "xxx",. "xx", "x", "", realm::null())
33
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
36 in various functions.
37
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.
40 */
41
42 class ArrayString : public Array {
43 public:
44     static const size_t max_width = 64;
45
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
51     {
52     }
53
54     bool is_null(size_t ndx) const;
55     void set_null(size_t ndx);
56     StringData get(size_t ndx) const noexcept;
57     void add();
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);
62
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,
66                   size_t end = npos);
67
68     /// Compare two string arrays for equality.
69     bool compare_string(const ArrayString&) const noexcept;
70
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
74     /// slower.
75     static StringData get(const char* header, size_t ndx, bool nullable) noexcept;
76
77     ref_type bptree_leaf_insert(size_t ndx, StringData, TreeInsertBase& state);
78
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&);
83
84     /// Create a new empty string array and attach this accessor to
85     /// it. This does not modify the parent reference information of
86     /// this accessor.
87     ///
88     /// Note that the caller assumes ownership of the allocated
89     /// underlying node. It is not owned by the accessor.
90     void create();
91
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;
95
96 #ifdef REALM_DEBUG
97     void string_stats() const;
98     void to_dot(std::ostream&, StringData title = StringData()) const;
99 #endif
100
101 private:
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;
104
105     bool m_nullable;
106 };
107
108
109 // Implementation:
110
111 // Creates new array (but invalid, call init_from_ref() to init)
112 inline ArrayString::ArrayString(Allocator& allocator, bool nullable) noexcept
113     : Array(allocator)
114     , m_nullable(nullable)
115 {
116 }
117
118 inline void ArrayString::create()
119 {
120     size_t init_size = 0;
121     MemRef mem = create_array(init_size, get_alloc()); // Throws
122     init_from_mem(mem);
123 }
124
125 inline MemRef ArrayString::create_array(size_t init_size, Allocator& allocator)
126 {
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
130 }
131
132 inline StringData ArrayString::get(size_t ndx) const noexcept
133 {
134     REALM_ASSERT_3(ndx, <, m_size);
135     if (m_width == 0)
136         return m_nullable ? realm::null() : StringData("");
137
138     const char* data = m_data + (ndx * m_width);
139     size_t array_size = (m_width - 1) - data[m_width - 1];
140
141     if (array_size == static_cast<size_t>(-1))
142         return m_nullable ? realm::null() : StringData("");
143
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);
147 }
148
149 inline void ArrayString::add(StringData value)
150 {
151     REALM_ASSERT(!(!m_nullable && value.is_null()));
152     insert(m_size, value); // Throws
153 }
154
155 inline void ArrayString::add()
156 {
157     add(m_nullable ? realm::null() : StringData("")); // Throws
158 }
159
160 inline StringData ArrayString::get(const char* header, size_t ndx, bool nullable) noexcept
161 {
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);
165
166     if (width == 0)
167         return nullable ? realm::null() : StringData("");
168
169     size_t size = (width - 1) - data[width - 1];
170
171     if (size == static_cast<size_t>(-1))
172         return nullable ? realm::null() : StringData("");
173
174     return StringData(data, size);
175 }
176
177
178 } // namespace realm
179
180 #endif // REALM_ARRAY_STRING_HPP