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_VIEW_HPP
20 #define REALM_TABLE_VIEW_HPP
22 #include <realm/column.hpp>
23 #include <realm/link_view.hpp>
24 #include <realm/table.hpp>
25 #include <realm/util/features.h>
26 #include <realm/views.hpp>
30 // Views, tables and synchronization between them:
32 // Views are built through queries against either tables or another view.
33 // Views may be restricted to only hold entries provided by another view.
34 // this other view is called the "restricting view".
35 // Views may be sorted in ascending or descending order of values in one ore more columns.
37 // Views remember the query from which it was originally built.
38 // Views remember the table from which it was originally built.
39 // Views remember a restricting view if one was used when it was originally built.
40 // Views remember the sorting criteria (columns and direction)
42 // A view may be operated in one of two distinct modes: *reflective* and *imperative*.
43 // Sometimes the term "reactive" is used instead of "reflective" with the same meaning.
46 // - A reflective view *always* *reflect* the result of running the query.
47 // If the underlying tables or tableviews change, the reflective view changes as well.
48 // A reflective view may need to rerun the query it was generated from, a potentially
49 // costly operation which happens on demand.
50 // - It does not matter whether changes are explicitly done within the transaction, or
51 // occur implicitly as part of advance_read() or promote_to_write().
54 // - An imperative view only *initially* holds the result of the query. An imperative
55 // view *never* reruns the query. To force the view to match it's query (by rerunning it),
56 // the view must be operated in reflective mode.
57 // An imperative view can be modified explicitly. References can be added, removed or
60 // - In imperative mode, the references in the view tracks movement of the referenced data:
61 // If you delete an entry which is referenced from a view, said reference is detached,
63 // - It does not matter whether the delete is done in-line (as part of the current transaction),
64 // or if it is done implicitly as part of advance_read() or promote_to_write().
66 // The choice between reflective and imperative views might eventually be represented by a
67 // switch on the tableview, but isn't yet. For now, clients (bindings) must call sync_if_needed()
68 // to get reflective behavior.
73 // The first use case (and primary motivator behind the reflective view) is to just track
74 // and present the state of the database. In this case, the view is operated in reflective
75 // mode, it is not modified within the transaction, and it is not used to modify data in
76 // other parts of the database.
79 // The second use case is "handover." The implicit rerun of the query in our first use case
80 // may be too costly to be acceptable on the main thread. Instead you want to run the query
81 // on a worker thread, but display it on the main thread. To achieve this, you need two
82 // SharedGroups locked on to the same version of the database. If you have that, you can
83 // *handover* a view from one thread/SharedGroup to the other.
85 // Handover is a two-step procedure. First, the accessors are *exported* from one SharedGroup,
86 // called the sourcing group, then it is *imported* into another SharedGroup, called the
87 // receiving group. The thread associated with the sourcing SharedGroup will be
88 // responsible for the export operation, while the thread associated with the receiving
89 // SharedGroup will do the import operation.
91 // 3. Iterating a view and changing data
92 // The third use case (and a motivator behind the imperative view) is when you want
93 // to make changes to the database in accordance with a query result. Imagine you want to
94 // find all employees with a salary below a limit and raise their salaries to the limit (pseudocode):
96 // promote_to_write();
97 // view = table.where().less_than(salary_column,limit).find_all();
98 // for (size_t i = 0; i < view.size(); ++i) {
99 // view.set_int(salary_column, i, limit);
100 // // add this to get reflective mode: view.sync_if_needed();
102 // commit_and_continue_as_read();
104 // This is idiomatic imperative code and it works if the view is operated in imperative mode.
106 // If the view is operated in reflective mode, the behaviour surprises most people: When the
107 // first salary is changed, the entry no longer fullfills the query, so it is dropped from the
108 // view implicitly. view[0] is removed, view[1] moves to view[0] and so forth. But the next
109 // loop iteration has i=1 and refers to view[1], thus skipping view[0]. The end result is that
110 // every other employee get a raise, while the others don't.
112 // 4. Iterating intermixed with implicit updates
113 // This leads us to use case 4, which is similar to use case 3, but uses promote_to_write()
114 // intermixed with iterating a view. This is actually quite important to some, who do not want
115 // to end up with a large write transaction.
117 // view = table.where().less_than(salary_column,limit).find_all();
118 // for (size_t i = 0; i < view.size(); ++i) {
119 // promote_to_write();
120 // view.set_int(salary_column, i, limit);
121 // commit_and_continue_as_write();
124 // Anything can happen at the call to promote_to_write(). The key question then becomes: how
125 // do we support a safe way of realising the original goal (raising salaries) ?
127 // using the imperative operating mode:
129 // view = table.where().less_than(salary_column,limit).find_all();
130 // for (size_t i = 0; i < view.size(); ++i) {
131 // promote_to_write();
132 // // add r.sync_if_needed(); to get reflective mode
133 // if (r.is_row_attached(i)) {
135 // r.set_int(salary_column, limit);
137 // commit_and_continue_as_write();
140 // This is safe, and we just aim for providing low level safety: is_row_attached() can tell
141 // if the reference is valid, and the references in the view continue to point to the
142 // same object at all times, also following implicit updates. The rest is up to the
143 // application logic.
145 // It is important to see, that there is no guarantee that all relevant employees get
146 // their raise in cases whith concurrent updates. At every call to promote_to_write() new
147 // employees may be added to the underlying table, but as the view is in imperative mode,
148 // these new employees are not added to the view. Also at promote_to_write() an existing
149 // employee could recieve a (different, larger) raise which would then be overwritten and lost.
150 // However, these are problems that you should expect, since the activity is spread over multiple
154 /// Common base class for TableView and ConstTableView.
155 class TableViewBase : public RowIndexes {
157 // - not in use / implemented yet: ... explicit calls to sync_if_needed() must be used
158 // to get 'reflective' mode.
159 // enum mode { mode_Reflective, mode_Imperative };
160 // void set_operating_mode(mode);
161 // mode get_operating_mode();
162 bool is_empty() const noexcept;
164 // Tells if the table that this TableView points at still exists or has been deleted.
165 bool is_attached() const noexcept;
167 bool is_row_attached(size_t row_ndx) const noexcept;
168 size_t size() const noexcept;
169 size_t num_attached_rows() const noexcept;
171 // Get the query used to create this TableView
172 // The query will have a null source table if this tv was not created from
174 const Query& get_query() const noexcept;
176 // Column information
177 const ColumnBase& get_column_base(size_t index) const;
179 size_t get_column_count() const noexcept;
180 StringData get_column_name(size_t column_ndx) const noexcept;
181 size_t get_column_index(StringData name) const;
182 DataType get_column_type(size_t column_ndx) const noexcept;
185 int64_t get_int(size_t column_ndx, size_t row_ndx) const noexcept;
186 bool get_bool(size_t column_ndx, size_t row_ndx) const noexcept;
187 OldDateTime get_olddatetime(size_t column_ndx, size_t row_ndx) const noexcept;
188 Timestamp get_timestamp(size_t column_ndx, size_t row_ndx) const noexcept;
189 float get_float(size_t column_ndx, size_t row_ndx) const noexcept;
190 double get_double(size_t column_ndx, size_t row_ndx) const noexcept;
191 StringData get_string(size_t column_ndx, size_t row_ndx) const noexcept;
192 BinaryData get_binary(size_t column_ndx, size_t row_ndx) const noexcept;
193 Mixed get_mixed(size_t column_ndx, size_t row_ndx) const noexcept;
194 DataType get_mixed_type(size_t column_ndx, size_t row_ndx) const noexcept;
195 size_t get_link(size_t column_ndx, size_t row_ndx) const noexcept;
198 bool is_null_link(size_t column_ndx, size_t row_ndx) const noexcept;
201 size_t get_subtable_size(size_t column_ndx, size_t row_ndx) const noexcept;
205 size_t find_first(size_t column_ndx, T value) const;
207 size_t find_first_int(size_t column_ndx, int64_t value) const;
208 size_t find_first_bool(size_t column_ndx, bool value) const;
209 size_t find_first_olddatetime(size_t column_ndx, OldDateTime value) const;
210 size_t find_first_float(size_t column_ndx, float value) const;
211 size_t find_first_double(size_t column_ndx, double value) const;
212 size_t find_first_string(size_t column_ndx, StringData value) const;
213 size_t find_first_binary(size_t column_ndx, BinaryData value) const;
214 size_t find_first_timestamp(size_t column_ndx, Timestamp value) const;
216 // Aggregate functions. count_target is ignored by all <int
217 // function> except Count. Hack because of bug in optional
218 // arguments in clang and vs2010 (fixed in 2012)
219 template <int function, typename T, typename R, class ColType>
220 R aggregate(R (ColType::*aggregateMethod)(size_t, size_t, size_t, size_t*) const, size_t column_ndx,
221 T count_target, size_t* return_ndx = nullptr) const;
223 int64_t sum_int(size_t column_ndx) const;
224 int64_t maximum_int(size_t column_ndx, size_t* return_ndx = nullptr) const;
225 int64_t minimum_int(size_t column_ndx, size_t* return_ndx = nullptr) const;
226 double average_int(size_t column_ndx, size_t* value_count = nullptr) const;
227 size_t count_int(size_t column_ndx, int64_t target) const;
229 double sum_float(size_t column_ndx) const;
230 float maximum_float(size_t column_ndx, size_t* return_ndx = nullptr) const;
231 float minimum_float(size_t column_ndx, size_t* return_ndx = nullptr) const;
232 double average_float(size_t column_ndx, size_t* value_count = nullptr) const;
233 size_t count_float(size_t column_ndx, float target) const;
235 double sum_double(size_t column_ndx) const;
236 double maximum_double(size_t column_ndx, size_t* return_ndx = nullptr) const;
237 double minimum_double(size_t column_ndx, size_t* return_ndx = nullptr) const;
238 double average_double(size_t column_ndx, size_t* value_count = nullptr) const;
239 size_t count_double(size_t column_ndx, double target) const;
241 OldDateTime maximum_olddatetime(size_t column_ndx, size_t* return_ndx = nullptr) const;
242 OldDateTime minimum_olddatetime(size_t column_ndx, size_t* return_ndx = nullptr) const;
244 Timestamp minimum_timestamp(size_t column_ndx, size_t* return_ndx = nullptr) const;
245 Timestamp maximum_timestamp(size_t column_ndx, size_t* return_ndx = nullptr) const;
246 size_t count_timestamp(size_t column_ndx, Timestamp target) const;
248 // Simple pivot aggregate method. Experimental! Please do not
249 // document method publicly.
250 void aggregate(size_t group_by_column, size_t aggr_column, Table::AggrType op, Table& result) const;
252 // Get row index in the source table this view is "looking" at.
253 size_t get_source_ndx(size_t row_ndx) const noexcept;
255 /// Search this view for the specified source table row (specified by its
256 /// index in the source table). If found, the index of that row within this
257 /// view is returned, otherwise `realm::not_found` is returned.
258 size_t find_by_source_ndx(size_t source_ndx) const noexcept;
261 void to_json(std::ostream&) const;
262 void to_string(std::ostream&, size_t limit = 500) const;
263 void row_to_string(size_t row_ndx, std::ostream&) const;
265 // Determine if the view is 'in sync' with the underlying table
266 // as well as other views used to generate the view. Note that updates
267 // through views maintains synchronization between view and table.
268 // It doesnt by itself maintain other views as well. So if a view
269 // is generated from another view (not a table), updates may cause
270 // that view to be outdated, AND as the generated view depends upon
271 // it, it too will become outdated.
272 bool is_in_sync() const;
274 // Tells if this TableView depends on a LinkList or row that has been deleted.
275 bool depends_on_deleted_object() const;
277 // Synchronize a view to match a table or tableview from which it
278 // has been derived. Synchronization is achieved by rerunning the
279 // query used to generate the view. If derived from another view, that
280 // view will be synchronized as well.
282 // "live" or "reactive" views are implemented by calling sync_if_needed
283 // before any of the other access-methods whenever the view may have become
286 // This will make the TableView empty and in sync with the highest possible table version
287 // if the TableView depends on an object (LinkView or row) that has been deleted.
288 uint_fast64_t sync_if_needed() const;
290 // Sort m_row_indexes according to one column
291 void sort(size_t column, bool ascending = true);
293 // Sort m_row_indexes according to multiple columns
294 void sort(SortDescriptor order);
296 // Remove rows that are duplicated with respect to the column set passed as argument.
297 // distinct() will preserve the original order of the row pointers, also if the order is a result of sort()
298 // If two rows are indentical (for the given set of distinct-columns), then the last row is removed.
299 // You can call sync_if_needed() to update the distinct view, just like you can for a sorted view.
300 // Each time you call distinct() it will compound on the previous calls
301 void distinct(size_t column);
302 void distinct(DistinctDescriptor columns);
304 // Replace the order of sort and distinct operations, bypassing manually
305 // calling sort and distinct. This is a convenience method for bindings.
306 void apply_descriptor_ordering(DescriptorOrdering new_ordering);
308 // Returns whether the rows are guaranteed to be in table order.
309 // This is true only of unsorted TableViews created from either:
310 // - Table::find_all()
311 // - Query::find_all() when the query is not restricted to a view.
312 bool is_in_table_order() const;
314 virtual ~TableViewBase() noexcept;
316 virtual std::unique_ptr<TableViewBase> clone() const = 0;
319 // This TableView can be "born" from 4 different sources:
321 // - Query::find_all()
322 // - Table::get_distinct_view()
323 // - Table::get_backlink_view()
324 // Return the version of the source it was created from.
325 uint64_t outside_version() const;
329 // Null if, and only if, the view is detached.
330 mutable TableRef m_table;
332 // The link column that this view contain backlinks for.
333 const BacklinkColumn* m_linked_column = nullptr;
334 // The target row that rows in this view link to.
335 ConstRow m_linked_row;
337 // If this TableView was created from a LinkView, then this reference points to it. Otherwise it's 0
338 mutable ConstLinkViewRef m_linkview_source;
340 // m_distinct_column_source != npos if this view was created from distinct values in a column of m_table.
341 size_t m_distinct_column_source = npos;
343 // Stores the ordering criteria of applied sort and distinct operations.
344 DescriptorOrdering m_descriptor_ordering;
346 // A valid query holds a reference to its table which must match our m_table.
347 // hence we can use a query with a null table reference to indicate that the view
348 // was NOT generated by a query, but follows a table directly.
350 // parameters for findall, needed to rerun the query
355 mutable util::Optional<uint_fast64_t> m_last_seen_version;
357 size_t m_num_detached_refs = 0;
358 /// Construct null view (no memory allocated).
361 /// Construct empty view, ready for addition of row indices.
362 TableViewBase(Table* parent);
363 TableViewBase(Table* parent, Query& query, size_t start, size_t end, size_t limit);
364 TableViewBase(Table* parent, size_t column, BasicRowExpr<const Table> row);
365 TableViewBase(Table* parent, ConstLinkViewRef link_view);
367 enum DistinctViewTag { DistinctView };
368 TableViewBase(DistinctViewTag, Table* parent, size_t column_ndx);
370 /// Copy constructor.
371 TableViewBase(const TableViewBase&);
373 /// Move constructor.
374 TableViewBase(TableViewBase&&) noexcept;
376 TableViewBase& operator=(const TableViewBase&);
377 TableViewBase& operator=(TableViewBase&&) noexcept;
379 template <class R, class V>
380 static R find_all_integer(V*, size_t, int64_t);
382 template <class R, class V>
383 static R find_all_float(V*, size_t, float);
385 template <class R, class V>
386 static R find_all_double(V*, size_t, double);
388 template <class R, class V>
389 static R find_all_string(V*, size_t, StringData);
391 using HandoverPatch = TableViewHandoverPatch;
393 // handover machinery entry points based on dynamic type. These methods:
394 // a) forward their calls to the static type entry points.
395 // b) new/delete patch data structures.
396 virtual std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
397 ConstSourcePayload mode) const = 0;
399 virtual std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
400 MutableSourcePayload mode) = 0;
402 void apply_and_consume_patch(std::unique_ptr<HandoverPatch>& patch, Group& group)
404 apply_patch(*patch, group);
407 // handover machinery entry points based on static type
408 void apply_patch(HandoverPatch& patch, Group& group);
409 TableViewBase(const TableViewBase& source, HandoverPatch& patch, ConstSourcePayload mode);
410 TableViewBase(TableViewBase& source, HandoverPatch& patch, MutableSourcePayload mode);
413 void allocate_row_indexes();
414 void detach() const noexcept; // may have to remove const
415 size_t find_first_integer(size_t column_ndx, int64_t value) const;
416 template <class oper>
417 Timestamp minmax_timestamp(size_t column_ndx, size_t* return_ndx) const;
421 friend class SharedGroup;
423 // Called by table to adjust any row references:
424 void adj_row_acc_insert_rows(size_t row_ndx, size_t num_rows) noexcept;
425 void adj_row_acc_erase_row(size_t row_ndx) noexcept;
426 void adj_row_acc_move_over(size_t from_row_ndx, size_t to_row_ndx) noexcept;
427 void adj_row_acc_swap_rows(size_t row_ndx_1, size_t row_ndx_2) noexcept;
428 void adj_row_acc_move_row(size_t from_row_ndx, size_t to_row_ndx) noexcept;
429 void adj_row_acc_clear() noexcept;
433 inline void TableViewBase::detach() const noexcept // may have to remove const
435 m_table = TableRef();
439 class ConstTableView;
442 enum class RemoveMode { ordered, unordered };
445 /// A TableView gives read and write access to the parent table.
447 /// A 'const TableView' cannot be changed (e.g. sorted), nor can the
448 /// parent table be modified through it.
450 /// A TableView is both copyable and movable.
451 class TableView : public TableViewBase {
453 using TableViewBase::TableViewBase;
455 TableView() = default;
458 typedef BasicRowExpr<Table> RowExpr;
459 typedef BasicRowExpr<const Table> ConstRowExpr;
460 RowExpr get(size_t row_ndx) noexcept;
461 ConstRowExpr get(size_t row_ndx) const noexcept;
462 RowExpr front() noexcept;
463 ConstRowExpr front() const noexcept;
464 RowExpr back() noexcept;
465 ConstRowExpr back() const noexcept;
466 RowExpr operator[](size_t row_ndx) noexcept;
467 ConstRowExpr operator[](size_t row_ndx) const noexcept;
470 void set_int(size_t column_ndx, size_t row_ndx, int64_t value);
471 void set_bool(size_t column_ndx, size_t row_ndx, bool value);
472 void set_olddatetime(size_t column_ndx, size_t row_ndx, OldDateTime value);
473 void set_timestamp(size_t column_ndx, size_t row_ndx, Timestamp value);
475 void set_enum(size_t column_ndx, size_t row_ndx, E value);
476 void set_float(size_t column_ndx, size_t row_ndx, float value);
477 void set_double(size_t column_ndx, size_t row_ndx, double value);
478 void set_string(size_t column_ndx, size_t row_ndx, StringData value);
479 void set_binary(size_t column_ndx, size_t row_ndx, BinaryData value);
480 void set_mixed(size_t column_ndx, size_t row_ndx, Mixed value);
481 void set_subtable(size_t column_ndx, size_t row_ndx, const Table* table);
482 void set_link(size_t column_ndx, size_t row_ndx, size_t target_row_ndx);
485 TableRef get_subtable(size_t column_ndx, size_t row_ndx);
486 ConstTableRef get_subtable(size_t column_ndx, size_t row_ndx) const;
487 void clear_subtable(size_t column_ndx, size_t row_ndx);
490 TableRef get_link_target(size_t column_ndx) noexcept;
491 ConstTableRef get_link_target(size_t column_ndx) const noexcept;
492 void nullify_link(size_t column_ndx, size_t row_ndx);
494 /// \defgroup table_view_removes
496 /// \brief Remove the specified row (or rows) from the underlying table.
498 /// remove() removes the specified row from the underlying table,
499 /// remove_last() removes the last row in the table view from the underlying
500 /// table, and clear removes all the rows in the table view from the
501 /// underlying table.
503 /// When rows are removed from the underlying table, they will by necessity
504 /// also be removed from the table view.
506 /// The order of the remaining rows in the the table view will be maintained
507 /// regardless of the value passed for \a underlying_mode.
509 /// \param row_ndx The index within this table view of the row to be
512 /// \param underlying_mode If set to RemoveMode::ordered (the default), the
513 /// rows will be removed from the underlying table in a way that maintains
514 /// the order of the remaining rows in the underlying table. If set to
515 /// RemoveMode::unordered, the order of the remaining rows in the underlying
516 /// table will not in general be maintaind, but the operation will generally
517 /// be much faster. In any case, the order of remaining rows in the table
518 /// view will not be affected.
519 void remove(size_t row_ndx, RemoveMode underlying_mode = RemoveMode::ordered);
520 void remove_last(RemoveMode underlying_mode = RemoveMode::ordered);
521 void clear(RemoveMode underlying_mode = RemoveMode::ordered);
524 // Searching (Int and String)
525 TableView find_all_int(size_t column_ndx, int64_t value);
526 ConstTableView find_all_int(size_t column_ndx, int64_t value) const;
527 TableView find_all_bool(size_t column_ndx, bool value);
528 ConstTableView find_all_bool(size_t column_ndx, bool value) const;
529 TableView find_all_olddatetime(size_t column_ndx, OldDateTime value);
530 ConstTableView find_all_olddatetime(size_t column_ndx, OldDateTime value) const;
531 TableView find_all_float(size_t column_ndx, float value);
532 ConstTableView find_all_float(size_t column_ndx, float value) const;
533 TableView find_all_double(size_t column_ndx, double value);
534 ConstTableView find_all_double(size_t column_ndx, double value) const;
535 TableView find_all_string(size_t column_ndx, StringData value);
536 ConstTableView find_all_string(size_t column_ndx, StringData value) const;
537 // FIXME: Need: TableView find_all_binary(size_t column_ndx, BinaryData value);
538 // FIXME: Need: ConstTableView find_all_binary(size_t column_ndx, BinaryData value) const;
540 Table& get_parent() noexcept;
541 const Table& get_parent() const noexcept;
543 std::unique_ptr<TableViewBase> clone() const override
545 return std::unique_ptr<TableViewBase>(new TableView(*this));
548 std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
549 ConstSourcePayload mode) const override
551 patch.reset(new HandoverPatch);
552 std::unique_ptr<TableViewBase> retval(new TableView(*this, *patch, mode));
556 std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
557 MutableSourcePayload mode) override
559 patch.reset(new HandoverPatch);
560 std::unique_ptr<TableViewBase> retval(new TableView(*this, *patch, mode));
565 TableView(Table& parent);
566 TableView(Table& parent, Query& query, size_t start, size_t end, size_t limit);
567 TableView(Table& parent, ConstLinkViewRef);
569 TableView(DistinctViewTag, Table& parent, size_t column_ndx);
571 TableView find_all_integer(size_t column_ndx, int64_t value);
572 ConstTableView find_all_integer(size_t column_ndx, int64_t value) const;
574 friend class ConstTableView;
577 friend class TableViewBase;
578 friend class LinkView;
582 /// A ConstTableView gives read access to the parent table, but no
583 /// write access. The view itself, though, can be changed, for
584 /// example, it can be sorted.
586 /// Note that methods are declared 'const' if, and only if they leave
587 /// the view unmodified, and this is irrespective of whether they
588 /// modify the parent table.
590 /// A ConstTableView has both copy and move semantics. See TableView
591 /// for more on this.
592 class ConstTableView : public TableViewBase {
594 using TableViewBase::TableViewBase;
596 ConstTableView() = default;
598 ConstTableView(const TableView&);
599 ConstTableView(TableView&&);
600 ConstTableView& operator=(const TableView&);
601 ConstTableView& operator=(TableView&&);
604 typedef BasicRowExpr<const Table> ConstRowExpr;
605 ConstRowExpr get(size_t row_ndx) const noexcept;
606 ConstRowExpr front() const noexcept;
607 ConstRowExpr back() const noexcept;
608 ConstRowExpr operator[](size_t row_ndx) const noexcept;
611 ConstTableRef get_subtable(size_t column_ndx, size_t row_ndx) const;
614 ConstTableRef get_link_target(size_t column_ndx) const noexcept;
616 // Searching (Int and String)
617 ConstTableView find_all_int(size_t column_ndx, int64_t value) const;
618 ConstTableView find_all_bool(size_t column_ndx, bool value) const;
619 ConstTableView find_all_olddatetime(size_t column_ndx, OldDateTime value) const;
620 ConstTableView find_all_float(size_t column_ndx, float value) const;
621 ConstTableView find_all_double(size_t column_ndx, double value) const;
622 ConstTableView find_all_string(size_t column_ndx, StringData value) const;
624 const Table& get_parent() const noexcept;
626 std::unique_ptr<TableViewBase> clone() const override
628 return std::unique_ptr<TableViewBase>(new ConstTableView(*this));
631 std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
632 ConstSourcePayload mode) const override
634 patch.reset(new HandoverPatch);
635 std::unique_ptr<TableViewBase> retval(new ConstTableView(*this, *patch, mode));
639 std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
640 MutableSourcePayload mode) override
642 patch.reset(new HandoverPatch);
643 std::unique_ptr<TableViewBase> retval(new ConstTableView(*this, *patch, mode));
648 ConstTableView(const Table& parent);
650 ConstTableView find_all_integer(size_t column_ndx, int64_t value) const;
652 friend class TableView;
655 friend class TableViewBase;
659 // ================================================================================================
660 // TableViewBase Implementation:
662 inline const Query& TableViewBase::get_query() const noexcept
667 inline bool TableViewBase::is_empty() const noexcept
669 return m_row_indexes.is_empty();
672 inline bool TableViewBase::is_attached() const noexcept
674 return bool(m_table);
677 inline bool TableViewBase::is_row_attached(size_t row_ndx) const noexcept
679 return m_row_indexes.get(row_ndx) != detached_ref;
682 inline size_t TableViewBase::size() const noexcept
684 return m_row_indexes.size();
687 inline size_t TableViewBase::num_attached_rows() const noexcept
689 return m_row_indexes.size() - m_num_detached_refs;
692 inline size_t TableViewBase::get_source_ndx(size_t row_ndx) const noexcept
694 return to_size_t(m_row_indexes.get(row_ndx));
697 inline size_t TableViewBase::find_by_source_ndx(size_t source_ndx) const noexcept
699 REALM_ASSERT(source_ndx < m_table->size());
700 return m_row_indexes.find_first(source_ndx);
703 inline void TableViewBase::allocate_row_indexes()
705 // FIXME: This code is unreasonably complicated because it uses `IntegerColumn` as
706 // a free-standing container, and beause `IntegerColumn` does not conform to the
707 // RAII idiom (nor should it).
708 Allocator& alloc = m_row_indexes.get_alloc();
709 _impl::DeepArrayRefDestroyGuard ref_guard(alloc);
710 ref_guard.reset(IntegerColumn::create(alloc)); // Throws
711 m_table->register_view(this); // Throws
712 m_row_indexes.init_from_ref(alloc, ref_guard.release());
715 inline TableViewBase::TableViewBase()
716 : RowIndexes(IntegerColumn::unattached_root_tag(), Allocator::get_default()) // Throws
718 ref_type ref = IntegerColumn::create(m_row_indexes.get_alloc()); // Throws
719 m_row_indexes.get_root_array()->init_from_ref(ref);
722 inline TableViewBase::TableViewBase(Table* parent)
723 : RowIndexes(IntegerColumn::unattached_root_tag(), Allocator::get_default())
724 , m_table(parent->get_table_ref()) // Throws
725 , m_last_seen_version(m_table ? util::make_optional(m_table->m_version) : util::none)
727 allocate_row_indexes();
730 inline TableViewBase::TableViewBase(Table* parent, Query& query, size_t start, size_t end, size_t limit)
731 : RowIndexes(IntegerColumn::unattached_root_tag(), Allocator::get_default()) // Throws
732 , m_table(parent->get_table_ref())
737 , m_last_seen_version(outside_version())
739 allocate_row_indexes();
742 inline TableViewBase::TableViewBase(Table* parent, size_t column, BasicRowExpr<const Table> row)
743 : RowIndexes(IntegerColumn::unattached_root_tag(), Allocator::get_default())
744 , m_table(parent->get_table_ref()) // Throws
745 , m_linked_column(&parent->get_column_link_base(column).get_backlink_column())
747 , m_last_seen_version(m_table ? util::make_optional(m_table->m_version) : util::none)
749 allocate_row_indexes();
752 inline TableViewBase::TableViewBase(DistinctViewTag, Table* parent, size_t column_ndx)
753 : RowIndexes(IntegerColumn::unattached_root_tag(), Allocator::get_default())
754 , m_table(parent->get_table_ref()) // Throws
755 , m_distinct_column_source(column_ndx)
756 , m_last_seen_version(m_table ? util::make_optional(m_table->m_version) : util::none)
758 REALM_ASSERT(m_distinct_column_source != npos);
760 allocate_row_indexes();
763 inline TableViewBase::TableViewBase(Table* parent, ConstLinkViewRef link_view)
764 : RowIndexes(IntegerColumn::unattached_root_tag(), Allocator::get_default())
765 , m_table(parent->get_table_ref()) // Throws
766 , m_linkview_source(std::move(link_view))
767 , m_last_seen_version(m_table ? util::make_optional(m_table->m_version) : util::none)
769 REALM_ASSERT(m_linkview_source);
771 allocate_row_indexes();
774 inline TableViewBase::TableViewBase(const TableViewBase& tv)
775 : RowIndexes(IntegerColumn::unattached_root_tag(), Allocator::get_default())
776 , m_table(tv.m_table)
777 , m_linked_column(tv.m_linked_column)
778 , m_linked_row(tv.m_linked_row)
779 , m_linkview_source(tv.m_linkview_source)
780 , m_distinct_column_source(tv.m_distinct_column_source)
781 , m_descriptor_ordering(std::move(tv.m_descriptor_ordering))
782 , m_query(tv.m_query)
783 , m_start(tv.m_start)
785 , m_limit(tv.m_limit)
786 , m_last_seen_version(tv.m_last_seen_version)
787 , m_num_detached_refs(tv.m_num_detached_refs)
789 // FIXME: This code is unreasonably complicated because it uses `IntegerColumn` as
790 // a free-standing container, and because `IntegerColumn` does not conform to the
791 // RAII idiom (nor should it).
792 Allocator& alloc = m_row_indexes.get_alloc();
793 MemRef mem = tv.m_row_indexes.get_root_array()->clone_deep(alloc); // Throws
794 _impl::DeepArrayRefDestroyGuard ref_guard(mem.get_ref(), alloc);
796 m_table->register_view(this); // Throws
797 m_row_indexes.init_from_mem(alloc, mem);
801 inline TableViewBase::TableViewBase(TableViewBase&& tv) noexcept
802 : RowIndexes(std::move(tv.m_row_indexes))
803 , m_table(std::move(tv.m_table))
804 , m_linked_column(tv.m_linked_column)
805 , m_linked_row(tv.m_linked_row)
806 , m_linkview_source(std::move(tv.m_linkview_source))
807 , m_distinct_column_source(tv.m_distinct_column_source)
808 , m_descriptor_ordering(std::move(tv.m_descriptor_ordering))
809 , m_query(std::move(tv.m_query))
810 , m_start(tv.m_start)
812 , m_limit(tv.m_limit)
814 // if we are created from a table view which is outdated, take care to use the outdated
815 // version number so that we can later trigger a sync if needed.
816 m_last_seen_version(tv.m_last_seen_version)
817 , m_num_detached_refs(tv.m_num_detached_refs)
820 m_table->move_registered_view(&tv, this);
823 inline TableViewBase::~TableViewBase() noexcept
826 m_table->unregister_view(this);
827 m_table = TableRef();
829 m_row_indexes.destroy(); // Shallow
832 inline TableViewBase& TableViewBase::operator=(TableViewBase&& tv) noexcept
835 m_table->unregister_view(this);
836 m_table = std::move(tv.m_table);
838 m_table->move_registered_view(&tv, this);
840 m_row_indexes.move_assign(tv.m_row_indexes);
841 m_query = std::move(tv.m_query);
842 m_num_detached_refs = tv.m_num_detached_refs;
843 m_last_seen_version = tv.m_last_seen_version;
844 m_start = tv.m_start;
846 m_limit = tv.m_limit;
847 m_linked_column = tv.m_linked_column;
848 m_linked_row = tv.m_linked_row;
849 m_linkview_source = std::move(tv.m_linkview_source);
850 m_descriptor_ordering = std::move(tv.m_descriptor_ordering);
851 m_distinct_column_source = tv.m_distinct_column_source;
856 inline TableViewBase& TableViewBase::operator=(const TableViewBase& tv)
861 if (m_table != tv.m_table) {
863 m_table->unregister_view(this);
864 m_table = tv.m_table;
866 m_table->register_view(this);
869 Allocator& alloc = m_row_indexes.get_alloc();
870 MemRef mem = tv.m_row_indexes.get_root_array()->clone_deep(alloc); // Throws
871 _impl::DeepArrayRefDestroyGuard ref_guard(mem.get_ref(), alloc);
872 m_row_indexes.destroy();
873 m_row_indexes.get_root_array()->init_from_mem(mem);
876 m_query = tv.m_query;
877 m_num_detached_refs = tv.m_num_detached_refs;
878 m_last_seen_version = tv.m_last_seen_version;
879 m_start = tv.m_start;
881 m_limit = tv.m_limit;
882 m_linked_column = tv.m_linked_column;
883 m_linked_row = tv.m_linked_row;
884 m_linkview_source = tv.m_linkview_source;
885 m_descriptor_ordering = tv.m_descriptor_ordering;
886 m_distinct_column_source = tv.m_distinct_column_source;
891 #define REALM_ASSERT_COLUMN(column_ndx) \
892 REALM_ASSERT(m_table); \
893 REALM_ASSERT(column_ndx < m_table->get_column_count())
895 #define REALM_ASSERT_ROW(row_ndx) \
896 REALM_ASSERT(m_table); \
897 REALM_ASSERT(row_ndx < m_row_indexes.size())
899 #define REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, column_type) \
900 REALM_ASSERT_COLUMN(column_ndx); \
902 REALM_DIAG_IGNORE_TAUTOLOGICAL_COMPARE(); \
903 REALM_ASSERT(m_table->get_column_type(column_ndx) == column_type || \
904 (m_table->get_column_type(column_ndx) == type_OldDateTime && column_type == type_Int)); \
907 #define REALM_ASSERT_INDEX(column_ndx, row_ndx) \
908 REALM_ASSERT_COLUMN(column_ndx); \
909 REALM_ASSERT(row_ndx < m_row_indexes.size())
911 #define REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, column_type) \
912 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, column_type); \
913 REALM_ASSERT(row_ndx < m_row_indexes.size())
915 #define REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx) \
916 REALM_ASSERT_COLUMN(column_ndx); \
918 REALM_DIAG_IGNORE_TAUTOLOGICAL_COMPARE(); \
919 REALM_ASSERT(m_table->get_column_type(column_ndx) == type_Table || \
920 (m_table->get_column_type(column_ndx) == type_Mixed)); \
922 REALM_ASSERT(row_ndx < m_row_indexes.size())
924 // Column information
926 inline const ColumnBase& TableViewBase::get_column_base(size_t index) const
928 return m_table->get_column_base(index);
931 inline size_t TableViewBase::get_column_count() const noexcept
933 REALM_ASSERT(m_table);
934 return m_table->get_column_count();
937 inline StringData TableViewBase::get_column_name(size_t column_ndx) const noexcept
939 REALM_ASSERT(m_table);
940 return m_table->get_column_name(column_ndx);
943 inline size_t TableViewBase::get_column_index(StringData name) const
945 REALM_ASSERT(m_table);
946 return m_table->get_column_index(name);
949 inline DataType TableViewBase::get_column_type(size_t column_ndx) const noexcept
951 REALM_ASSERT(m_table);
952 return m_table->get_column_type(column_ndx);
959 inline int64_t TableViewBase::get_int(size_t column_ndx, size_t row_ndx) const noexcept
961 REALM_ASSERT_INDEX(column_ndx, row_ndx);
963 const int64_t real_ndx = m_row_indexes.get(row_ndx);
964 REALM_ASSERT(real_ndx != detached_ref);
965 return m_table->get_int(column_ndx, to_size_t(real_ndx));
968 inline bool TableViewBase::get_bool(size_t column_ndx, size_t row_ndx) const noexcept
970 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Bool);
972 const int64_t real_ndx = m_row_indexes.get(row_ndx);
973 REALM_ASSERT(real_ndx != detached_ref);
974 return m_table->get_bool(column_ndx, to_size_t(real_ndx));
977 inline OldDateTime TableViewBase::get_olddatetime(size_t column_ndx, size_t row_ndx) const noexcept
979 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_OldDateTime);
981 const int64_t real_ndx = m_row_indexes.get(row_ndx);
982 REALM_ASSERT(real_ndx != detached_ref);
983 return m_table->get_olddatetime(column_ndx, to_size_t(real_ndx));
986 inline Timestamp TableViewBase::get_timestamp(size_t column_ndx, size_t row_ndx) const noexcept
988 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Timestamp);
990 const int64_t real_ndx = m_row_indexes.get(row_ndx);
991 REALM_ASSERT(real_ndx != detached_ref);
992 return m_table->get_timestamp(column_ndx, to_size_t(real_ndx));
995 inline float TableViewBase::get_float(size_t column_ndx, size_t row_ndx) const noexcept
997 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Float);
999 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1000 REALM_ASSERT(real_ndx != detached_ref);
1001 return m_table->get_float(column_ndx, to_size_t(real_ndx));
1004 inline double TableViewBase::get_double(size_t column_ndx, size_t row_ndx) const noexcept
1006 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Double);
1008 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1009 REALM_ASSERT(real_ndx != detached_ref);
1010 return m_table->get_double(column_ndx, to_size_t(real_ndx));
1013 inline StringData TableViewBase::get_string(size_t column_ndx, size_t row_ndx) const noexcept
1015 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_String);
1017 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1018 REALM_ASSERT(real_ndx != detached_ref);
1019 return m_table->get_string(column_ndx, to_size_t(real_ndx));
1022 inline BinaryData TableViewBase::get_binary(size_t column_ndx, size_t row_ndx) const noexcept
1024 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Binary);
1026 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1027 REALM_ASSERT(real_ndx != detached_ref);
1028 return m_table->get_binary(column_ndx, to_size_t(real_ndx));
1031 inline Mixed TableViewBase::get_mixed(size_t column_ndx, size_t row_ndx) const noexcept
1033 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Mixed);
1035 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1036 REALM_ASSERT(real_ndx != detached_ref);
1037 return m_table->get_mixed(column_ndx, to_size_t(real_ndx));
1040 inline DataType TableViewBase::get_mixed_type(size_t column_ndx, size_t row_ndx) const noexcept
1042 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Mixed);
1044 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1045 REALM_ASSERT(real_ndx != detached_ref);
1046 return m_table->get_mixed_type(column_ndx, to_size_t(real_ndx));
1049 inline size_t TableViewBase::get_subtable_size(size_t column_ndx, size_t row_ndx) const noexcept
1051 REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1053 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1054 REALM_ASSERT(real_ndx != detached_ref);
1055 return m_table->get_subtable_size(column_ndx, to_size_t(real_ndx));
1058 inline size_t TableViewBase::get_link(size_t column_ndx, size_t row_ndx) const noexcept
1060 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Link);
1062 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1063 REALM_ASSERT(real_ndx != detached_ref);
1064 return m_table->get_link(column_ndx, to_size_t(real_ndx));
1067 inline TableRef TableView::get_link_target(size_t column_ndx) noexcept
1069 return m_table->get_link_target(column_ndx);
1072 inline ConstTableRef TableView::get_link_target(size_t column_ndx) const noexcept
1074 return m_table->get_link_target(column_ndx);
1077 inline ConstTableRef ConstTableView::get_link_target(size_t column_ndx) const noexcept
1079 return m_table->get_link_target(column_ndx);
1082 inline bool TableViewBase::is_null_link(size_t column_ndx, size_t row_ndx) const noexcept
1084 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Link);
1086 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1087 REALM_ASSERT(real_ndx != detached_ref);
1088 return m_table->is_null_link(column_ndx, to_size_t(real_ndx));
1095 inline size_t TableViewBase::find_first_int(size_t column_ndx, int64_t value) const
1097 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Int);
1098 return find_first_integer(column_ndx, value);
1101 inline size_t TableViewBase::find_first_bool(size_t column_ndx, bool value) const
1103 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Bool);
1104 return find_first_integer(column_ndx, value ? 1 : 0);
1107 inline size_t TableViewBase::find_first_olddatetime(size_t column_ndx, OldDateTime value) const
1109 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_OldDateTime);
1110 return find_first_integer(column_ndx, int64_t(value.get_olddatetime()));
1113 inline size_t TableViewBase::find_first_integer(size_t column_ndx, int64_t value) const
1115 return find_first<int64_t>(column_ndx, value);
1118 inline size_t TableViewBase::find_first_float(size_t column_ndx, float value) const
1120 return find_first<float>(column_ndx, value);
1123 inline size_t TableViewBase::find_first_double(size_t column_ndx, double value) const
1125 return find_first<double>(column_ndx, value);
1128 inline size_t TableViewBase::find_first_string(size_t column_ndx, StringData value) const
1130 return find_first<StringData>(column_ndx, value);
1133 inline size_t TableViewBase::find_first_binary(size_t column_ndx, BinaryData value) const
1135 return find_first<BinaryData>(column_ndx, value);
1138 inline size_t TableViewBase::find_first_timestamp(size_t column_ndx, Timestamp value) const
1140 return find_first<Timestamp>(column_ndx, value);
1144 template <class R, class V>
1145 R TableViewBase::find_all_integer(V* view, size_t column_ndx, int64_t value)
1147 typedef typename std::remove_const<V>::type TNonConst;
1148 return view->m_table->where(const_cast<TNonConst*>(view)).equal(column_ndx, value).find_all();
1151 template <class R, class V>
1152 R TableViewBase::find_all_float(V* view, size_t column_ndx, float value)
1154 typedef typename std::remove_const<V>::type TNonConst;
1155 return view->m_table->where(const_cast<TNonConst*>(view)).equal(column_ndx, value).find_all();
1158 template <class R, class V>
1159 R TableViewBase::find_all_double(V* view, size_t column_ndx, double value)
1161 typedef typename std::remove_const<V>::type TNonConst;
1162 return view->m_table->where(const_cast<TNonConst*>(view)).equal(column_ndx, value).find_all();
1165 template <class R, class V>
1166 R TableViewBase::find_all_string(V* view, size_t column_ndx, StringData value)
1168 typedef typename std::remove_const<V>::type TNonConst;
1169 return view->m_table->where(const_cast<TNonConst*>(view)).equal(column_ndx, value).find_all();
1173 //-------------------------- TableView, ConstTableView implementation:
1175 inline ConstTableView::ConstTableView(const TableView& tv)
1180 inline ConstTableView::ConstTableView(TableView&& tv)
1181 : TableViewBase(std::move(tv))
1185 inline void TableView::remove_last(RemoveMode underlying_mode)
1188 remove(size() - 1, underlying_mode);
1191 inline Table& TableView::get_parent() noexcept
1196 inline const Table& TableView::get_parent() const noexcept
1201 inline const Table& ConstTableView::get_parent() const noexcept
1206 inline TableView::TableView(Table& parent)
1207 : TableViewBase(&parent)
1211 inline TableView::TableView(Table& parent, Query& query, size_t start, size_t end, size_t limit)
1212 : TableViewBase(&parent, query, start, end, limit)
1216 inline TableView::TableView(Table& parent, ConstLinkViewRef link_view)
1217 : TableViewBase(&parent, std::move(link_view))
1221 inline TableView::TableView(TableViewBase::DistinctViewTag, Table& parent, size_t column_ndx)
1222 : TableViewBase(TableViewBase::DistinctView, &parent, column_ndx)
1226 inline ConstTableView::ConstTableView(const Table& parent)
1227 : TableViewBase(const_cast<Table*>(&parent))
1231 inline ConstTableView& ConstTableView::operator=(const TableView& tv)
1233 TableViewBase::operator=(tv);
1237 inline ConstTableView& ConstTableView::operator=(TableView&& tv)
1239 TableViewBase::operator=(std::move(tv));
1245 inline TableView TableView::find_all_string(size_t column_ndx, StringData value)
1247 return TableViewBase::find_all_string<TableView>(this, column_ndx, value);
1250 inline ConstTableView TableView::find_all_string(size_t column_ndx, StringData value) const
1252 return TableViewBase::find_all_string<ConstTableView>(this, column_ndx, value);
1255 inline ConstTableView ConstTableView::find_all_string(size_t column_ndx, StringData value) const
1257 return TableViewBase::find_all_string<ConstTableView>(this, column_ndx, value);
1261 inline TableView TableView::find_all_float(size_t column_ndx, float value)
1263 return TableViewBase::find_all_float<TableView>(this, column_ndx, value);
1266 inline ConstTableView TableView::find_all_float(size_t column_ndx, float value) const
1268 return TableViewBase::find_all_float<ConstTableView>(this, column_ndx, value);
1271 inline ConstTableView ConstTableView::find_all_float(size_t column_ndx, float value) const
1273 return TableViewBase::find_all_float<ConstTableView>(this, column_ndx, value);
1278 inline TableView TableView::find_all_double(size_t column_ndx, double value)
1280 return TableViewBase::find_all_double<TableView>(this, column_ndx, value);
1283 inline ConstTableView TableView::find_all_double(size_t column_ndx, double value) const
1285 return TableViewBase::find_all_double<ConstTableView>(this, column_ndx, value);
1288 inline ConstTableView ConstTableView::find_all_double(size_t column_ndx, double value) const
1290 return TableViewBase::find_all_double<ConstTableView>(this, column_ndx, value);
1294 // -- 3 variants of the 3 find_all_{int, bool, date} all based on integer
1296 inline TableView TableView::find_all_integer(size_t column_ndx, int64_t value)
1298 return TableViewBase::find_all_integer<TableView>(this, column_ndx, value);
1301 inline ConstTableView TableView::find_all_integer(size_t column_ndx, int64_t value) const
1303 return TableViewBase::find_all_integer<ConstTableView>(this, column_ndx, value);
1306 inline ConstTableView ConstTableView::find_all_integer(size_t column_ndx, int64_t value) const
1308 return TableViewBase::find_all_integer<ConstTableView>(this, column_ndx, value);
1312 inline TableView TableView::find_all_int(size_t column_ndx, int64_t value)
1314 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Int);
1315 return find_all_integer(column_ndx, value);
1318 inline TableView TableView::find_all_bool(size_t column_ndx, bool value)
1320 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Bool);
1321 return find_all_integer(column_ndx, value ? 1 : 0);
1324 inline TableView TableView::find_all_olddatetime(size_t column_ndx, OldDateTime value)
1326 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_OldDateTime);
1327 return find_all_integer(column_ndx, int64_t(value.get_olddatetime()));
1331 inline ConstTableView TableView::find_all_int(size_t column_ndx, int64_t value) const
1333 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Int);
1334 return find_all_integer(column_ndx, value);
1337 inline ConstTableView TableView::find_all_bool(size_t column_ndx, bool value) const
1339 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Bool);
1340 return find_all_integer(column_ndx, value ? 1 : 0);
1343 inline ConstTableView TableView::find_all_olddatetime(size_t column_ndx, OldDateTime value) const
1345 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_OldDateTime);
1346 return find_all_integer(column_ndx, int64_t(value.get_olddatetime()));
1350 inline ConstTableView ConstTableView::find_all_int(size_t column_ndx, int64_t value) const
1352 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Int);
1353 return find_all_integer(column_ndx, value);
1356 inline ConstTableView ConstTableView::find_all_bool(size_t column_ndx, bool value) const
1358 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Bool);
1359 return find_all_integer(column_ndx, value ? 1 : 0);
1362 inline ConstTableView ConstTableView::find_all_olddatetime(size_t column_ndx, OldDateTime value) const
1364 REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_OldDateTime);
1365 return find_all_integer(column_ndx, int64_t(value.get_olddatetime()));
1372 inline TableView::RowExpr TableView::get(size_t row_ndx) noexcept
1374 REALM_ASSERT_ROW(row_ndx);
1375 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1376 REALM_ASSERT(real_ndx != detached_ref);
1377 return m_table->get(to_size_t(real_ndx));
1380 inline TableView::ConstRowExpr TableView::get(size_t row_ndx) const noexcept
1382 REALM_ASSERT_ROW(row_ndx);
1383 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1384 REALM_ASSERT(real_ndx != detached_ref);
1385 return m_table->get(to_size_t(real_ndx));
1388 inline ConstTableView::ConstRowExpr ConstTableView::get(size_t row_ndx) const noexcept
1390 REALM_ASSERT_ROW(row_ndx);
1391 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1392 REALM_ASSERT(real_ndx != detached_ref);
1393 return m_table->get(to_size_t(real_ndx));
1396 inline TableView::RowExpr TableView::front() noexcept
1401 inline TableView::ConstRowExpr TableView::front() const noexcept
1406 inline ConstTableView::ConstRowExpr ConstTableView::front() const noexcept
1411 inline TableView::RowExpr TableView::back() noexcept
1413 size_t last_row_ndx = size() - 1;
1414 return get(last_row_ndx);
1417 inline TableView::ConstRowExpr TableView::back() const noexcept
1419 size_t last_row_ndx = size() - 1;
1420 return get(last_row_ndx);
1423 inline ConstTableView::ConstRowExpr ConstTableView::back() const noexcept
1425 size_t last_row_ndx = size() - 1;
1426 return get(last_row_ndx);
1429 inline TableView::RowExpr TableView::operator[](size_t row_ndx) noexcept
1431 return get(row_ndx);
1434 inline TableView::ConstRowExpr TableView::operator[](size_t row_ndx) const noexcept
1436 return get(row_ndx);
1439 inline ConstTableView::ConstRowExpr ConstTableView::operator[](size_t row_ndx) const noexcept
1441 return get(row_ndx);
1448 inline TableRef TableView::get_subtable(size_t column_ndx, size_t row_ndx)
1450 REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1452 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1453 REALM_ASSERT(real_ndx != detached_ref);
1454 return m_table->get_subtable(column_ndx, to_size_t(real_ndx));
1457 inline ConstTableRef TableView::get_subtable(size_t column_ndx, size_t row_ndx) const
1459 REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1461 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1462 REALM_ASSERT(real_ndx != detached_ref);
1463 return m_table->get_subtable(column_ndx, to_size_t(real_ndx));
1466 inline ConstTableRef ConstTableView::get_subtable(size_t column_ndx, size_t row_ndx) const
1468 REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1470 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1471 REALM_ASSERT(real_ndx != detached_ref);
1472 return m_table->get_subtable(column_ndx, to_size_t(real_ndx));
1475 inline void TableView::clear_subtable(size_t column_ndx, size_t row_ndx)
1477 REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1479 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1480 REALM_ASSERT(real_ndx != detached_ref);
1481 return m_table->clear_subtable(column_ndx, to_size_t(real_ndx));
1488 inline void TableView::set_int(size_t column_ndx, size_t row_ndx, int64_t value)
1490 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Int);
1492 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1493 REALM_ASSERT(real_ndx != detached_ref);
1494 m_table->set_int(column_ndx, to_size_t(real_ndx), value);
1497 inline void TableView::set_bool(size_t column_ndx, size_t row_ndx, bool value)
1499 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Bool);
1501 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1502 REALM_ASSERT(real_ndx != detached_ref);
1503 m_table->set_bool(column_ndx, to_size_t(real_ndx), value);
1506 inline void TableView::set_olddatetime(size_t column_ndx, size_t row_ndx, OldDateTime value)
1508 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_OldDateTime);
1510 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1511 REALM_ASSERT(real_ndx != detached_ref);
1512 m_table->set_olddatetime(column_ndx, to_size_t(real_ndx), value);
1515 inline void TableView::set_timestamp(size_t column_ndx, size_t row_ndx, Timestamp value)
1517 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Timestamp);
1519 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1520 REALM_ASSERT(real_ndx != detached_ref);
1521 m_table->set_timestamp(column_ndx, to_size_t(real_ndx), value);
1524 inline void TableView::set_float(size_t column_ndx, size_t row_ndx, float value)
1526 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Float);
1528 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1529 REALM_ASSERT(real_ndx != detached_ref);
1530 m_table->set_float(column_ndx, to_size_t(real_ndx), value);
1533 inline void TableView::set_double(size_t column_ndx, size_t row_ndx, double value)
1535 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Double);
1537 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1538 REALM_ASSERT(real_ndx != detached_ref);
1539 m_table->set_double(column_ndx, to_size_t(real_ndx), value);
1543 inline void TableView::set_enum(size_t column_ndx, size_t row_ndx, E value)
1545 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1546 REALM_ASSERT(real_ndx != detached_ref);
1547 m_table->set_int(column_ndx, real_ndx, value);
1550 inline void TableView::set_string(size_t column_ndx, size_t row_ndx, StringData value)
1552 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_String);
1554 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1555 REALM_ASSERT(real_ndx != detached_ref);
1556 m_table->set_string(column_ndx, to_size_t(real_ndx), value);
1559 inline void TableView::set_binary(size_t column_ndx, size_t row_ndx, BinaryData value)
1561 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Binary);
1563 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1564 REALM_ASSERT(real_ndx != detached_ref);
1565 m_table->set_binary(column_ndx, to_size_t(real_ndx), value);
1568 inline void TableView::set_mixed(size_t column_ndx, size_t row_ndx, Mixed value)
1570 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Mixed);
1572 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1573 REALM_ASSERT(real_ndx != detached_ref);
1574 m_table->set_mixed(column_ndx, to_size_t(real_ndx), value);
1577 inline void TableView::set_subtable(size_t column_ndx, size_t row_ndx, const Table* value)
1579 REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1580 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1581 REALM_ASSERT(real_ndx != detached_ref);
1582 m_table->set_subtable(column_ndx, to_size_t(real_ndx), value);
1585 inline void TableView::set_link(size_t column_ndx, size_t row_ndx, size_t target_row_ndx)
1587 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Link);
1588 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1589 REALM_ASSERT(real_ndx != detached_ref);
1590 m_table->set_link(column_ndx, to_size_t(real_ndx), target_row_ndx);
1593 inline void TableView::nullify_link(size_t column_ndx, size_t row_ndx)
1595 REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Link);
1596 const int64_t real_ndx = m_row_indexes.get(row_ndx);
1597 REALM_ASSERT(real_ndx != detached_ref);
1598 m_table->nullify_link(column_ndx, to_size_t(real_ndx));
1601 } // namespace realm
1603 #endif // REALM_TABLE_VIEW_HPP