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_COLUMN_MIXED_HPP
20 #define REALM_COLUMN_MIXED_HPP
24 #include <realm/column.hpp>
25 #include <realm/column_type.hpp>
26 #include <realm/column_table.hpp>
27 #include <realm/table.hpp>
28 #include <realm/utilities.hpp>
38 /// A mixed column (MixedColumn) is composed of three subcolumns. The first
39 /// subcolumn is an integer column (Column) and stores value types. The second
40 /// one stores values and is a subtable parent column (SubtableColumnBase),
41 /// which is a subclass of an integer column (Column). The last one is a binary
42 /// column (BinaryColumn) and stores additional data for values of type string
43 /// or binary data. The last subcolumn is optional. The root of a mixed column
44 /// is an array node of type Array that stores the root refs of the subcolumns.
45 class MixedColumn : public ColumnBaseSimple {
47 /// Create a mixed column wrapper and attach it to a preexisting
48 /// underlying structure of arrays.
50 /// \param alloc The memory allocator to change the underlying
51 /// structure in memory.
53 /// \param ref The memory reference of the MixedColumn for which
54 /// this accessor should be creator for.
56 /// \param table If this column is used as part of a table you
57 /// must pass a pointer to that table. Otherwise you must pass
60 /// \param column_ndx If this column is used as part of a table
61 /// you must pass the logical index of the column within that
62 /// table. Otherwise you should pass zero.
63 MixedColumn(Allocator& alloc, ref_type ref, Table* table, size_t column_ndx);
65 ~MixedColumn() noexcept override;
67 DataType get_type(size_t ndx) const noexcept;
68 size_t size() const noexcept final
70 return m_types->size();
72 bool is_empty() const noexcept
77 int64_t get_int(size_t ndx) const noexcept;
78 bool get_bool(size_t ndx) const noexcept;
79 OldDateTime get_olddatetime(size_t ndx) const noexcept;
80 Timestamp get_timestamp(size_t ndx) const noexcept;
81 float get_float(size_t ndx) const noexcept;
82 double get_double(size_t ndx) const noexcept;
83 StringData get_string(size_t ndx) const noexcept;
84 BinaryData get_binary(size_t ndx) const noexcept;
85 StringData get_index_data(size_t ndx, StringIndex::StringConversionBuffer& buffer) const noexcept override;
87 /// The returned array ref is zero if the specified row does not
88 /// contain a subtable.
89 ref_type get_subtable_ref(size_t row_ndx) const noexcept;
91 /// The returned size is zero if the specified row does not
92 /// contain a subtable.
93 size_t get_subtable_size(size_t row_ndx) const noexcept;
95 TableRef get_subtable_accessor(size_t row_ndx) const noexcept override;
97 void discard_subtable_accessor(size_t row_ndx) noexcept override;
99 /// If the value at the specified index is a subtable, return a
100 /// TableRef to that accessor for that subtable. Otherwise return
101 /// null. The accessor will be created if it does not already
103 TableRef get_subtable_tableref(size_t row_ndx);
105 ConstTableRef get_subtable_tableref(size_t subtable_ndx) const;
107 void set_int(size_t ndx, int64_t value);
108 void set_bool(size_t ndx, bool value);
109 void set_olddatetime(size_t ndx, OldDateTime value);
110 void set_timestamp(size_t ndx, Timestamp value);
111 void set_float(size_t ndx, float value);
112 void set_double(size_t ndx, double value);
113 void set_string(size_t ndx, StringData value) override;
114 void set_binary(size_t ndx, BinaryData value);
115 void set_subtable(size_t ndx, const Table* value);
117 void insert_int(size_t ndx, int_fast64_t value);
118 void insert_bool(size_t ndx, bool value);
119 void insert_olddatetime(size_t ndx, OldDateTime value);
120 void insert_timestamp(size_t ndx, Timestamp value);
121 void insert_float(size_t ndx, float value);
122 void insert_double(size_t ndx, double value);
123 void insert_string(size_t ndx, StringData value);
124 void insert_binary(size_t ndx, BinaryData value);
125 void insert_subtable(size_t ndx, const Table* value);
127 void erase(size_t row_ndx);
128 void move_last_over(size_t row_ndx);
131 /// Compare two mixed columns for equality.
132 bool compare_mixed(const MixedColumn&) const;
134 int compare_values(size_t row1, size_t row2) const noexcept override;
136 void discard_child_accessors() noexcept;
138 static ref_type create(Allocator&, size_t size = 0);
140 static size_t get_size_from_ref(ref_type root_ref, Allocator&) noexcept;
142 // Overriding method in ColumnBase
143 ref_type write(size_t, size_t, size_t, _impl::OutputStream&) const override;
145 void insert_rows(size_t, size_t, size_t, bool) override;
146 void erase_rows(size_t, size_t, size_t, bool) override;
147 void move_last_row_over(size_t, size_t, bool) override;
148 void swap_rows(size_t, size_t) override;
149 void clear(size_t, bool) override;
150 void update_from_parent(size_t) noexcept override;
151 void adj_acc_insert_rows(size_t, size_t) noexcept override;
152 void adj_acc_erase_row(size_t) noexcept override;
153 void adj_acc_move_over(size_t, size_t) noexcept override;
154 void adj_acc_swap_rows(size_t, size_t) noexcept override;
155 void adj_acc_move_row(size_t, size_t) noexcept override;
156 void adj_acc_clear_root_table() noexcept override;
157 void mark(int) noexcept override;
158 void refresh_accessor_tree(size_t, const Spec&) override;
160 void verify() const override;
161 void verify(const Table&, size_t) const override;
162 void to_dot(std::ostream&, StringData title) const override;
163 void do_dump_node_structure(std::ostream&, int) const override;
167 // NOTE: below numbers must be kept in sync with ColumnType
168 // Column types used in Mixed
172 // 3, used for STRING_ENUM in ColumnType
176 mixcol_OldDateTime = 7,
177 mixcol_Timestamp = 8,
179 mixcol_Double = 10, // Positive Double
180 mixcol_DoubleNeg = 11, // Negative Double
181 mixcol_IntNeg = 12 // Negative Integers
186 /// Stores the MixedColType of each value at the given index. For
187 /// values that uses all 64 bits, the type also encodes the sign
188 /// bit by having distinct types for positive negative values.
189 std::unique_ptr<IntegerColumn> m_types;
191 /// Stores the data for each entry. For a subtable, the stored
192 /// value is the ref of the subtable. For string, binary data,
193 /// the stored value is an index within `m_binary_data`. Likewise,
194 /// for timestamp, an index into `m_timestamp` is stored. For other
195 /// types the stored value is itself. Since we only have 63 bits
196 /// available for a non-ref value, the sign of numeric values is
197 /// encoded as part of the type in `m_types`.
198 std::unique_ptr<RefsColumn> m_data;
200 /// For string and binary data types, the bytes are stored here.
201 std::unique_ptr<BinaryColumn> m_binary_data;
203 /// Timestamps are stored here.
204 std::unique_ptr<TimestampColumn> m_timestamp_data;
206 void do_erase(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows);
207 void do_move_last_over(size_t row_ndx, size_t prior_num_rows);
208 void do_swap_rows(size_t, size_t);
209 void do_clear(size_t num_rows);
211 void create(Allocator&, ref_type, Table*, size_t column_ndx);
212 void ensure_binary_data_column();
213 void ensure_timestamp_column();
215 MixedColType clear_value(size_t ndx, MixedColType new_type); // Returns old type
216 void clear_value_and_discard_subtab_acc(size_t ndx, MixedColType new_type);
218 // Get/set/insert 64-bit values in m_data/m_types
219 int64_t get_value(size_t ndx) const noexcept;
220 void set_value(size_t ndx, int64_t value, MixedColType);
221 void set_int64(size_t ndx, int64_t value, MixedColType pos_type, MixedColType neg_type);
223 void insert_value(size_t row_ndx, int_fast64_t types_value, int_fast64_t data_value);
224 void insert_int(size_t ndx, int_fast64_t value, MixedColType type);
225 void insert_pos_neg(size_t ndx, int_fast64_t value, MixedColType pos_type, MixedColType neg_type);
227 void do_discard_child_accessors() noexcept override;
230 void do_verify(const Table*, size_t col_ndx) const;
232 void leaf_to_dot(MemRef, ArrayParent*, size_t, std::ostream&) const override;
236 inline StringData MixedColumn::get_index_data(size_t, StringIndex::StringConversionBuffer&) const noexcept
238 REALM_ASSERT(false && "Index not supported for MixedColumn yet.");
245 class MixedColumn::RefsColumn : public SubtableColumnBase {
247 RefsColumn(Allocator& alloc, ref_type ref, Table* table, size_t column_ndx);
248 ~RefsColumn() noexcept override;
250 using SubtableColumnBase::get_subtable_tableref;
252 void refresh_accessor_tree(size_t, const Spec&) override;
254 friend class MixedColumn;
262 #include <realm/column_mixed_tpl.hpp>
265 #endif // REALM_COLUMN_MIXED_HPP