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_TABLE_REF_HPP
20 #define REALM_TABLE_REF_HPP
25 #include <realm/util/bind_ptr.hpp>
33 /// A reference-counting "smart pointer" for referring to table
36 /// The purpose of this smart pointer is to keep the referenced table
37 /// accessor alive for as long as anybody is referring to it, however,
38 /// for stack allocated table accessors, the lifetime is necessarily
39 /// determined by scope (see below).
41 /// Please take note of the distinction between a "table" and a "table
42 /// accessor" here. A table accessor is an instance of `Table`,
43 /// and it may, or may not be attached to an
44 /// actual table at any specific point in time, but this state of
45 /// attachment of the accessor has nothing to do with the function of
46 /// the smart pointer. Also, in the rest of the documentation of this
47 /// class, whenever you see `Table::%foo`, you are supposed to read it
48 /// as, `Table::%foo`.
51 /// Table accessors are either created directly by an application via
52 /// a call to one of the public table constructors, or they are
53 /// created internally by the Realm library, such as when the
54 /// application calls Group::get_table(), Table::get_subtable(), or
57 /// Applications can safely assume that all table accessors, created
58 /// internally by the Realm library, have a lifetime that is managed
59 /// by reference counting. This means that the application can prolong
60 /// the lifetime of *such* table accessors indefinitely by holding on
61 /// to at least one smart pointer, but note that the guarantee of the
62 /// continued existence of the accessor, does not imply that the
63 /// accessor remains attached to the underlying table (see
64 /// Table::is_attached() for details). Accessors whose lifetime are
65 /// controlled by reference counting are destroyed exactly when the
66 /// reference count drops to zero.
68 /// When an application creates a new table accessor by a direct call
69 /// to one of the public constructors, the lifetime of that table
70 /// accessor is *not*, and cannot be managed by reference
71 /// counting. This is true regardless of the way the accessor is
72 /// created (i.e., regardless of whether it is an automatic variable
73 /// on the stack, or created on the heap using `new`). However, for
74 /// convenience, but with one important caveat, it is still possible
75 /// to use smart pointers to refer to such accessors. The caveat is
76 /// that no smart pointers are allowed to refer to the accessor at the
77 /// point in time when its destructor is called. It is entirely the
78 /// responsibility of the application to ensure that this requirement
79 /// is met. Failing to do so, will result in undefined
80 /// behavior. Finally, please note that an application is always free
81 /// to use Table::create() as an alternative to creating free-standing
82 /// top-level tables on the stack, and that this is indeed neccessary
83 /// when fully reference counted lifetimes are required.
85 /// So, at any time, and for any table accessor, an application can
86 /// call Table::get_table_ref() to obtain a smart pointer that refers
87 /// to that table, however, while that is always possible and safe, it
88 /// is not always possible to extend the lifetime of an accessor by
89 /// holding on to a smart pointer. The question of whether that is
90 /// possible, depends directly on the way the accessor was created.
93 /// Apart from keeping track of the number of references, these smart
94 /// pointers behaves almost exactly like regular pointers. In
95 /// particular, it is possible to dereference a TableRef and get a
96 /// `Table&` out of it, however, if you are not careful, this can
97 /// easily lead to dangling references:
101 /// Table& sub_1 = *(table.get_subtable(0,0));
102 /// sub_1.add_empty_row(); // Oops, sub_1 may be dangling!
106 /// Whether `sub_1` is actually dangling in the example above will
107 /// depend on whether other references to the same subtable accessor
108 /// already exist, but it is never wise to rely in this. Here is a
109 /// safe and proper alternative:
113 /// TableRef sub_2 = table.get_subtable(0,0);
114 /// sub_2.add_empty_row(); // Safe!
116 /// void do_something(Table&);
117 /// do_something(*(table.get_subtable(0,0))); // Also safe!
125 class BasicTableRef : util::bind_ptr<T> {
127 constexpr BasicTableRef() noexcept
130 ~BasicTableRef() noexcept
135 BasicTableRef(const BasicTableRef& r) noexcept
136 : util::bind_ptr<T>(r)
140 BasicTableRef(const BasicTableRef<U>& r) noexcept
141 : util::bind_ptr<T>(r)
146 BasicTableRef& operator=(const BasicTableRef&) noexcept;
148 BasicTableRef& operator=(const BasicTableRef<U>&) noexcept;
151 BasicTableRef(BasicTableRef&& r) noexcept
152 : util::bind_ptr<T>(std::move(r))
156 BasicTableRef(BasicTableRef<U>&& r) noexcept
157 : util::bind_ptr<T>(std::move(r))
162 BasicTableRef& operator=(BasicTableRef&&) noexcept;
164 BasicTableRef& operator=(BasicTableRef<U>&&) noexcept;
169 bool operator==(const BasicTableRef<U>&) const noexcept;
172 bool operator==(U*) const noexcept;
175 bool operator!=(const BasicTableRef<U>&) const noexcept;
178 bool operator!=(U*) const noexcept;
181 bool operator<(const BasicTableRef<U>&) const noexcept;
184 bool operator<(U*) const noexcept;
187 bool operator>(const BasicTableRef<U>&) const noexcept;
190 bool operator>(U*) const noexcept;
193 bool operator<=(const BasicTableRef<U>&) const noexcept;
196 bool operator<=(U*) const noexcept;
199 bool operator>=(const BasicTableRef<U>&) const noexcept;
202 bool operator>=(U*) const noexcept;
207 // Clang has a bug that causes it to effectively ignore the 'using' declaration.
208 T& operator*() const noexcept
210 return util::bind_ptr<T>::operator*();
213 using util::bind_ptr<T>::operator*;
215 using util::bind_ptr<T>::operator->;
217 using util::bind_ptr<T>::operator bool;
219 T* get() const noexcept
221 return util::bind_ptr<T>::get();
223 void reset() noexcept
225 util::bind_ptr<T>::reset();
227 void reset(T* t) noexcept
229 util::bind_ptr<T>::reset(t);
232 void swap(BasicTableRef& r) noexcept
234 this->util::bind_ptr<T>::swap(r);
236 friend void swap(BasicTableRef& a, BasicTableRef& b) noexcept
242 friend BasicTableRef<U> unchecked_cast(BasicTableRef<Table>) noexcept;
245 friend BasicTableRef<const U> unchecked_cast(BasicTableRef<const Table>) noexcept;
249 struct GetRowAccType {
253 typedef typename GetRowAccType<T>::type RowAccessor;
256 /// Same as 'table[i]' where 'table' is the referenced table.
257 RowAccessor operator[](size_t i) const noexcept
259 return (*this->get())[i];
262 explicit BasicTableRef(T* t) noexcept
263 : util::bind_ptr<T>(t)
267 T* release() { return util::bind_ptr<T>::release(); }
269 friend class SubtableColumnBase;
274 friend class BasicTableRef;
276 typedef typename util::bind_ptr<T>::casting_move_tag casting_move_tag;
278 BasicTableRef(BasicTableRef<U>* r, casting_move_tag) noexcept
279 : util::bind_ptr<T>(r, casting_move_tag())
285 typedef BasicTableRef<Table> TableRef;
286 typedef BasicTableRef<const Table> ConstTableRef;
289 template <class C, class T, class U>
290 inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const BasicTableRef<U>& p)
292 out << static_cast<const void*>(&*p);
297 inline BasicTableRef<T> unchecked_cast(TableRef t) noexcept
299 return BasicTableRef<T>(&t, typename BasicTableRef<T>::casting_move_tag());
303 inline BasicTableRef<const T> unchecked_cast(ConstTableRef t) noexcept
305 return BasicTableRef<const T>(&t, typename BasicTableRef<T>::casting_move_tag());
311 template <class T, class U>
312 bool operator==(T*, const BasicTableRef<U>&) noexcept;
313 template <class T, class U>
314 bool operator!=(T*, const BasicTableRef<U>&) noexcept;
315 template <class T, class U>
316 bool operator<(T*, const BasicTableRef<U>&) noexcept;
317 template <class T, class U>
318 bool operator>(T*, const BasicTableRef<U>&) noexcept;
319 template <class T, class U>
320 bool operator<=(T*, const BasicTableRef<U>&) noexcept;
321 template <class T, class U>
322 bool operator>=(T*, const BasicTableRef<U>&) noexcept;
329 inline BasicTableRef<T>& BasicTableRef<T>::operator=(const BasicTableRef& r) noexcept
331 this->util::bind_ptr<T>::operator=(r);
337 inline BasicTableRef<T>& BasicTableRef<T>::operator=(const BasicTableRef<U>& r) noexcept
339 this->util::bind_ptr<T>::operator=(r);
344 inline BasicTableRef<T>& BasicTableRef<T>::operator=(BasicTableRef&& r) noexcept
346 this->util::bind_ptr<T>::operator=(std::move(r));
352 inline BasicTableRef<T>& BasicTableRef<T>::operator=(BasicTableRef<U>&& r) noexcept
354 this->util::bind_ptr<T>::operator=(std::move(r));
360 bool BasicTableRef<T>::operator==(const BasicTableRef<U>& p) const noexcept
362 return get() == p.get();
367 bool BasicTableRef<T>::operator==(U* p) const noexcept
374 bool BasicTableRef<T>::operator!=(const BasicTableRef<U>& p) const noexcept
376 return get() != p.get();
381 bool BasicTableRef<T>::operator!=(U* p) const noexcept
388 bool BasicTableRef<T>::operator<(const BasicTableRef<U>& p) const noexcept
390 return get() < p.get();
395 bool BasicTableRef<T>::operator<(U* p) const noexcept
402 bool BasicTableRef<T>::operator>(const BasicTableRef<U>& p) const noexcept
404 return get() > p.get();
409 bool BasicTableRef<T>::operator>(U* p) const noexcept
416 bool BasicTableRef<T>::operator<=(const BasicTableRef<U>& p) const noexcept
418 return get() <= p.get();
423 bool BasicTableRef<T>::operator<=(U* p) const noexcept
430 bool BasicTableRef<T>::operator>=(const BasicTableRef<U>& p) const noexcept
432 return get() >= p.get();
437 bool BasicTableRef<T>::operator>=(U* p) const noexcept
442 template <class T, class U>
443 bool operator==(T* a, const BasicTableRef<U>& b) noexcept
448 template <class T, class U>
449 bool operator!=(T* a, const BasicTableRef<U>& b) noexcept
454 template <class T, class U>
455 bool operator<(T* a, const BasicTableRef<U>& b) noexcept
460 template <class T, class U>
461 bool operator>(T* a, const BasicTableRef<U>& b) noexcept
466 template <class T, class U>
467 bool operator<=(T* a, const BasicTableRef<U>& b) noexcept
472 template <class T, class U>
473 bool operator>=(T* a, const BasicTableRef<U>& b) noexcept
481 #endif // REALM_TABLE_REF_HPP