added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / column_mixed_tpl.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 #include <realm/column_binary.hpp>
20 #include <realm/column_timestamp.hpp>
21
22 namespace realm {
23
24 inline MixedColumn::MixedColumn(Allocator& alloc, ref_type ref, Table* table, size_t column_ndx)
25     : ColumnBaseSimple(column_ndx)
26 {
27     create(alloc, ref, table, column_ndx);
28 }
29
30 inline void MixedColumn::adj_acc_insert_rows(size_t row_ndx, size_t num_rows) noexcept
31 {
32     m_data->adj_acc_insert_rows(row_ndx, num_rows);
33 }
34
35 inline void MixedColumn::adj_acc_erase_row(size_t row_ndx) noexcept
36 {
37     m_data->adj_acc_erase_row(row_ndx);
38 }
39
40 inline void MixedColumn::adj_acc_swap_rows(size_t row_ndx_1, size_t row_ndx_2) noexcept
41 {
42     m_data->adj_acc_swap_rows(row_ndx_1, row_ndx_2);
43 }
44
45 inline void MixedColumn::adj_acc_move_row(size_t from_ndx, size_t to_ndx) noexcept
46 {
47     m_data->adj_acc_move_row(from_ndx, to_ndx);
48 }
49
50 inline void MixedColumn::adj_acc_move_over(size_t from_row_ndx, size_t to_row_ndx) noexcept
51 {
52     m_data->adj_acc_move_over(from_row_ndx, to_row_ndx);
53 }
54
55 inline void MixedColumn::adj_acc_clear_root_table() noexcept
56 {
57     m_data->adj_acc_clear_root_table();
58 }
59
60 inline ref_type MixedColumn::get_subtable_ref(size_t row_ndx) const noexcept
61 {
62     REALM_ASSERT_3(row_ndx, <, m_types->size());
63     if (m_types->get(row_ndx) != type_Table)
64         return 0;
65     return m_data->get_as_ref(row_ndx);
66 }
67
68 inline size_t MixedColumn::get_subtable_size(size_t row_ndx) const noexcept
69 {
70     ref_type top_ref = get_subtable_ref(row_ndx);
71     if (top_ref == 0)
72         return 0;
73     return _impl::TableFriend::get_size_from_ref(top_ref, m_data->get_alloc());
74 }
75
76 inline TableRef MixedColumn::get_subtable_accessor(size_t row_ndx) const noexcept
77 {
78     return m_data->get_subtable_accessor(row_ndx);
79 }
80
81 inline void MixedColumn::discard_subtable_accessor(size_t row_ndx) noexcept
82 {
83     m_data->discard_subtable_accessor(row_ndx);
84 }
85
86 inline TableRef MixedColumn::get_subtable_tableref(size_t row_ndx)
87 {
88     REALM_ASSERT_3(row_ndx, <, m_types->size());
89     if (m_types->get(row_ndx) != type_Table)
90         return {};
91     return m_data->get_subtable_tableref(row_ndx); // Throws
92 }
93
94 inline ConstTableRef MixedColumn::get_subtable_tableref(size_t subtable_ndx) const
95 {
96     return const_cast<MixedColumn*>(this)->get_subtable_tableref(subtable_ndx);
97 }
98
99 inline void MixedColumn::discard_child_accessors() noexcept
100 {
101     m_data->discard_child_accessors();
102 }
103
104
105 //
106 // Getters
107 //
108
109 #define REALM_BIT63 0x8000000000000000ULL
110
111 inline int64_t MixedColumn::get_value(size_t ndx) const noexcept
112 {
113     REALM_ASSERT_3(ndx, <, m_types->size());
114
115     // Shift the unsigned value right - ensuring 0 gets in from left.
116     // Shifting signed integers right doesn't ensure 0's.
117     uint64_t value = uint64_t(m_data->get(ndx)) >> 1;
118     return int64_t(value);
119 }
120
121 inline int64_t MixedColumn::get_int(size_t ndx) const noexcept
122 {
123     // Get first 63 bits of the integer value
124     int64_t value = get_value(ndx);
125
126     // restore 'sign'-bit from the column-type
127     MixedColType col_type = MixedColType(m_types->get(ndx));
128     if (col_type == mixcol_IntNeg) {
129         // FIXME: Bad cast of result of '|' from unsigned to signed
130         value |= REALM_BIT63; // set sign bit (63)
131     }
132     else {
133         REALM_ASSERT_3(col_type, ==, mixcol_Int);
134     }
135     return value;
136 }
137
138 inline bool MixedColumn::get_bool(size_t ndx) const noexcept
139 {
140     REALM_ASSERT_3(m_types->get(ndx), ==, mixcol_Bool);
141
142     return (get_value(ndx) != 0);
143 }
144
145 inline OldDateTime MixedColumn::get_olddatetime(size_t ndx) const noexcept
146 {
147     REALM_ASSERT_3(m_types->get(ndx), ==, mixcol_OldDateTime);
148
149     return OldDateTime(get_value(ndx));
150 }
151
152 inline float MixedColumn::get_float(size_t ndx) const noexcept
153 {
154     static_assert(std::numeric_limits<float>::is_iec559, "'float' is not IEEE");
155     static_assert((sizeof(float) * CHAR_BIT == 32), "Assume 32 bit float.");
156     REALM_ASSERT_3(m_types->get(ndx), ==, mixcol_Float);
157
158     return type_punning<float>(get_value(ndx));
159 }
160
161 inline double MixedColumn::get_double(size_t ndx) const noexcept
162 {
163     static_assert(std::numeric_limits<double>::is_iec559, "'double' is not IEEE");
164     static_assert((sizeof(double) * CHAR_BIT == 64), "Assume 64 bit double.");
165
166     int64_t int_val = get_value(ndx);
167
168     // restore 'sign'-bit from the column-type
169     MixedColType col_type = MixedColType(m_types->get(ndx));
170     if (col_type == mixcol_DoubleNeg)
171         int_val |= REALM_BIT63; // set sign bit (63)
172     else {
173         REALM_ASSERT_3(col_type, ==, mixcol_Double);
174     }
175     return type_punning<double>(int_val);
176 }
177
178 inline StringData MixedColumn::get_string(size_t ndx) const noexcept
179 {
180     REALM_ASSERT_3(ndx, <, m_types->size());
181     REALM_ASSERT_3(m_types->get(ndx), ==, mixcol_String);
182     REALM_ASSERT(m_binary_data);
183
184     size_t data_ndx = size_t(int64_t(m_data->get(ndx)) >> 1);
185     return m_binary_data->get_string(data_ndx);
186 }
187
188 inline BinaryData MixedColumn::get_binary(size_t ndx) const noexcept
189 {
190     REALM_ASSERT_3(ndx, <, m_types->size());
191     REALM_ASSERT_3(m_types->get(ndx), ==, mixcol_Binary);
192     REALM_ASSERT(m_binary_data);
193
194     size_t data_ndx = size_t(uint64_t(m_data->get(ndx)) >> 1);
195     return m_binary_data->get(data_ndx);
196 }
197
198 inline Timestamp MixedColumn::get_timestamp(size_t ndx) const noexcept
199 {
200     REALM_ASSERT_3(ndx, <, m_types->size());
201     REALM_ASSERT_3(m_types->get(ndx), ==, mixcol_Timestamp);
202     REALM_ASSERT(m_timestamp_data);
203     size_t data_ndx = size_t(uint64_t(m_data->get(ndx)) >> 1);
204     return m_timestamp_data->get(data_ndx);
205 }
206
207 //
208 // Setters
209 //
210
211 // Set a int64 value.
212 // Store 63 bit of the value in m_data. Store sign bit in m_types.
213
214 inline void MixedColumn::set_int64(size_t ndx, int64_t value, MixedColType pos_type, MixedColType neg_type)
215 {
216     REALM_ASSERT_3(ndx, <, m_types->size());
217
218     // If sign-bit is set in value, 'store' it in the column-type
219     MixedColType coltype = ((value & REALM_BIT63) == 0) ? pos_type : neg_type;
220
221     // Remove refs or binary data (sets type to double)
222     clear_value_and_discard_subtab_acc(ndx, coltype); // Throws
223
224     // Shift value one bit and set lowest bit to indicate that this is not a ref
225     value = (value << 1) + 1;
226     m_data->set(ndx, value);
227 }
228
229 inline void MixedColumn::set_int(size_t ndx, int64_t value)
230 {
231     set_int64(ndx, value, mixcol_Int, mixcol_IntNeg); // Throws
232 }
233
234 inline void MixedColumn::set_double(size_t ndx, double value)
235 {
236     int64_t val64 = type_punning<int64_t>(value);
237     set_int64(ndx, val64, mixcol_Double, mixcol_DoubleNeg); // Throws
238 }
239
240 inline void MixedColumn::set_value(size_t ndx, int64_t value, MixedColType coltype)
241 {
242     REALM_ASSERT_3(ndx, <, m_types->size());
243
244     // Remove refs or binary data (sets type to float)
245     clear_value_and_discard_subtab_acc(ndx, coltype); // Throws
246
247     // Shift value one bit and set lowest bit to indicate that this is not a ref
248     int64_t v = (value << 1) + 1;
249     m_data->set(ndx, v); // Throws
250 }
251
252 inline void MixedColumn::set_float(size_t ndx, float value)
253 {
254     int64_t val64 = type_punning<int64_t>(value);
255     set_value(ndx, val64, mixcol_Float); // Throws
256 }
257
258 inline void MixedColumn::set_bool(size_t ndx, bool value)
259 {
260     set_value(ndx, (value ? 1 : 0), mixcol_Bool); // Throws
261 }
262
263 inline void MixedColumn::set_olddatetime(size_t ndx, OldDateTime value)
264 {
265     set_value(ndx, int64_t(value.get_olddatetime()), mixcol_OldDateTime); // Throws
266 }
267
268 inline void MixedColumn::set_subtable(size_t ndx, const Table* t)
269 {
270     REALM_ASSERT_3(ndx, <, m_types->size());
271     typedef _impl::TableFriend tf;
272     ref_type ref;
273     if (t) {
274         ref = tf::clone(*t, get_alloc()); // Throws
275     }
276     else {
277         ref = tf::create_empty_table(get_alloc()); // Throws
278     }
279     // Remove any previous refs or binary data
280     clear_value_and_discard_subtab_acc(ndx, mixcol_Table); // Throws
281     m_data->set(ndx, ref);                                 // Throws
282 }
283
284 //
285 // Inserts
286 //
287
288 inline void MixedColumn::insert_value(size_t row_ndx, int_fast64_t types_value, int_fast64_t data_value)
289 {
290     size_t types_size = m_types->size(); // Slow
291     bool is_append = row_ndx == types_size;
292     size_t row_ndx_2 = is_append ? realm::npos : row_ndx;
293     size_t num_rows = 1;
294     m_types->insert_without_updating_index(row_ndx_2, types_value, num_rows); // Throws
295     m_data->do_insert(row_ndx_2, data_value, num_rows);                       // Throws
296 }
297
298 // Insert a int64 value.
299 // Store 63 bit of the value in m_data. Store sign bit in m_types.
300
301 inline void MixedColumn::insert_int(size_t ndx, int_fast64_t value, MixedColType type)
302 {
303     int_fast64_t types_value = type;
304     // Shift value one bit and set lowest bit to indicate that this is not a ref
305     int_fast64_t data_value = 1 + (value << 1);
306     insert_value(ndx, types_value, data_value); // Throws
307 }
308
309 inline void MixedColumn::insert_pos_neg(size_t ndx, int_fast64_t value, MixedColType pos_type, MixedColType neg_type)
310 {
311     // 'store' the sign-bit in the integer-type
312     MixedColType type = (value & REALM_BIT63) == 0 ? pos_type : neg_type;
313     int_fast64_t types_value = type;
314     // Shift value one bit and set lowest bit to indicate that this is not a ref
315     int_fast64_t data_value = 1 + (value << 1);
316     insert_value(ndx, types_value, data_value); // Throws
317 }
318
319 inline void MixedColumn::insert_int(size_t ndx, int_fast64_t value)
320 {
321     insert_pos_neg(ndx, value, mixcol_Int, mixcol_IntNeg); // Throws
322 }
323
324 inline void MixedColumn::insert_double(size_t ndx, double value)
325 {
326     int_fast64_t value_2 = type_punning<int64_t>(value);
327     insert_pos_neg(ndx, value_2, mixcol_Double, mixcol_DoubleNeg); // Throws
328 }
329
330 inline void MixedColumn::insert_float(size_t ndx, float value)
331 {
332     int_fast64_t value_2 = type_punning<int32_t>(value);
333     insert_int(ndx, value_2, mixcol_Float); // Throws
334 }
335
336 inline void MixedColumn::insert_bool(size_t ndx, bool value)
337 {
338     int_fast64_t value_2 = int_fast64_t(value);
339     insert_int(ndx, value_2, mixcol_Bool); // Throws
340 }
341
342 inline void MixedColumn::insert_olddatetime(size_t ndx, OldDateTime value)
343 {
344     int_fast64_t value_2 = int_fast64_t(value.get_olddatetime());
345     insert_int(ndx, value_2, mixcol_OldDateTime); // Throws
346 }
347
348 inline void MixedColumn::insert_timestamp(size_t ndx, Timestamp value)
349 {
350     ensure_timestamp_column();
351     size_t data_ndx = m_timestamp_data->size();
352     m_timestamp_data->add(value); // Throws
353     insert_int(ndx, int_fast64_t(data_ndx), mixcol_Timestamp);
354 }
355
356 inline void MixedColumn::insert_string(size_t ndx, StringData value)
357 {
358     ensure_binary_data_column();
359     size_t blob_ndx = m_binary_data->size();
360     m_binary_data->add_string(value); // Throws
361
362     int_fast64_t value_2 = int_fast64_t(blob_ndx);
363     insert_int(ndx, value_2, mixcol_String); // Throws
364 }
365
366 inline void MixedColumn::insert_binary(size_t ndx, BinaryData value)
367 {
368     ensure_binary_data_column();
369     size_t blob_ndx = m_binary_data->size();
370     m_binary_data->add(value); // Throws
371
372     int_fast64_t value_2 = int_fast64_t(blob_ndx);
373     insert_int(ndx, value_2, mixcol_Binary); // Throws
374 }
375
376 inline void MixedColumn::insert_subtable(size_t ndx, const Table* t)
377 {
378     typedef _impl::TableFriend tf;
379     ref_type ref;
380     if (t) {
381         ref = tf::clone(*t, get_alloc()); // Throws
382     }
383     else {
384         ref = tf::create_empty_table(get_alloc()); // Throws
385     }
386     int_fast64_t types_value = mixcol_Table;
387     int_fast64_t data_value = int_fast64_t(ref);
388     insert_value(ndx, types_value, data_value); // Throws
389 }
390
391 inline void MixedColumn::erase(size_t row_ndx)
392 {
393     size_t num_rows_to_erase = 1;
394     size_t prior_num_rows = size();                       // Note that size() is slow
395     do_erase(row_ndx, num_rows_to_erase, prior_num_rows); // Throws
396 }
397
398 inline void MixedColumn::move_last_over(size_t row_ndx)
399 {
400     size_t prior_num_rows = size();             // Note that size() is slow
401     do_move_last_over(row_ndx, prior_num_rows); // Throws
402 }
403
404 inline void MixedColumn::swap_rows(size_t row_ndx_1, size_t row_ndx_2)
405 {
406     do_swap_rows(row_ndx_1, row_ndx_2);
407 }
408
409 inline void MixedColumn::clear()
410 {
411     size_t num_rows = size(); // Note that size() is slow
412     do_clear(num_rows);       // Throws
413 }
414
415 inline size_t MixedColumn::get_size_from_ref(ref_type root_ref, Allocator& alloc) noexcept
416 {
417     const char* root_header = alloc.translate(root_ref);
418     ref_type types_ref = to_ref(Array::get(root_header, 0));
419     return IntegerColumn::get_size_from_ref(types_ref, alloc);
420 }
421
422 inline void MixedColumn::clear_value_and_discard_subtab_acc(size_t row_ndx, MixedColType new_type)
423 {
424     MixedColType old_type = clear_value(row_ndx, new_type);
425     if (old_type == mixcol_Table)
426         m_data->discard_subtable_accessor(row_ndx);
427 }
428
429 // Implementing pure virtual method of ColumnBase.
430 inline void MixedColumn::insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows,
431                                      bool insert_nulls)
432 {
433     REALM_ASSERT_DEBUG(prior_num_rows == size());
434     REALM_ASSERT(row_ndx <= prior_num_rows);
435     REALM_ASSERT(!insert_nulls);
436
437     size_t row_ndx_2 = (row_ndx == prior_num_rows ? realm::npos : row_ndx);
438
439     int_fast64_t type_value = mixcol_Int;
440     m_types->insert_without_updating_index(row_ndx_2, type_value, num_rows_to_insert); // Throws
441
442     // The least significant bit indicates that the rest of the bits form an
443     // integer value, so 1 is actually zero.
444     int_fast64_t data_value = 1;
445     m_data->do_insert(row_ndx_2, data_value, num_rows_to_insert); // Throws
446 }
447
448 // Implementing pure virtual method of ColumnBase.
449 inline void MixedColumn::erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows, bool)
450 {
451     do_erase(row_ndx, num_rows_to_erase, prior_num_rows); // Throws
452 }
453
454 // Implementing pure virtual method of ColumnBase.
455 inline void MixedColumn::move_last_row_over(size_t row_ndx, size_t prior_num_rows, bool)
456 {
457     do_move_last_over(row_ndx, prior_num_rows); // Throws
458 }
459
460 // Implementing pure virtual method of ColumnBase.
461 inline void MixedColumn::clear(size_t num_rows, bool)
462 {
463     do_clear(num_rows); // Throws
464 }
465
466 inline void MixedColumn::mark(int type) noexcept
467 {
468     m_data->mark(type);
469 }
470
471 inline void MixedColumn::refresh_accessor_tree(size_t col_ndx, const Spec& spec)
472 {
473     ColumnBaseSimple::refresh_accessor_tree(col_ndx, spec);
474
475     get_root_array()->init_from_parent();
476     m_types->refresh_accessor_tree(col_ndx, spec); // Throws
477     m_data->refresh_accessor_tree(col_ndx, spec);  // Throws
478
479     m_binary_data.reset();
480     // See if m_binary_data needs to be created.
481     if (get_root_array()->size() >= 3) {
482         ref_type ref = get_root_array()->get_as_ref(2);
483         m_binary_data.reset(new BinaryColumn(get_alloc(), ref)); // Throws
484         m_binary_data->set_parent(get_root_array(), 2);
485     }
486
487     m_timestamp_data.reset();
488     // See if m_timestamp_data needs to be created.
489     if (get_root_array()->size() >= 4) {
490         ref_type ref = get_root_array()->get_as_ref(3);
491         // When adding/creating a Mixed column the user cannot specify nullability, so the "true" below
492         // makes it implicitly nullable, which may not be wanted. But it's OK since Mixed columns are not
493         // publicly supported
494         m_timestamp_data.reset(new TimestampColumn(true /*fixme*/, get_alloc(), ref)); // Throws
495         m_timestamp_data->set_parent(get_root_array(), 3);
496     }
497
498     if (m_binary_data) {
499         REALM_ASSERT_3(get_root_array()->size(), >=, 3);
500         m_binary_data->refresh_accessor_tree(col_ndx, spec); // Throws
501     }
502     if (m_timestamp_data) {
503         REALM_ASSERT_3(get_root_array()->size(), >=, 4);
504         m_timestamp_data->refresh_accessor_tree(col_ndx, spec); // Throws
505     }
506 }
507
508 inline void MixedColumn::RefsColumn::refresh_accessor_tree(size_t col_ndx, const Spec& spec)
509 {
510     SubtableColumnBase::refresh_accessor_tree(col_ndx, spec); // Throws
511     m_subtable_map.refresh_accessor_tree();                   // Throws
512 }
513
514 } // namespace realm