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_COLLECTION_NOTIFICATIONS_HPP
20 #define REALM_COLLECTION_NOTIFICATIONS_HPP
22 #include "index_set.hpp"
23 #include "util/atomic_shared_ptr.hpp"
27 #include <type_traits>
32 class CollectionNotifier;
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);
41 NotificationToken(NotificationToken&&);
42 NotificationToken& operator=(NotificationToken&&);
44 NotificationToken(NotificationToken const&) = delete;
45 NotificationToken& operator=(NotificationToken const&) = delete;
50 util::AtomicSharedPtr<_impl::CollectionNotifier> m_notifier;
54 struct CollectionChangeSet {
59 bool operator==(Move m) const noexcept { return from == m.from && to == m.to; }
62 // Indices which were removed from the _old_ collection
65 // Indices in the _new_ collection which are new insertions
68 // Indices of objects in the _old_ collection which were modified
69 IndexSet modifications;
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;
78 // Rows in the collection which moved.
80 // Every `from` index will also be present in `deletions` and every `to`
81 // index will be present in `insertions`.
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;
88 // Per-column version of `modifications`
89 std::vector<IndexSet> columns;
91 bool empty() const noexcept
93 return deletions.empty() && insertions.empty() && modifications.empty()
94 && modifications_new.empty() && moves.empty();
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 {
107 CollectionChangeCallback(std::nullptr_t={}) { }
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; }
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;
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); }
125 explicit operator bool() const { return !!m_impl; }
129 virtual void before(CollectionChangeSet const&)=0;
130 virtual void after(CollectionChangeSet const&)=0;
131 virtual void error(std::exception_ptr)=0;
134 template<typename Callback, typename = decltype(std::declval<Callback>()(CollectionChangeSet(), std::exception_ptr()))>
135 std::shared_ptr<Base> make_impl(Callback cb)
137 return std::make_shared<Impl<Callback>>(std::move(cb));
140 template<typename Callback, typename = decltype(std::declval<Callback>().after(CollectionChangeSet())), typename = void>
141 std::shared_ptr<Base> make_impl(Callback cb)
143 return std::make_shared<Impl2<Callback>>(std::move(cb));
146 template<typename Callback, typename = decltype(std::declval<Callback>().after(CollectionChangeSet())), typename = void>
147 std::shared_ptr<Base> make_impl(Callback* cb)
149 return std::make_shared<Impl3<Callback>>(cb);
153 struct Impl : public Base {
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); }
161 struct Impl2 : public Base {
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); }
169 struct Impl3 : public Base {
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); }
177 std::shared_ptr<Base> m_impl;
181 #endif // REALM_COLLECTION_NOTIFICATIONS_HPP