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_LANG_BIND_HELPER_HPP
20 #define REALM_LANG_BIND_HELPER_HPP
24 #include <realm/table.hpp>
25 #include <realm/table_view.hpp>
26 #include <realm/link_view.hpp>
27 #include <realm/group.hpp>
28 #include <realm/group_shared.hpp>
30 #include <realm/replication.hpp>
35 /// These functions are only to be used by language bindings to gain
36 /// access to certain memebers that are othewise private.
38 /// \note Applications are not supposed to call any of these functions
41 /// All of the get_subtable_ptr() functions bind the table accessor pointer
42 /// before it is returned (bind_table_ptr()). The caller is then responsible for
43 /// making the corresponding call to unbind_table_ptr().
44 class LangBindHelper {
46 /// Increment the reference counter of the specified table accessor. This is
47 /// done automatically by all of the functions in this class that return
48 /// table accessor pointers, but if the binding/application makes a copy of
49 /// such a pointer, and the copy needs to have an "independent life", then
50 /// the binding/application must bind that copy using this function.
51 static void bind_table_ptr(const Table*) noexcept;
53 /// Decrement the reference counter of the specified table accessor. The
54 /// binding/application must call this function for every bound table
55 /// accessor pointer object, when that pointer object ends its life.
56 static void unbind_table_ptr(const Table*) noexcept;
58 /// Construct a new freestanding table. The table accessor pointer is bound
59 /// by the callee before it is returned (bind_table_ptr()).
60 static Table* new_table();
62 /// Construct a new freestanding table as a copy of the specified one. The
63 /// table accessor pointer is bound by the callee before it is returned
64 /// (bind_table_ptr()).
65 static Table* copy_table(const Table&);
69 /// These functions are like their namesakes in Group, but these bypass the
70 /// construction of a smart-pointer object (TableRef). The table accessor
71 /// pointer is bound by the callee before it is returned (bind_table_ptr()).
73 static Table* get_table(Group&, size_t index_in_group);
74 static const Table* get_table(const Group&, size_t index_in_group);
76 static Table* get_table(Group&, StringData name);
77 static const Table* get_table(const Group&, StringData name);
79 static Table* add_table(Group&, StringData name, bool require_unique_name = true);
80 static Table* get_or_add_table(Group&, StringData name, bool* was_added = nullptr);
84 static Table* get_subtable_ptr(Table*, size_t column_ndx, size_t row_ndx);
85 static const Table* get_subtable_ptr(const Table*, size_t column_ndx, size_t row_ndx);
87 // FIXME: This is an 'oddball', do we really need it? If we do,
88 // please provide a comment that explains why it is needed!
89 static Table* get_subtable_ptr_during_insert(Table*, size_t col_ndx, size_t row_ndx);
91 static Table* get_subtable_ptr(TableView*, size_t column_ndx, size_t row_ndx);
92 static const Table* get_subtable_ptr(const TableView*, size_t column_ndx, size_t row_ndx);
93 static const Table* get_subtable_ptr(const ConstTableView*, size_t column_ndx, size_t row_ndx);
95 /// Calls parent.set_mixed_subtable(col_ndx, row_ndx, &source). Note
96 /// that the source table must have a descriptor that is
97 /// compatible with the target subtable column.
98 static void set_mixed_subtable(Table& parent, size_t col_ndx, size_t row_ndx, const Table& source);
100 static const LinkViewRef& get_linklist_ptr(Row&, size_t col_ndx);
101 static void unbind_linklist_ptr(const LinkViewRef&);
103 using VersionID = SharedGroup::VersionID;
105 /// \defgroup lang_bind_helper_transactions Continuous Transactions
107 /// advance_read() is equivalent to terminating the current read transaction
108 /// (SharedGroup::end_read()), and initiating a new one
109 /// (SharedGroup::begin_read()), except that all subordinate accessors
110 /// (Table, Row, Descriptor) will remain attached to the underlying objects,
111 /// unless those objects were removed in the target snapshot. By default,
112 /// the read transaction is advanced to the latest available snapshot, but
113 /// see SharedGroup::begin_read() for information about \a version.
115 /// promote_to_write() is equivalent to terminating the current read
116 /// transaction (SharedGroup::end_read()), and initiating a new write
117 /// transaction (SharedGroup::begin_write()), except that all subordinate
118 /// accessors (Table, Row, Descriptor) will remain attached to the
119 /// underlying objects, unless those objects were removed in the target
122 /// commit_and_continue_as_read() is equivalent to committing the current
123 /// write transaction (SharedGroup::commit()) and initiating a new read
124 /// transaction, which is bound to the snapshot produced by the write
125 /// transaction (SharedGroup::begin_read()), except that all subordinate
126 /// accessors (Table, Row, Descriptor) will remain attached to the
127 /// underlying objects. commit_and_continue_as_read() returns the version
128 /// produced by the committed transaction.
130 /// rollback_and_continue_as_read() is equivalent to rolling back the
131 /// current write transaction (SharedGroup::rollback()) and initiating a new
132 /// read transaction, which is bound to the snapshot, that the write
133 /// transaction was based on (SharedGroup::begin_read()), except that all
134 /// subordinate accessors (Table, Row, Descriptor) will remain attached to
135 /// the underlying objects, unless they were attached to object that were
136 /// added during the rolled back transaction.
138 /// If advance_read(), promote_to_write(), commit_and_continue_as_read(), or
139 /// rollback_and_continue_as_read() throws, the associated group accessor
140 /// and all of its subordinate accessors are left in a state that may not be
141 /// fully consistent. Only minimal consistency is guaranteed (see
142 /// AccessorConsistencyLevels). In this case, the application is required to
143 /// either destroy the SharedGroup object, forcing all associated accessors
144 /// to become detached, or take some other equivalent action that involves a
145 /// complete accessor detachment, such as terminating the transaction in
146 /// progress. Until then it is an error, and unsafe if the application
147 /// attempts to access any of those accessors.
149 /// The application must use SharedGroup::end_read() if it wants to
150 /// terminate the transaction after advance_read() or promote_to_write() has
151 /// thrown an exception. Likewise, it must use SharedGroup::rollback() if it
152 /// wants to terminate the transaction after commit_and_continue_as_read()
153 /// or rollback_and_continue_as_read() has thrown an exception.
155 /// \param observer An optional custom replication instruction handler. The
156 /// application may pass such a handler to observe the sequence of
157 /// modifications that advances (or rolls back) the state of the Realm.
159 /// \throw SharedGroup::BadVersion Thrown by advance_read() if the specified
160 /// version does not correspond to a bound (or tethered) snapshot.
164 static void advance_read(SharedGroup&, VersionID = VersionID());
166 static void advance_read(SharedGroup&, O&& observer, VersionID = VersionID());
167 static void promote_to_write(SharedGroup&);
169 static void promote_to_write(SharedGroup&, O&& observer);
170 static SharedGroup::version_type commit_and_continue_as_read(SharedGroup&);
171 static void rollback_and_continue_as_read(SharedGroup&);
173 static void rollback_and_continue_as_read(SharedGroup&, O&& observer);
177 /// Returns the name of the specified data type. Examples:
181 /// type_Int -> "int"
182 /// type_Bool -> "bool"
183 /// type_Float -> "float"
187 static const char* get_data_type_name(DataType) noexcept;
189 static SharedGroup::version_type get_version_of_latest_snapshot(SharedGroup&);
195 inline Table* LangBindHelper::new_table()
197 typedef _impl::TableFriend tf;
198 Allocator& alloc = Allocator::get_default();
199 size_t ref = tf::create_empty_table(alloc); // Throws
200 Table::Parent* parent = nullptr;
201 size_t ndx_in_parent = 0;
202 Table* table = tf::create_accessor(alloc, ref, parent, ndx_in_parent); // Throws
203 bind_table_ptr(table);
207 inline Table* LangBindHelper::copy_table(const Table& table)
209 typedef _impl::TableFriend tf;
210 Allocator& alloc = Allocator::get_default();
211 size_t ref = tf::clone(table, alloc); // Throws
212 Table::Parent* parent = nullptr;
213 size_t ndx_in_parent = 0;
214 Table* copy_of_table = tf::create_accessor(alloc, ref, parent, ndx_in_parent); // Throws
215 bind_table_ptr(copy_of_table);
216 return copy_of_table;
219 inline Table* LangBindHelper::get_subtable_ptr(Table* t, size_t column_ndx, size_t row_ndx)
221 TableRef subtab = t->get_subtable_tableref(column_ndx, row_ndx); // Throws
222 return subtab.release();
225 inline const Table* LangBindHelper::get_subtable_ptr(const Table* t, size_t column_ndx, size_t row_ndx)
227 ConstTableRef subtab = t->get_subtable_tableref(column_ndx, row_ndx); // Throws
228 return subtab.release();
231 inline Table* LangBindHelper::get_subtable_ptr(TableView* tv, size_t column_ndx, size_t row_ndx)
233 return get_subtable_ptr(&tv->get_parent(), column_ndx, tv->get_source_ndx(row_ndx));
236 inline const Table* LangBindHelper::get_subtable_ptr(const TableView* tv, size_t column_ndx, size_t row_ndx)
238 return get_subtable_ptr(&tv->get_parent(), column_ndx, tv->get_source_ndx(row_ndx));
241 inline const Table* LangBindHelper::get_subtable_ptr(const ConstTableView* tv, size_t column_ndx, size_t row_ndx)
243 return get_subtable_ptr(&tv->get_parent(), column_ndx, tv->get_source_ndx(row_ndx));
246 inline Table* LangBindHelper::get_table(Group& group, size_t index_in_group)
248 typedef _impl::GroupFriend gf;
249 Table* table = &gf::get_table(group, index_in_group); // Throws
254 inline const Table* LangBindHelper::get_table(const Group& group, size_t index_in_group)
256 typedef _impl::GroupFriend gf;
257 const Table* table = &gf::get_table(group, index_in_group); // Throws
262 inline Table* LangBindHelper::get_table(Group& group, StringData name)
264 typedef _impl::GroupFriend gf;
265 Table* table = gf::get_table(group, name); // Throws
271 inline const Table* LangBindHelper::get_table(const Group& group, StringData name)
273 typedef _impl::GroupFriend gf;
274 const Table* table = gf::get_table(group, name); // Throws
280 inline Table* LangBindHelper::add_table(Group& group, StringData name, bool require_unique_name)
282 typedef _impl::GroupFriend gf;
283 Table* table = &gf::add_table(group, name, require_unique_name); // Throws
288 inline Table* LangBindHelper::get_or_add_table(Group& group, StringData name, bool* was_added)
290 typedef _impl::GroupFriend gf;
291 Table* table = &gf::get_or_add_table(group, name, was_added); // Throws
296 inline void LangBindHelper::unbind_table_ptr(const Table* t) noexcept
301 inline void LangBindHelper::bind_table_ptr(const Table* t) noexcept
306 inline void LangBindHelper::set_mixed_subtable(Table& parent, size_t col_ndx, size_t row_ndx, const Table& source)
308 parent.set_mixed_subtable(col_ndx, row_ndx, &source);
311 inline const LinkViewRef& LangBindHelper::get_linklist_ptr(Row& row, size_t col_ndx)
313 LinkViewRef* link_view = new LinkViewRef(row.get_linklist(col_ndx));
317 inline void LangBindHelper::unbind_linklist_ptr(const LinkViewRef& link_view)
322 inline void LangBindHelper::advance_read(SharedGroup& sg, VersionID version)
324 using sgf = _impl::SharedGroupFriend;
325 _impl::NullInstructionObserver* observer = nullptr;
326 sgf::advance_read(sg, observer, version); // Throws
330 inline void LangBindHelper::advance_read(SharedGroup& sg, O&& observer, VersionID version)
332 using sgf = _impl::SharedGroupFriend;
333 sgf::advance_read(sg, &observer, version); // Throws
336 inline void LangBindHelper::promote_to_write(SharedGroup& sg)
338 using sgf = _impl::SharedGroupFriend;
339 _impl::NullInstructionObserver* observer = nullptr;
340 sgf::promote_to_write(sg, observer); // Throws
344 inline void LangBindHelper::promote_to_write(SharedGroup& sg, O&& observer)
346 using sgf = _impl::SharedGroupFriend;
347 sgf::promote_to_write(sg, &observer); // Throws
350 inline SharedGroup::version_type LangBindHelper::commit_and_continue_as_read(SharedGroup& sg)
352 using sgf = _impl::SharedGroupFriend;
353 return sgf::commit_and_continue_as_read(sg); // Throws
356 inline void LangBindHelper::rollback_and_continue_as_read(SharedGroup& sg)
358 using sgf = _impl::SharedGroupFriend;
359 _impl::NullInstructionObserver* observer = nullptr;
360 sgf::rollback_and_continue_as_read(sg, observer); // Throws
364 inline void LangBindHelper::rollback_and_continue_as_read(SharedGroup& sg, O&& observer)
366 using sgf = _impl::SharedGroupFriend;
367 sgf::rollback_and_continue_as_read(sg, &observer); // Throws
370 inline SharedGroup::version_type LangBindHelper::get_version_of_latest_snapshot(SharedGroup& sg)
372 using sgf = _impl::SharedGroupFriend;
373 return sgf::get_version_of_latest_snapshot(sg); // Throws
378 #endif // REALM_LANG_BIND_HELPER_HPP