added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / lang_bind_helper.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_LANG_BIND_HELPER_HPP
20 #define REALM_LANG_BIND_HELPER_HPP
21
22 #include <cstddef>
23
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>
29
30 #include <realm/replication.hpp>
31
32 namespace realm {
33
34
35 /// These functions are only to be used by language bindings to gain
36 /// access to certain memebers that are othewise private.
37 ///
38 /// \note Applications are not supposed to call any of these functions
39 /// directly.
40 ///
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 {
45 public:
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;
52
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;
57
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();
61
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&);
66
67     //@{
68
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()).
72
73     static Table* get_table(Group&, size_t index_in_group);
74     static const Table* get_table(const Group&, size_t index_in_group);
75
76     static Table* get_table(Group&, StringData name);
77     static const Table* get_table(const Group&, StringData name);
78
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);
81
82     //@}
83
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);
86
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);
90
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);
94
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);
99
100     static const LinkViewRef& get_linklist_ptr(Row&, size_t col_ndx);
101     static void unbind_linklist_ptr(const LinkViewRef&);
102
103     using VersionID = SharedGroup::VersionID;
104
105     /// \defgroup lang_bind_helper_transactions Continuous Transactions
106     ///
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.
114     ///
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
120     /// snapshot.
121     ///
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.
129     ///
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.
137     ///
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.
148     ///
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.
154     ///
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.
158     ///
159     /// \throw SharedGroup::BadVersion Thrown by advance_read() if the specified
160     /// version does not correspond to a bound (or tethered) snapshot.
161     ///
162     //@{
163
164     static void advance_read(SharedGroup&, VersionID = VersionID());
165     template <class O>
166     static void advance_read(SharedGroup&, O&& observer, VersionID = VersionID());
167     static void promote_to_write(SharedGroup&);
168     template <class O>
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&);
172     template <class O>
173     static void rollback_and_continue_as_read(SharedGroup&, O&& observer);
174
175     //@}
176
177     /// Returns the name of the specified data type. Examples:
178     ///
179     /// <pre>
180     ///
181     ///   type_Int          ->  "int"
182     ///   type_Bool         ->  "bool"
183     ///   type_Float        ->  "float"
184     ///   ...
185     ///
186     /// </pre>
187     static const char* get_data_type_name(DataType) noexcept;
188
189     static SharedGroup::version_type get_version_of_latest_snapshot(SharedGroup&);
190 };
191
192
193 // Implementation:
194
195 inline Table* LangBindHelper::new_table()
196 {
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);
204     return table;
205 }
206
207 inline Table* LangBindHelper::copy_table(const Table& table)
208 {
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;
217 }
218
219 inline Table* LangBindHelper::get_subtable_ptr(Table* t, size_t column_ndx, size_t row_ndx)
220 {
221     TableRef subtab = t->get_subtable_tableref(column_ndx, row_ndx); // Throws
222     return subtab.release();
223 }
224
225 inline const Table* LangBindHelper::get_subtable_ptr(const Table* t, size_t column_ndx, size_t row_ndx)
226 {
227     ConstTableRef subtab = t->get_subtable_tableref(column_ndx, row_ndx); // Throws
228     return subtab.release();
229 }
230
231 inline Table* LangBindHelper::get_subtable_ptr(TableView* tv, size_t column_ndx, size_t row_ndx)
232 {
233     return get_subtable_ptr(&tv->get_parent(), column_ndx, tv->get_source_ndx(row_ndx));
234 }
235
236 inline const Table* LangBindHelper::get_subtable_ptr(const TableView* tv, size_t column_ndx, size_t row_ndx)
237 {
238     return get_subtable_ptr(&tv->get_parent(), column_ndx, tv->get_source_ndx(row_ndx));
239 }
240
241 inline const Table* LangBindHelper::get_subtable_ptr(const ConstTableView* tv, size_t column_ndx, size_t row_ndx)
242 {
243     return get_subtable_ptr(&tv->get_parent(), column_ndx, tv->get_source_ndx(row_ndx));
244 }
245
246 inline Table* LangBindHelper::get_table(Group& group, size_t index_in_group)
247 {
248     typedef _impl::GroupFriend gf;
249     Table* table = &gf::get_table(group, index_in_group); // Throws
250     table->bind_ptr();
251     return table;
252 }
253
254 inline const Table* LangBindHelper::get_table(const Group& group, size_t index_in_group)
255 {
256     typedef _impl::GroupFriend gf;
257     const Table* table = &gf::get_table(group, index_in_group); // Throws
258     table->bind_ptr();
259     return table;
260 }
261
262 inline Table* LangBindHelper::get_table(Group& group, StringData name)
263 {
264     typedef _impl::GroupFriend gf;
265     Table* table = gf::get_table(group, name); // Throws
266     if (table)
267         table->bind_ptr();
268     return table;
269 }
270
271 inline const Table* LangBindHelper::get_table(const Group& group, StringData name)
272 {
273     typedef _impl::GroupFriend gf;
274     const Table* table = gf::get_table(group, name); // Throws
275     if (table)
276         table->bind_ptr();
277     return table;
278 }
279
280 inline Table* LangBindHelper::add_table(Group& group, StringData name, bool require_unique_name)
281 {
282     typedef _impl::GroupFriend gf;
283     Table* table = &gf::add_table(group, name, require_unique_name); // Throws
284     table->bind_ptr();
285     return table;
286 }
287
288 inline Table* LangBindHelper::get_or_add_table(Group& group, StringData name, bool* was_added)
289 {
290     typedef _impl::GroupFriend gf;
291     Table* table = &gf::get_or_add_table(group, name, was_added); // Throws
292     table->bind_ptr();
293     return table;
294 }
295
296 inline void LangBindHelper::unbind_table_ptr(const Table* t) noexcept
297 {
298     t->unbind_ptr();
299 }
300
301 inline void LangBindHelper::bind_table_ptr(const Table* t) noexcept
302 {
303     t->bind_ptr();
304 }
305
306 inline void LangBindHelper::set_mixed_subtable(Table& parent, size_t col_ndx, size_t row_ndx, const Table& source)
307 {
308     parent.set_mixed_subtable(col_ndx, row_ndx, &source);
309 }
310
311 inline const LinkViewRef& LangBindHelper::get_linklist_ptr(Row& row, size_t col_ndx)
312 {
313     LinkViewRef* link_view = new LinkViewRef(row.get_linklist(col_ndx));
314     return *link_view;
315 }
316
317 inline void LangBindHelper::unbind_linklist_ptr(const LinkViewRef& link_view)
318 {
319     delete (&link_view);
320 }
321
322 inline void LangBindHelper::advance_read(SharedGroup& sg, VersionID version)
323 {
324     using sgf = _impl::SharedGroupFriend;
325     _impl::NullInstructionObserver* observer = nullptr;
326     sgf::advance_read(sg, observer, version); // Throws
327 }
328
329 template <class O>
330 inline void LangBindHelper::advance_read(SharedGroup& sg, O&& observer, VersionID version)
331 {
332     using sgf = _impl::SharedGroupFriend;
333     sgf::advance_read(sg, &observer, version); // Throws
334 }
335
336 inline void LangBindHelper::promote_to_write(SharedGroup& sg)
337 {
338     using sgf = _impl::SharedGroupFriend;
339     _impl::NullInstructionObserver* observer = nullptr;
340     sgf::promote_to_write(sg, observer); // Throws
341 }
342
343 template <class O>
344 inline void LangBindHelper::promote_to_write(SharedGroup& sg, O&& observer)
345 {
346     using sgf = _impl::SharedGroupFriend;
347     sgf::promote_to_write(sg, &observer); // Throws
348 }
349
350 inline SharedGroup::version_type LangBindHelper::commit_and_continue_as_read(SharedGroup& sg)
351 {
352     using sgf = _impl::SharedGroupFriend;
353     return sgf::commit_and_continue_as_read(sg); // Throws
354 }
355
356 inline void LangBindHelper::rollback_and_continue_as_read(SharedGroup& sg)
357 {
358     using sgf = _impl::SharedGroupFriend;
359     _impl::NullInstructionObserver* observer = nullptr;
360     sgf::rollback_and_continue_as_read(sg, observer); // Throws
361 }
362
363 template <class O>
364 inline void LangBindHelper::rollback_and_continue_as_read(SharedGroup& sg, O&& observer)
365 {
366     using sgf = _impl::SharedGroupFriend;
367     sgf::rollback_and_continue_as_read(sg, &observer); // Throws
368 }
369
370 inline SharedGroup::version_type LangBindHelper::get_version_of_latest_snapshot(SharedGroup& sg)
371 {
372     using sgf = _impl::SharedGroupFriend;
373     return sgf::get_version_of_latest_snapshot(sg); // Throws
374 }
375
376 } // namespace realm
377
378 #endif // REALM_LANG_BIND_HELPER_HPP