added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / collection_notifications.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_COLLECTION_NOTIFICATIONS_HPP
20 #define REALM_COLLECTION_NOTIFICATIONS_HPP
21
22 #include "index_set.hpp"
23 #include "util/atomic_shared_ptr.hpp"
24
25 #include <exception>
26 #include <memory>
27 #include <type_traits>
28 #include <vector>
29
30 namespace realm {
31 namespace _impl {
32     class CollectionNotifier;
33 }
34
35 // A token which keeps an asynchronous query alive
36 struct NotificationToken {
37     NotificationToken() = default;
38     NotificationToken(std::shared_ptr<_impl::CollectionNotifier> notifier, uint64_t token);
39     ~NotificationToken();
40
41     NotificationToken(NotificationToken&&);
42     NotificationToken& operator=(NotificationToken&&);
43
44     NotificationToken(NotificationToken const&) = delete;
45     NotificationToken& operator=(NotificationToken const&) = delete;
46
47     void suppress_next();
48
49 private:
50     util::AtomicSharedPtr<_impl::CollectionNotifier> m_notifier;
51     uint64_t m_token;
52 };
53
54 struct CollectionChangeSet {
55     struct Move {
56         size_t from;
57         size_t to;
58
59         bool operator==(Move m) const noexcept { return from == m.from && to == m.to; }
60     };
61
62     // Indices which were removed from the _old_ collection
63     IndexSet deletions;
64
65     // Indices in the _new_ collection which are new insertions
66     IndexSet insertions;
67
68     // Indices of objects in the _old_ collection which were modified
69     IndexSet modifications;
70
71     // Indices in the _new_ collection which were modified. This will always
72     // have the same number of indices as `modifications` and conceptually
73     // represents the same entries, just in different versions of the collection.
74     // It exists for the sake of code which finds it easier to process
75     // modifications after processing deletions and insertions rather than before.
76     IndexSet modifications_new;
77
78     // Rows in the collection which moved.
79     //
80     // Every `from` index will also be present in `deletions` and every `to`
81     // index will be present in `insertions`.
82     //
83     // This is currently not reliably calculated for all types of collections. A
84     // reported move will always actually be a move, but there may also be
85     // unreported moves which show up only as a delete/insert pair.
86     std::vector<Move> moves;
87
88     // Per-column version of `modifications`
89     std::vector<IndexSet> columns;
90
91     bool empty() const noexcept
92     {
93         return deletions.empty() && insertions.empty() && modifications.empty()
94             && modifications_new.empty() && moves.empty();
95     }
96 };
97
98 // A type-erasing wrapper for the callback for collection notifications. Can be
99 // constructed with either any callable compatible with the signature
100 // `void (CollectionChangeSet, std::exception_ptr)`, an object with member
101 // functions `void before(CollectionChangeSet)`, `void after(CollectionChangeSet)`,
102 // `void error(std::exception_ptr)`, or a pointer to such an object. If a pointer
103 // is given, the caller is responsible for ensuring that the pointed-to object
104 // outlives the collection.
105 class CollectionChangeCallback {
106 public:
107     CollectionChangeCallback(std::nullptr_t={}) { }
108
109     template<typename Callback>
110     CollectionChangeCallback(Callback cb) : m_impl(make_impl(std::move(cb))) { }
111     template<typename Callback>
112     CollectionChangeCallback& operator=(Callback cb) { m_impl = make_impl(std::move(cb)); return *this; }
113
114     // Explicitly default the copy/move constructors as otherwise they'll use
115     // the above ones and add an extra layer of wrapping
116     CollectionChangeCallback(CollectionChangeCallback&&) = default;
117     CollectionChangeCallback(CollectionChangeCallback const&) = default;
118     CollectionChangeCallback& operator=(CollectionChangeCallback&&) = default;
119     CollectionChangeCallback& operator=(CollectionChangeCallback const&) = default;
120
121     void before(CollectionChangeSet const& c) { m_impl->before(c); }
122     void after(CollectionChangeSet const& c) { m_impl->after(c); }
123     void error(std::exception_ptr e) { m_impl->error(e); }
124
125     explicit operator bool() const { return !!m_impl; }
126
127 private:
128     struct Base {
129         virtual void before(CollectionChangeSet const&)=0;
130         virtual void after(CollectionChangeSet const&)=0;
131         virtual void error(std::exception_ptr)=0;
132     };
133
134     template<typename Callback, typename = decltype(std::declval<Callback>()(CollectionChangeSet(), std::exception_ptr()))>
135     std::shared_ptr<Base> make_impl(Callback cb)
136     {
137         return std::make_shared<Impl<Callback>>(std::move(cb));
138     }
139
140     template<typename Callback, typename = decltype(std::declval<Callback>().after(CollectionChangeSet())), typename = void>
141     std::shared_ptr<Base> make_impl(Callback cb)
142     {
143         return std::make_shared<Impl2<Callback>>(std::move(cb));
144     }
145
146     template<typename Callback, typename = decltype(std::declval<Callback>().after(CollectionChangeSet())), typename = void>
147     std::shared_ptr<Base> make_impl(Callback* cb)
148     {
149         return std::make_shared<Impl3<Callback>>(cb);
150     }
151
152     template<typename T>
153     struct Impl : public Base {
154         T impl;
155         Impl(T impl) : impl(std::move(impl)) { }
156         void before(CollectionChangeSet const&) override { }
157         void after(CollectionChangeSet const& change) override { impl(change, {}); }
158         void error(std::exception_ptr error) override { impl({}, error); }
159     };
160     template<typename T>
161     struct Impl2 : public Base {
162         T impl;
163         Impl2(T impl) : impl(std::move(impl)) { }
164         void before(CollectionChangeSet const& c) override { impl.before(c); }
165         void after(CollectionChangeSet const& c) override { impl.after(c); }
166         void error(std::exception_ptr error) override { impl.error(error); }
167     };
168     template<typename T>
169     struct Impl3 : public Base {
170         T* impl;
171         Impl3(T* impl) : impl(impl) { }
172         void before(CollectionChangeSet const& c) override { impl->before(c); }
173         void after(CollectionChangeSet const& c) override { impl->after(c); }
174         void error(std::exception_ptr error) override { impl->error(error); }
175     };
176
177     std::shared_ptr<Base> m_impl;
178 };
179 } // namespace realm
180
181 #endif // REALM_COLLECTION_NOTIFICATIONS_HPP