filesbox/app/filesbox_ios/FilesBox/Pods/Realm/include/collection_notifications.hpp
2023-09-21 10:53:23 +08:00

183 lines
6.7 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#ifndef REALM_COLLECTION_NOTIFICATIONS_HPP
#define REALM_COLLECTION_NOTIFICATIONS_HPP
#include "index_set.hpp"
#include "util/atomic_shared_ptr.hpp"
#include <exception>
#include <memory>
#include <type_traits>
#include <vector>
namespace realm {
namespace _impl {
class CollectionNotifier;
}
// A token which keeps an asynchronous query alive
struct NotificationToken {
NotificationToken() = default;
NotificationToken(std::shared_ptr<_impl::CollectionNotifier> notifier, uint64_t token);
~NotificationToken();
NotificationToken(NotificationToken&&);
NotificationToken& operator=(NotificationToken&&);
NotificationToken(NotificationToken const&) = delete;
NotificationToken& operator=(NotificationToken const&) = delete;
void suppress_next();
private:
util::AtomicSharedPtr<_impl::CollectionNotifier> m_notifier;
uint64_t m_token;
};
struct CollectionChangeSet {
struct Move {
size_t from;
size_t to;
bool operator==(Move m) const noexcept { return from == m.from && to == m.to; }
};
// Indices which were removed from the _old_ collection
IndexSet deletions;
// Indices in the _new_ collection which are new insertions
IndexSet insertions;
// Indices of objects in the _old_ collection which were modified
IndexSet modifications;
// Indices in the _new_ collection which were modified. This will always
// have the same number of indices as `modifications` and conceptually
// represents the same entries, just in different versions of the collection.
// It exists for the sake of code which finds it easier to process
// modifications after processing deletions and insertions rather than before.
IndexSet modifications_new;
// Rows in the collection which moved.
//
// Every `from` index will also be present in `deletions` and every `to`
// index will be present in `insertions`.
//
// This is currently not reliably calculated for all types of collections. A
// reported move will always actually be a move, but there may also be
// unreported moves which show up only as a delete/insert pair.
std::vector<Move> moves;
// Per-column version of `modifications`
std::vector<IndexSet> columns;
bool empty() const noexcept
{
return deletions.empty() && insertions.empty() && modifications.empty()
&& modifications_new.empty() && moves.empty();
}
};
// A type-erasing wrapper for the callback for collection notifications. Can be
// constructed with either any callable compatible with the signature
// `void (CollectionChangeSet, std::exception_ptr)`, an object with member
// functions `void before(CollectionChangeSet)`, `void after(CollectionChangeSet)`,
// `void error(std::exception_ptr)`, or a pointer to such an object. If a pointer
// is given, the caller is responsible for ensuring that the pointed-to object
// outlives the collection.
class CollectionChangeCallback {
public:
CollectionChangeCallback(std::nullptr_t={}) { }
template<typename Callback>
CollectionChangeCallback(Callback cb) : m_impl(make_impl(std::move(cb))) { }
template<typename Callback>
CollectionChangeCallback& operator=(Callback cb) { m_impl = make_impl(std::move(cb)); return *this; }
// Explicitly default the copy/move constructors as otherwise they'll use
// the above ones and add an extra layer of wrapping
CollectionChangeCallback(CollectionChangeCallback&&) = default;
CollectionChangeCallback(CollectionChangeCallback const&) = default;
CollectionChangeCallback& operator=(CollectionChangeCallback&&) = default;
CollectionChangeCallback& operator=(CollectionChangeCallback const&) = default;
void before(CollectionChangeSet const& c) { m_impl->before(c); }
void after(CollectionChangeSet const& c) { m_impl->after(c); }
void error(std::exception_ptr e) { m_impl->error(e); }
explicit operator bool() const { return !!m_impl; }
private:
struct Base {
virtual ~Base() {}
virtual void before(CollectionChangeSet const&)=0;
virtual void after(CollectionChangeSet const&)=0;
virtual void error(std::exception_ptr)=0;
};
template<typename Callback, typename = decltype(std::declval<Callback>()(CollectionChangeSet(), std::exception_ptr()))>
std::shared_ptr<Base> make_impl(Callback cb)
{
return std::make_shared<Impl<Callback>>(std::move(cb));
}
template<typename Callback, typename = decltype(std::declval<Callback>().after(CollectionChangeSet())), typename = void>
std::shared_ptr<Base> make_impl(Callback cb)
{
return std::make_shared<Impl2<Callback>>(std::move(cb));
}
template<typename Callback, typename = decltype(std::declval<Callback>().after(CollectionChangeSet())), typename = void>
std::shared_ptr<Base> make_impl(Callback* cb)
{
return std::make_shared<Impl3<Callback>>(cb);
}
template<typename T>
struct Impl : public Base {
T impl;
Impl(T impl) : impl(std::move(impl)) { }
void before(CollectionChangeSet const&) override { }
void after(CollectionChangeSet const& change) override { impl(change, {}); }
void error(std::exception_ptr error) override { impl({}, error); }
};
template<typename T>
struct Impl2 : public Base {
T impl;
Impl2(T impl) : impl(std::move(impl)) { }
void before(CollectionChangeSet const& c) override { impl.before(c); }
void after(CollectionChangeSet const& c) override { impl.after(c); }
void error(std::exception_ptr error) override { impl.error(error); }
};
template<typename T>
struct Impl3 : public Base {
T* impl;
Impl3(T* impl) : impl(impl) { }
void before(CollectionChangeSet const& c) override { impl->before(c); }
void after(CollectionChangeSet const& c) override { impl->after(c); }
void error(std::exception_ptr error) override { impl->error(error); }
};
std::shared_ptr<Base> m_impl;
};
} // namespace realm
#endif // REALM_COLLECTION_NOTIFICATIONS_HPP