added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / column_string_enum.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_COLUMN_STRING_ENUM_HPP
20 #define REALM_COLUMN_STRING_ENUM_HPP
21
22 #include <realm/column_string.hpp>
23
24 namespace realm {
25
26 // Pre-declarations
27 class StringIndex;
28
29
30 /// From the point of view of the application, an enumerated strings column
31 /// (StringEnumColumn) is like a string column (StringColumn), yet it manages
32 /// its strings in such a way that each unique string is stored only once. In
33 /// fact, an enumerated strings column is a combination of two subcolumns; a
34 /// regular string column (StringColumn) that stores the unique strings, and an
35 /// integer column that stores one unique string index for each entry in the
36 /// enumerated strings column.
37 ///
38 /// In terms of the underlying node structure, the subcolumn containing the
39 /// unique strings is not a true part of the enumerated strings column. Instead
40 /// it is a part of the spec structure that describes the table of which the
41 /// enumerated strings column is a part. This way, the unique strings can be
42 /// shared across enumerated strings columns of multiple subtables. This also
43 /// means that the root of an enumerated strings column coincides with the root
44 /// of the integer subcolumn, and in some sense, an enumerated strings column is
45 /// just the integer subcolumn.
46 ///
47 /// An enumerated strings column can optionally be equipped with a
48 /// search index. If it is, then the root ref of the index is stored
49 /// in Table::m_columns immediately after the root ref of the
50 /// enumerated strings column.
51 class StringEnumColumn : public IntegerColumn {
52 public:
53     typedef StringData value_type;
54
55     StringEnumColumn(Allocator&, ref_type ref, ref_type keys_ref, bool nullable, size_t column_ndx = npos);
56     ~StringEnumColumn() noexcept override;
57     void destroy() noexcept override;
58     MemRef clone_deep(Allocator& alloc) const override;
59
60     int compare_values(size_t row1, size_t row2) const noexcept override
61     {
62         StringData a = get(row1);
63         StringData b = get(row2);
64
65         if (a.is_null() && !b.is_null())
66             return 1;
67         else if (b.is_null() && !a.is_null())
68             return -1;
69         else if (a.is_null() && b.is_null())
70             return 0;
71
72         if (a == b)
73             return 0;
74
75         return utf8_compare(a, b) ? 1 : -1;
76     }
77
78     StringData get(size_t ndx) const noexcept;
79     bool is_null(size_t ndx) const noexcept final;
80     void set(size_t ndx, StringData value);
81     void set_null(size_t ndx) override;
82     void add();
83     void add(StringData value);
84     void insert(size_t ndx);
85     void insert(size_t ndx, StringData value);
86     void erase(size_t row_ndx);
87     void move_last_over(size_t row_ndx);
88     void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
89     void clear();
90     bool is_nullable() const noexcept final;
91
92     size_t count(StringData value) const;
93     size_t find_first(StringData value, size_t begin = 0, size_t end = npos) const;
94     void find_all(IntegerColumn& res, StringData value, size_t begin = 0, size_t end = npos) const;
95     FindRes find_all_no_copy(StringData value, InternalFindResult& result) const;
96
97     size_t count(size_t key_index) const;
98     size_t find_first(size_t key_index, size_t begin = 0, size_t end = -1) const;
99     void find_all(IntegerColumn& res, size_t key_index, size_t begin = 0, size_t end = -1) const;
100
101     //@{
102     /// Find the lower/upper bound for the specified value assuming
103     /// that the elements are already sorted in ascending order
104     /// according to StringData::operator<().
105     size_t lower_bound_string(StringData value) const noexcept;
106     size_t upper_bound_string(StringData value) const noexcept;
107     //@}
108
109     void set_string(size_t, StringData) override;
110
111     void adjust_keys_ndx_in_parent(int diff) noexcept;
112
113     // Search index
114     StringData get_index_data(size_t ndx, StringIndex::StringConversionBuffer& buffer) const noexcept final;
115     bool supports_search_index() const noexcept final
116     {
117         return true;
118     }
119     StringIndex* create_search_index() override;
120     void install_search_index(std::unique_ptr<StringIndex>) noexcept;
121     void destroy_search_index() noexcept override;
122
123     // Compare two string columns for equality
124     bool compare_string(const StringColumn&) const;
125     bool compare_string(const StringEnumColumn&) const;
126
127     void insert_rows(size_t, size_t, size_t, bool) override;
128     void erase_rows(size_t, size_t, size_t, bool) override;
129     void move_last_row_over(size_t, size_t, bool) override;
130     void clear(size_t, bool) override;
131     void update_from_parent(size_t) noexcept override;
132     void refresh_accessor_tree(size_t, const Spec&) override;
133
134     size_t get_key_ndx(StringData value) const;
135     size_t get_key_ndx_or_add(StringData value);
136
137     StringColumn& get_keys();
138     const StringColumn& get_keys() const;
139
140 #ifdef REALM_DEBUG
141     void verify() const override;
142     void verify(const Table&, size_t) const override;
143     void do_dump_node_structure(std::ostream&, int) const override;
144     void to_dot(std::ostream&, StringData title) const override;
145 #endif
146
147 private:
148     // Member variables
149     StringColumn m_keys;
150     bool m_nullable;
151
152     /// If you are appending and have the size of the column readily available,
153     /// call the 4 argument version instead. If you are not appending, either
154     /// one is fine.
155     ///
156     /// \param row_ndx Must be `realm::npos` if appending.
157     void do_insert(size_t row_ndx, StringData value, size_t num_rows);
158
159     /// If you are appending and you do not have the size of the column readily
160     /// available, call the 3 argument version instead. If you are not
161     /// appending, either one is fine.
162     ///
163     /// \param is_append Must be true if, and only if `row_ndx` is equal to the
164     /// size of the column (before insertion).
165     void do_insert(size_t row_ndx, StringData value, size_t num_rows, bool is_append);
166
167     void do_erase(size_t row_ndx, bool is_last);
168     void do_move_last_over(size_t row_ndx, size_t last_row_ndx);
169     void do_clear();
170 };
171
172
173 // Implementation:
174
175 inline StringData StringEnumColumn::get(size_t ndx) const noexcept
176 {
177     REALM_ASSERT_3(ndx, <, IntegerColumn::size());
178     size_t key_ndx = to_size_t(IntegerColumn::get(ndx));
179     StringData sd = m_keys.get(key_ndx);
180     REALM_ASSERT_DEBUG(!(!m_nullable && sd.is_null()));
181     return sd;
182 }
183
184 inline bool StringEnumColumn::is_null(size_t ndx) const noexcept
185 {
186     return is_nullable() && get(ndx).is_null();
187 }
188
189 inline void StringEnumColumn::add()
190 {
191     add(m_nullable ? realm::null() : StringData(""));
192 }
193
194 inline void StringEnumColumn::add(StringData value)
195 {
196     REALM_ASSERT_DEBUG(!(!m_nullable && value.is_null()));
197     size_t row_ndx = realm::npos;
198     size_t num_rows = 1;
199     do_insert(row_ndx, value, num_rows); // Throws
200 }
201
202 inline void StringEnumColumn::insert(size_t row_ndx)
203 {
204     insert(row_ndx, m_nullable ? realm::null() : StringData(""));
205 }
206
207 inline void StringEnumColumn::insert(size_t row_ndx, StringData value)
208 {
209     REALM_ASSERT_DEBUG(!(!m_nullable && value.is_null()));
210     size_t column_size = this->size();
211     REALM_ASSERT_3(row_ndx, <=, column_size);
212     size_t num_rows = 1;
213     bool is_append = row_ndx == column_size;
214     do_insert(row_ndx, value, num_rows, is_append); // Throws
215 }
216
217 inline void StringEnumColumn::erase(size_t row_ndx)
218 {
219     size_t last_row_ndx = size() - 1; // Note that size() is slow
220     bool is_last = row_ndx == last_row_ndx;
221     do_erase(row_ndx, is_last); // Throws
222 }
223
224 inline void StringEnumColumn::move_last_over(size_t row_ndx)
225 {
226     size_t last_row_ndx = size() - 1;         // Note that size() is slow
227     do_move_last_over(row_ndx, last_row_ndx); // Throws
228 }
229
230 inline void StringEnumColumn::clear()
231 {
232     do_clear(); // Throws
233 }
234
235 // Overriding virtual method of Column.
236 inline void StringEnumColumn::insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows,
237                                           bool insert_nulls)
238 {
239     REALM_ASSERT_DEBUG(prior_num_rows == size());
240     REALM_ASSERT(row_ndx <= prior_num_rows);
241     REALM_ASSERT(!insert_nulls || m_nullable);
242
243     StringData value = m_nullable ? realm::null() : StringData("");
244     bool is_append = (row_ndx == prior_num_rows);
245     do_insert(row_ndx, value, num_rows_to_insert, is_append); // Throws
246 }
247
248 // Overriding virtual method of Column.
249 inline void StringEnumColumn::erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows, bool)
250 {
251     REALM_ASSERT_DEBUG(prior_num_rows == size());
252     REALM_ASSERT(num_rows_to_erase <= prior_num_rows);
253     REALM_ASSERT(row_ndx <= prior_num_rows - num_rows_to_erase);
254
255     bool is_last = (row_ndx + num_rows_to_erase == prior_num_rows);
256     for (size_t i = num_rows_to_erase; i > 0; --i) {
257         size_t row_ndx_2 = row_ndx + i - 1;
258         do_erase(row_ndx_2, is_last); // Throws
259     }
260 }
261
262 // Overriding virtual method of Column.
263 inline void StringEnumColumn::move_last_row_over(size_t row_ndx, size_t prior_num_rows, bool)
264 {
265     REALM_ASSERT_DEBUG(prior_num_rows == size());
266     REALM_ASSERT(row_ndx < prior_num_rows);
267
268     size_t last_row_ndx = prior_num_rows - 1;
269     do_move_last_over(row_ndx, last_row_ndx); // Throws
270 }
271
272 // Overriding virtual method of Column.
273 inline void StringEnumColumn::clear(size_t, bool)
274 {
275     do_clear(); // Throws
276 }
277
278 inline size_t StringEnumColumn::lower_bound_string(StringData value) const noexcept
279 {
280     return ColumnBase::lower_bound(*this, value);
281 }
282
283 inline size_t StringEnumColumn::upper_bound_string(StringData value) const noexcept
284 {
285     return ColumnBase::upper_bound(*this, value);
286 }
287
288 inline void StringEnumColumn::set_string(size_t row_ndx, StringData value)
289 {
290     set(row_ndx, value); // Throws
291 }
292
293 inline void StringEnumColumn::set_null(size_t row_ndx)
294 {
295     set(row_ndx, realm::null{});
296 }
297
298 inline StringColumn& StringEnumColumn::get_keys()
299 {
300     return m_keys;
301 }
302
303 inline const StringColumn& StringEnumColumn::get_keys() const
304 {
305     return m_keys;
306 }
307
308
309 } // namespace realm
310
311 #endif // REALM_COLUMN_STRING_ENUM_HPP