added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / table_view.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_TABLE_VIEW_HPP
20 #define REALM_TABLE_VIEW_HPP
21
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>
27
28 namespace realm {
29
30 // Views, tables and synchronization between them:
31 //
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.
36 //
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)
41 //
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.
44 //
45 // Reflective views:
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().
52 //
53 // Imperative views:
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
58 //   changed.
59 //
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,
62 //   not removed.
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().
65 //
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.
69 //
70 // Use cases:
71 //
72 // 1. Presenting data
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.
77 //
78 // 2. Handover
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.
84 //
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.
90 //
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):
95 //
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();
101 //    }
102 //    commit_and_continue_as_read();
103 //
104 // This is idiomatic imperative code and it works if the view is operated in imperative mode.
105 //
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.
111 //
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.
116 //
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();
122 //    }
123 //
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) ?
126 //
127 // using the imperative operating mode:
128 //
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)) {
134 //            Row r = view[i];
135 //            r.set_int(salary_column, limit);
136 //        }
137 //        commit_and_continue_as_write();
138 //    }
139 //
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.
144 //
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
151 // transactions.
152
153
154 /// Common base class for TableView and ConstTableView.
155 class TableViewBase : public RowIndexes {
156 public:
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;
163
164     // Tells if the table that this TableView points at still exists or has been deleted.
165     bool is_attached() const noexcept;
166
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;
170
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
173     // a query
174     const Query& get_query() const noexcept;
175
176     // Column information
177     const ColumnBase& get_column_base(size_t index) const;
178
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;
183
184     // Getting values
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;
196
197     // Links
198     bool is_null_link(size_t column_ndx, size_t row_ndx) const noexcept;
199
200     // Subtables
201     size_t get_subtable_size(size_t column_ndx, size_t row_ndx) const noexcept;
202
203     // Searching
204     template<typename T>
205     size_t find_first(size_t column_ndx, T value) const;
206
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;
215
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;
222
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;
228
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;
234
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;
240
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;
243
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;
247
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;
251
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;
254
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;
259
260     // Conversion
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;
264
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;
273
274     // Tells if this TableView depends on a LinkList or row that has been deleted.
275     bool depends_on_deleted_object() const;
276
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.
281     //
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
284     // outdated.
285     //
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;
289
290     // Sort m_row_indexes according to one column
291     void sort(size_t column, bool ascending = true);
292
293     // Sort m_row_indexes according to multiple columns
294     void sort(SortDescriptor order);
295
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);
303
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);
307
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;
313
314     virtual ~TableViewBase() noexcept;
315
316     virtual std::unique_ptr<TableViewBase> clone() const = 0;
317
318 protected:
319     // This TableView can be "born" from 4 different sources:
320     // - LinkView
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;
326
327     void do_sync();
328
329     // Null if, and only if, the view is detached.
330     mutable TableRef m_table;
331
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;
336
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;
339
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;
342
343     // Stores the ordering criteria of applied sort and distinct operations.
344     DescriptorOrdering m_descriptor_ordering;
345
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.
349     Query m_query;
350     // parameters for findall, needed to rerun the query
351     size_t m_start;
352     size_t m_end;
353     size_t m_limit;
354
355     mutable util::Optional<uint_fast64_t> m_last_seen_version;
356
357     size_t m_num_detached_refs = 0;
358     /// Construct null view (no memory allocated).
359     TableViewBase();
360
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);
366
367     enum DistinctViewTag { DistinctView };
368     TableViewBase(DistinctViewTag, Table* parent, size_t column_ndx);
369
370     /// Copy constructor.
371     TableViewBase(const TableViewBase&);
372
373     /// Move constructor.
374     TableViewBase(TableViewBase&&) noexcept;
375
376     TableViewBase& operator=(const TableViewBase&);
377     TableViewBase& operator=(TableViewBase&&) noexcept;
378
379     template <class R, class V>
380     static R find_all_integer(V*, size_t, int64_t);
381
382     template <class R, class V>
383     static R find_all_float(V*, size_t, float);
384
385     template <class R, class V>
386     static R find_all_double(V*, size_t, double);
387
388     template <class R, class V>
389     static R find_all_string(V*, size_t, StringData);
390
391     using HandoverPatch = TableViewHandoverPatch;
392
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;
398
399     virtual std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
400                                                               MutableSourcePayload mode) = 0;
401
402     void apply_and_consume_patch(std::unique_ptr<HandoverPatch>& patch, Group& group)
403     {
404         apply_patch(*patch, group);
405         patch.reset();
406     }
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);
411
412 private:
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;
418
419     friend class Table;
420     friend class Query;
421     friend class SharedGroup;
422
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;
430 };
431
432
433 inline void TableViewBase::detach() const noexcept // may have to remove const
434 {
435     m_table = TableRef();
436 }
437
438
439 class ConstTableView;
440
441
442 enum class RemoveMode { ordered, unordered };
443
444
445 /// A TableView gives read and write access to the parent table.
446 ///
447 /// A 'const TableView' cannot be changed (e.g. sorted), nor can the
448 /// parent table be modified through it.
449 ///
450 /// A TableView is both copyable and movable.
451 class TableView : public TableViewBase {
452 public:
453     using TableViewBase::TableViewBase;
454
455     TableView() = default;
456
457     // Rows
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;
468
469     // Setting values
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);
474     template <class E>
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);
483
484     // Subtables
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);
488
489     // Links
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);
493
494     /// \defgroup table_view_removes
495     //@{
496     /// \brief Remove the specified row (or rows) from the underlying table.
497     ///
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.
502     ///
503     /// When rows are removed from the underlying table, they will by necessity
504     /// also be removed from the table view.
505     ///
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.
508     ///
509     /// \param row_ndx The index within this table view of the row to be
510     /// removed.
511     ///
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);
522     //@}
523
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;
539
540     Table& get_parent() noexcept;
541     const Table& get_parent() const noexcept;
542
543     std::unique_ptr<TableViewBase> clone() const override
544     {
545         return std::unique_ptr<TableViewBase>(new TableView(*this));
546     }
547
548     std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
549                                                       ConstSourcePayload mode) const override
550     {
551         patch.reset(new HandoverPatch);
552         std::unique_ptr<TableViewBase> retval(new TableView(*this, *patch, mode));
553         return retval;
554     }
555
556     std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
557                                                       MutableSourcePayload mode) override
558     {
559         patch.reset(new HandoverPatch);
560         std::unique_ptr<TableViewBase> retval(new TableView(*this, *patch, mode));
561         return retval;
562     }
563
564 private:
565     TableView(Table& parent);
566     TableView(Table& parent, Query& query, size_t start, size_t end, size_t limit);
567     TableView(Table& parent, ConstLinkViewRef);
568
569     TableView(DistinctViewTag, Table& parent, size_t column_ndx);
570
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;
573
574     friend class ConstTableView;
575     friend class Table;
576     friend class Query;
577     friend class TableViewBase;
578     friend class LinkView;
579 };
580
581
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.
585 ///
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.
589 ///
590 /// A ConstTableView has both copy and move semantics. See TableView
591 /// for more on this.
592 class ConstTableView : public TableViewBase {
593 public:
594     using TableViewBase::TableViewBase;
595
596     ConstTableView() = default;
597
598     ConstTableView(const TableView&);
599     ConstTableView(TableView&&);
600     ConstTableView& operator=(const TableView&);
601     ConstTableView& operator=(TableView&&);
602
603     // Rows
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;
609
610     // Subtables
611     ConstTableRef get_subtable(size_t column_ndx, size_t row_ndx) const;
612
613     // Links
614     ConstTableRef get_link_target(size_t column_ndx) const noexcept;
615
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;
623
624     const Table& get_parent() const noexcept;
625
626     std::unique_ptr<TableViewBase> clone() const override
627     {
628         return std::unique_ptr<TableViewBase>(new ConstTableView(*this));
629     }
630
631     std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
632                                                       ConstSourcePayload mode) const override
633     {
634         patch.reset(new HandoverPatch);
635         std::unique_ptr<TableViewBase> retval(new ConstTableView(*this, *patch, mode));
636         return retval;
637     }
638
639     std::unique_ptr<TableViewBase> clone_for_handover(std::unique_ptr<HandoverPatch>& patch,
640                                                       MutableSourcePayload mode) override
641     {
642         patch.reset(new HandoverPatch);
643         std::unique_ptr<TableViewBase> retval(new ConstTableView(*this, *patch, mode));
644         return retval;
645     }
646
647 private:
648     ConstTableView(const Table& parent);
649
650     ConstTableView find_all_integer(size_t column_ndx, int64_t value) const;
651
652     friend class TableView;
653     friend class Table;
654     friend class Query;
655     friend class TableViewBase;
656 };
657
658
659 // ================================================================================================
660 // TableViewBase Implementation:
661
662 inline const Query& TableViewBase::get_query() const noexcept
663 {
664     return m_query;
665 }
666
667 inline bool TableViewBase::is_empty() const noexcept
668 {
669     return m_row_indexes.is_empty();
670 }
671
672 inline bool TableViewBase::is_attached() const noexcept
673 {
674     return bool(m_table);
675 }
676
677 inline bool TableViewBase::is_row_attached(size_t row_ndx) const noexcept
678 {
679     return m_row_indexes.get(row_ndx) != detached_ref;
680 }
681
682 inline size_t TableViewBase::size() const noexcept
683 {
684     return m_row_indexes.size();
685 }
686
687 inline size_t TableViewBase::num_attached_rows() const noexcept
688 {
689     return m_row_indexes.size() - m_num_detached_refs;
690 }
691
692 inline size_t TableViewBase::get_source_ndx(size_t row_ndx) const noexcept
693 {
694     return to_size_t(m_row_indexes.get(row_ndx));
695 }
696
697 inline size_t TableViewBase::find_by_source_ndx(size_t source_ndx) const noexcept
698 {
699     REALM_ASSERT(source_ndx < m_table->size());
700     return m_row_indexes.find_first(source_ndx);
701 }
702
703 inline void TableViewBase::allocate_row_indexes()
704 {
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());
713 }
714
715 inline TableViewBase::TableViewBase()
716     : RowIndexes(IntegerColumn::unattached_root_tag(), Allocator::get_default()) // Throws
717 {
718     ref_type ref = IntegerColumn::create(m_row_indexes.get_alloc()); // Throws
719     m_row_indexes.get_root_array()->init_from_ref(ref);
720 }
721
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)
726 {
727     allocate_row_indexes();
728 }
729
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())
733     , m_query(query)
734     , m_start(start)
735     , m_end(end)
736     , m_limit(limit)
737     , m_last_seen_version(outside_version())
738 {
739     allocate_row_indexes();
740 }
741
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())
746     , m_linked_row(row)
747     , m_last_seen_version(m_table ? util::make_optional(m_table->m_version) : util::none)
748 {
749     allocate_row_indexes();
750 }
751
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)
757 {
758     REALM_ASSERT(m_distinct_column_source != npos);
759
760     allocate_row_indexes();
761 }
762
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)
768 {
769     REALM_ASSERT(m_linkview_source);
770
771     allocate_row_indexes();
772 }
773
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)
784     , m_end(tv.m_end)
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)
788 {
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);
795     if (m_table)
796         m_table->register_view(this); // Throws
797     m_row_indexes.init_from_mem(alloc, mem);
798     ref_guard.release();
799 }
800
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)
811     , m_end(tv.m_end)
812     , m_limit(tv.m_limit)
813     ,
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)
818 {
819     if (m_table)
820         m_table->move_registered_view(&tv, this);
821 }
822
823 inline TableViewBase::~TableViewBase() noexcept
824 {
825     if (m_table) {
826         m_table->unregister_view(this);
827         m_table = TableRef();
828     }
829     m_row_indexes.destroy(); // Shallow
830 }
831
832 inline TableViewBase& TableViewBase::operator=(TableViewBase&& tv) noexcept
833 {
834     if (m_table)
835         m_table->unregister_view(this);
836     m_table = std::move(tv.m_table);
837     if (m_table)
838         m_table->move_registered_view(&tv, this);
839
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;
845     m_end = tv.m_end;
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;
852
853     return *this;
854 }
855
856 inline TableViewBase& TableViewBase::operator=(const TableViewBase& tv)
857 {
858     if (this == &tv)
859         return *this;
860
861     if (m_table != tv.m_table) {
862         if (m_table)
863             m_table->unregister_view(this);
864         m_table = tv.m_table;
865         if (m_table)
866             m_table->register_view(this);
867     }
868
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);
874     ref_guard.release();
875
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;
880     m_end = tv.m_end;
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;
887
888     return *this;
889 }
890
891 #define REALM_ASSERT_COLUMN(column_ndx)                                                                              \
892     REALM_ASSERT(m_table);                                                                                           \
893     REALM_ASSERT(column_ndx < m_table->get_column_count())
894
895 #define REALM_ASSERT_ROW(row_ndx)                                                                                    \
896     REALM_ASSERT(m_table);                                                                                           \
897     REALM_ASSERT(row_ndx < m_row_indexes.size())
898
899 #define REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, column_type)                                                        \
900     REALM_ASSERT_COLUMN(column_ndx);                                                                                 \
901     REALM_DIAG_PUSH();                                                                                               \
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));             \
905     REALM_DIAG_POP()
906
907 #define REALM_ASSERT_INDEX(column_ndx, row_ndx)                                                                      \
908     REALM_ASSERT_COLUMN(column_ndx);                                                                                 \
909     REALM_ASSERT(row_ndx < m_row_indexes.size())
910
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())
914
915 #define REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx)                                              \
916     REALM_ASSERT_COLUMN(column_ndx);                                                                                 \
917     REALM_DIAG_PUSH();                                                                                               \
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));                                              \
921     REALM_DIAG_POP();                                                                                                \
922     REALM_ASSERT(row_ndx < m_row_indexes.size())
923
924 // Column information
925
926 inline const ColumnBase& TableViewBase::get_column_base(size_t index) const
927 {
928     return m_table->get_column_base(index);
929 }
930
931 inline size_t TableViewBase::get_column_count() const noexcept
932 {
933     REALM_ASSERT(m_table);
934     return m_table->get_column_count();
935 }
936
937 inline StringData TableViewBase::get_column_name(size_t column_ndx) const noexcept
938 {
939     REALM_ASSERT(m_table);
940     return m_table->get_column_name(column_ndx);
941 }
942
943 inline size_t TableViewBase::get_column_index(StringData name) const
944 {
945     REALM_ASSERT(m_table);
946     return m_table->get_column_index(name);
947 }
948
949 inline DataType TableViewBase::get_column_type(size_t column_ndx) const noexcept
950 {
951     REALM_ASSERT(m_table);
952     return m_table->get_column_type(column_ndx);
953 }
954
955
956 // Getters
957
958
959 inline int64_t TableViewBase::get_int(size_t column_ndx, size_t row_ndx) const noexcept
960 {
961     REALM_ASSERT_INDEX(column_ndx, row_ndx);
962
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));
966 }
967
968 inline bool TableViewBase::get_bool(size_t column_ndx, size_t row_ndx) const noexcept
969 {
970     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Bool);
971
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));
975 }
976
977 inline OldDateTime TableViewBase::get_olddatetime(size_t column_ndx, size_t row_ndx) const noexcept
978 {
979     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_OldDateTime);
980
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));
984 }
985
986 inline Timestamp TableViewBase::get_timestamp(size_t column_ndx, size_t row_ndx) const noexcept
987 {
988     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Timestamp);
989
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));
993 }
994
995 inline float TableViewBase::get_float(size_t column_ndx, size_t row_ndx) const noexcept
996 {
997     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Float);
998
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));
1002 }
1003
1004 inline double TableViewBase::get_double(size_t column_ndx, size_t row_ndx) const noexcept
1005 {
1006     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Double);
1007
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));
1011 }
1012
1013 inline StringData TableViewBase::get_string(size_t column_ndx, size_t row_ndx) const noexcept
1014 {
1015     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_String);
1016
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));
1020 }
1021
1022 inline BinaryData TableViewBase::get_binary(size_t column_ndx, size_t row_ndx) const noexcept
1023 {
1024     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Binary);
1025
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));
1029 }
1030
1031 inline Mixed TableViewBase::get_mixed(size_t column_ndx, size_t row_ndx) const noexcept
1032 {
1033     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Mixed);
1034
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));
1038 }
1039
1040 inline DataType TableViewBase::get_mixed_type(size_t column_ndx, size_t row_ndx) const noexcept
1041 {
1042     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Mixed);
1043
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));
1047 }
1048
1049 inline size_t TableViewBase::get_subtable_size(size_t column_ndx, size_t row_ndx) const noexcept
1050 {
1051     REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1052
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));
1056 }
1057
1058 inline size_t TableViewBase::get_link(size_t column_ndx, size_t row_ndx) const noexcept
1059 {
1060     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Link);
1061
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));
1065 }
1066
1067 inline TableRef TableView::get_link_target(size_t column_ndx) noexcept
1068 {
1069     return m_table->get_link_target(column_ndx);
1070 }
1071
1072 inline ConstTableRef TableView::get_link_target(size_t column_ndx) const noexcept
1073 {
1074     return m_table->get_link_target(column_ndx);
1075 }
1076
1077 inline ConstTableRef ConstTableView::get_link_target(size_t column_ndx) const noexcept
1078 {
1079     return m_table->get_link_target(column_ndx);
1080 }
1081
1082 inline bool TableViewBase::is_null_link(size_t column_ndx, size_t row_ndx) const noexcept
1083 {
1084     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Link);
1085
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));
1089 }
1090
1091
1092 // Searching
1093
1094
1095 inline size_t TableViewBase::find_first_int(size_t column_ndx, int64_t value) const
1096 {
1097     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Int);
1098     return find_first_integer(column_ndx, value);
1099 }
1100
1101 inline size_t TableViewBase::find_first_bool(size_t column_ndx, bool value) const
1102 {
1103     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Bool);
1104     return find_first_integer(column_ndx, value ? 1 : 0);
1105 }
1106
1107 inline size_t TableViewBase::find_first_olddatetime(size_t column_ndx, OldDateTime value) const
1108 {
1109     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_OldDateTime);
1110     return find_first_integer(column_ndx, int64_t(value.get_olddatetime()));
1111 }
1112
1113 inline size_t TableViewBase::find_first_integer(size_t column_ndx, int64_t value) const
1114 {
1115     return find_first<int64_t>(column_ndx, value);
1116 }
1117
1118 inline size_t TableViewBase::find_first_float(size_t column_ndx, float value) const
1119 {
1120     return find_first<float>(column_ndx, value);
1121 }
1122
1123 inline size_t TableViewBase::find_first_double(size_t column_ndx, double value) const
1124 {
1125     return find_first<double>(column_ndx, value);
1126 }
1127
1128 inline size_t TableViewBase::find_first_string(size_t column_ndx, StringData value) const
1129 {
1130     return find_first<StringData>(column_ndx, value);
1131 }
1132
1133 inline size_t TableViewBase::find_first_binary(size_t column_ndx, BinaryData value) const
1134 {
1135     return find_first<BinaryData>(column_ndx, value);
1136 }
1137
1138 inline size_t TableViewBase::find_first_timestamp(size_t column_ndx, Timestamp value) const
1139 {
1140     return find_first<Timestamp>(column_ndx, value);
1141 }
1142
1143
1144 template <class R, class V>
1145 R TableViewBase::find_all_integer(V* view, size_t column_ndx, int64_t value)
1146 {
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();
1149 }
1150
1151 template <class R, class V>
1152 R TableViewBase::find_all_float(V* view, size_t column_ndx, float value)
1153 {
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();
1156 }
1157
1158 template <class R, class V>
1159 R TableViewBase::find_all_double(V* view, size_t column_ndx, double value)
1160 {
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();
1163 }
1164
1165 template <class R, class V>
1166 R TableViewBase::find_all_string(V* view, size_t column_ndx, StringData value)
1167 {
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();
1170 }
1171
1172
1173 //-------------------------- TableView, ConstTableView implementation:
1174
1175 inline ConstTableView::ConstTableView(const TableView& tv)
1176     : TableViewBase(tv)
1177 {
1178 }
1179
1180 inline ConstTableView::ConstTableView(TableView&& tv)
1181     : TableViewBase(std::move(tv))
1182 {
1183 }
1184
1185 inline void TableView::remove_last(RemoveMode underlying_mode)
1186 {
1187     if (!is_empty())
1188         remove(size() - 1, underlying_mode);
1189 }
1190
1191 inline Table& TableView::get_parent() noexcept
1192 {
1193     return *m_table;
1194 }
1195
1196 inline const Table& TableView::get_parent() const noexcept
1197 {
1198     return *m_table;
1199 }
1200
1201 inline const Table& ConstTableView::get_parent() const noexcept
1202 {
1203     return *m_table;
1204 }
1205
1206 inline TableView::TableView(Table& parent)
1207     : TableViewBase(&parent)
1208 {
1209 }
1210
1211 inline TableView::TableView(Table& parent, Query& query, size_t start, size_t end, size_t limit)
1212     : TableViewBase(&parent, query, start, end, limit)
1213 {
1214 }
1215
1216 inline TableView::TableView(Table& parent, ConstLinkViewRef link_view)
1217 : TableViewBase(&parent, std::move(link_view))
1218 {
1219 }
1220
1221 inline TableView::TableView(TableViewBase::DistinctViewTag, Table& parent, size_t column_ndx)
1222     : TableViewBase(TableViewBase::DistinctView, &parent, column_ndx)
1223 {
1224 }
1225
1226 inline ConstTableView::ConstTableView(const Table& parent)
1227     : TableViewBase(const_cast<Table*>(&parent))
1228 {
1229 }
1230
1231 inline ConstTableView& ConstTableView::operator=(const TableView& tv)
1232 {
1233     TableViewBase::operator=(tv);
1234     return *this;
1235 }
1236
1237 inline ConstTableView& ConstTableView::operator=(TableView&& tv)
1238 {
1239     TableViewBase::operator=(std::move(tv));
1240     return *this;
1241 }
1242
1243
1244 // - string
1245 inline TableView TableView::find_all_string(size_t column_ndx, StringData value)
1246 {
1247     return TableViewBase::find_all_string<TableView>(this, column_ndx, value);
1248 }
1249
1250 inline ConstTableView TableView::find_all_string(size_t column_ndx, StringData value) const
1251 {
1252     return TableViewBase::find_all_string<ConstTableView>(this, column_ndx, value);
1253 }
1254
1255 inline ConstTableView ConstTableView::find_all_string(size_t column_ndx, StringData value) const
1256 {
1257     return TableViewBase::find_all_string<ConstTableView>(this, column_ndx, value);
1258 }
1259
1260 // - float
1261 inline TableView TableView::find_all_float(size_t column_ndx, float value)
1262 {
1263     return TableViewBase::find_all_float<TableView>(this, column_ndx, value);
1264 }
1265
1266 inline ConstTableView TableView::find_all_float(size_t column_ndx, float value) const
1267 {
1268     return TableViewBase::find_all_float<ConstTableView>(this, column_ndx, value);
1269 }
1270
1271 inline ConstTableView ConstTableView::find_all_float(size_t column_ndx, float value) const
1272 {
1273     return TableViewBase::find_all_float<ConstTableView>(this, column_ndx, value);
1274 }
1275
1276
1277 // - double
1278 inline TableView TableView::find_all_double(size_t column_ndx, double value)
1279 {
1280     return TableViewBase::find_all_double<TableView>(this, column_ndx, value);
1281 }
1282
1283 inline ConstTableView TableView::find_all_double(size_t column_ndx, double value) const
1284 {
1285     return TableViewBase::find_all_double<ConstTableView>(this, column_ndx, value);
1286 }
1287
1288 inline ConstTableView ConstTableView::find_all_double(size_t column_ndx, double value) const
1289 {
1290     return TableViewBase::find_all_double<ConstTableView>(this, column_ndx, value);
1291 }
1292
1293
1294 // -- 3 variants of the 3 find_all_{int, bool, date} all based on integer
1295
1296 inline TableView TableView::find_all_integer(size_t column_ndx, int64_t value)
1297 {
1298     return TableViewBase::find_all_integer<TableView>(this, column_ndx, value);
1299 }
1300
1301 inline ConstTableView TableView::find_all_integer(size_t column_ndx, int64_t value) const
1302 {
1303     return TableViewBase::find_all_integer<ConstTableView>(this, column_ndx, value);
1304 }
1305
1306 inline ConstTableView ConstTableView::find_all_integer(size_t column_ndx, int64_t value) const
1307 {
1308     return TableViewBase::find_all_integer<ConstTableView>(this, column_ndx, value);
1309 }
1310
1311
1312 inline TableView TableView::find_all_int(size_t column_ndx, int64_t value)
1313 {
1314     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Int);
1315     return find_all_integer(column_ndx, value);
1316 }
1317
1318 inline TableView TableView::find_all_bool(size_t column_ndx, bool value)
1319 {
1320     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Bool);
1321     return find_all_integer(column_ndx, value ? 1 : 0);
1322 }
1323
1324 inline TableView TableView::find_all_olddatetime(size_t column_ndx, OldDateTime value)
1325 {
1326     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_OldDateTime);
1327     return find_all_integer(column_ndx, int64_t(value.get_olddatetime()));
1328 }
1329
1330
1331 inline ConstTableView TableView::find_all_int(size_t column_ndx, int64_t value) const
1332 {
1333     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Int);
1334     return find_all_integer(column_ndx, value);
1335 }
1336
1337 inline ConstTableView TableView::find_all_bool(size_t column_ndx, bool value) const
1338 {
1339     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Bool);
1340     return find_all_integer(column_ndx, value ? 1 : 0);
1341 }
1342
1343 inline ConstTableView TableView::find_all_olddatetime(size_t column_ndx, OldDateTime value) const
1344 {
1345     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_OldDateTime);
1346     return find_all_integer(column_ndx, int64_t(value.get_olddatetime()));
1347 }
1348
1349
1350 inline ConstTableView ConstTableView::find_all_int(size_t column_ndx, int64_t value) const
1351 {
1352     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Int);
1353     return find_all_integer(column_ndx, value);
1354 }
1355
1356 inline ConstTableView ConstTableView::find_all_bool(size_t column_ndx, bool value) const
1357 {
1358     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_Bool);
1359     return find_all_integer(column_ndx, value ? 1 : 0);
1360 }
1361
1362 inline ConstTableView ConstTableView::find_all_olddatetime(size_t column_ndx, OldDateTime value) const
1363 {
1364     REALM_ASSERT_COLUMN_AND_TYPE(column_ndx, type_OldDateTime);
1365     return find_all_integer(column_ndx, int64_t(value.get_olddatetime()));
1366 }
1367
1368
1369 // Rows
1370
1371
1372 inline TableView::RowExpr TableView::get(size_t row_ndx) noexcept
1373 {
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));
1378 }
1379
1380 inline TableView::ConstRowExpr TableView::get(size_t row_ndx) const noexcept
1381 {
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));
1386 }
1387
1388 inline ConstTableView::ConstRowExpr ConstTableView::get(size_t row_ndx) const noexcept
1389 {
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));
1394 }
1395
1396 inline TableView::RowExpr TableView::front() noexcept
1397 {
1398     return get(0);
1399 }
1400
1401 inline TableView::ConstRowExpr TableView::front() const noexcept
1402 {
1403     return get(0);
1404 }
1405
1406 inline ConstTableView::ConstRowExpr ConstTableView::front() const noexcept
1407 {
1408     return get(0);
1409 }
1410
1411 inline TableView::RowExpr TableView::back() noexcept
1412 {
1413     size_t last_row_ndx = size() - 1;
1414     return get(last_row_ndx);
1415 }
1416
1417 inline TableView::ConstRowExpr TableView::back() const noexcept
1418 {
1419     size_t last_row_ndx = size() - 1;
1420     return get(last_row_ndx);
1421 }
1422
1423 inline ConstTableView::ConstRowExpr ConstTableView::back() const noexcept
1424 {
1425     size_t last_row_ndx = size() - 1;
1426     return get(last_row_ndx);
1427 }
1428
1429 inline TableView::RowExpr TableView::operator[](size_t row_ndx) noexcept
1430 {
1431     return get(row_ndx);
1432 }
1433
1434 inline TableView::ConstRowExpr TableView::operator[](size_t row_ndx) const noexcept
1435 {
1436     return get(row_ndx);
1437 }
1438
1439 inline ConstTableView::ConstRowExpr ConstTableView::operator[](size_t row_ndx) const noexcept
1440 {
1441     return get(row_ndx);
1442 }
1443
1444
1445 // Subtables
1446
1447
1448 inline TableRef TableView::get_subtable(size_t column_ndx, size_t row_ndx)
1449 {
1450     REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1451
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));
1455 }
1456
1457 inline ConstTableRef TableView::get_subtable(size_t column_ndx, size_t row_ndx) const
1458 {
1459     REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1460
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));
1464 }
1465
1466 inline ConstTableRef ConstTableView::get_subtable(size_t column_ndx, size_t row_ndx) const
1467 {
1468     REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1469
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));
1473 }
1474
1475 inline void TableView::clear_subtable(size_t column_ndx, size_t row_ndx)
1476 {
1477     REALM_ASSERT_INDEX_AND_TYPE_TABLE_OR_MIXED(column_ndx, row_ndx);
1478
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));
1482 }
1483
1484
1485 // Setters
1486
1487
1488 inline void TableView::set_int(size_t column_ndx, size_t row_ndx, int64_t value)
1489 {
1490     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Int);
1491
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);
1495 }
1496
1497 inline void TableView::set_bool(size_t column_ndx, size_t row_ndx, bool value)
1498 {
1499     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Bool);
1500
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);
1504 }
1505
1506 inline void TableView::set_olddatetime(size_t column_ndx, size_t row_ndx, OldDateTime value)
1507 {
1508     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_OldDateTime);
1509
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);
1513 }
1514
1515 inline void TableView::set_timestamp(size_t column_ndx, size_t row_ndx, Timestamp value)
1516 {
1517     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Timestamp);
1518
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);
1522 }
1523
1524 inline void TableView::set_float(size_t column_ndx, size_t row_ndx, float value)
1525 {
1526     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Float);
1527
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);
1531 }
1532
1533 inline void TableView::set_double(size_t column_ndx, size_t row_ndx, double value)
1534 {
1535     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Double);
1536
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);
1540 }
1541
1542 template <class E>
1543 inline void TableView::set_enum(size_t column_ndx, size_t row_ndx, E value)
1544 {
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);
1548 }
1549
1550 inline void TableView::set_string(size_t column_ndx, size_t row_ndx, StringData value)
1551 {
1552     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_String);
1553
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);
1557 }
1558
1559 inline void TableView::set_binary(size_t column_ndx, size_t row_ndx, BinaryData value)
1560 {
1561     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Binary);
1562
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);
1566 }
1567
1568 inline void TableView::set_mixed(size_t column_ndx, size_t row_ndx, Mixed value)
1569 {
1570     REALM_ASSERT_INDEX_AND_TYPE(column_ndx, row_ndx, type_Mixed);
1571
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);
1575 }
1576
1577 inline void TableView::set_subtable(size_t column_ndx, size_t row_ndx, const Table* value)
1578 {
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);
1583 }
1584
1585 inline void TableView::set_link(size_t column_ndx, size_t row_ndx, size_t target_row_ndx)
1586 {
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);
1591 }
1592
1593 inline void TableView::nullify_link(size_t column_ndx, size_t row_ndx)
1594 {
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));
1599 }
1600
1601 } // namespace realm
1602
1603 #endif // REALM_TABLE_VIEW_HPP