diff options
Diffstat (limited to 'include/cru/common/event.hpp')
-rw-r--r-- | include/cru/common/event.hpp | 127 |
1 files changed, 86 insertions, 41 deletions
diff --git a/include/cru/common/event.hpp b/include/cru/common/event.hpp index 6228d867..987bcdd6 100644 --- a/include/cru/common/event.hpp +++ b/include/cru/common/event.hpp @@ -2,73 +2,102 @@ #include "base.hpp" #include <functional> +#include <list> #include <map> #include <memory> #include <utility> namespace cru { -using EventHandlerRevoker = std::function<void()>; +class EventRevoker; + +namespace details { +class EventBase { + friend EventRevoker; + + protected: + using EventHandlerToken = long; + + EventBase() : resolve_ptr_(new std::reference_wrapper(*this)) {} + + EventBase(const EventBase& other) = delete; + EventBase(EventBase&& other) = delete; + EventBase& operator=(const EventBase& other) = delete; + EventBase& operator=(EventBase&& other) = delete; + virtual ~EventBase() = default; + + virtual void RemoveHandler(EventHandlerToken token) = 0; + + inline EventRevoker CreateRevoker(EventHandlerToken token); + + private: + std::shared_ptr<std::reference_wrapper<EventBase>> resolve_ptr_; +}; +} // namespace details + +class EventRevoker { + friend class ::cru::details::EventBase; -// A non-copyable non-movable Event class. -// It stores a list of event handlers. -template <typename... TArgs> -class Event { private: - using EventResolver = std::function<Event*()>; - class EventHandlerRevokerImpl { - public: - EventHandlerRevokerImpl(const std::shared_ptr<EventResolver>& resolver, - long token) - : resolver_(resolver), token_(token) {} - EventHandlerRevokerImpl(const EventHandlerRevokerImpl& other) = default; - EventHandlerRevokerImpl(EventHandlerRevokerImpl&& other) = default; - EventHandlerRevokerImpl& operator=(const EventHandlerRevokerImpl& other) = - default; - EventHandlerRevokerImpl& operator=(EventHandlerRevokerImpl&& other) = - default; - ~EventHandlerRevokerImpl() = default; - - void operator()() { - const auto true_resolver = resolver_.lock(); - if (true_resolver) { - (*true_resolver)()->RemoveHandler(token_); - } + EventRevoker(const std::shared_ptr< + std::reference_wrapper<details::EventBase>>& resolve_ptr, + details::EventBase::EventHandlerToken token) + : weak_ptr_(resolve_ptr), token_(token) {} + + public: + EventRevoker(const EventRevoker& other) = default; + EventRevoker(EventRevoker&& other) = default; + EventRevoker& operator=(const EventRevoker& other) = default; + EventRevoker& operator=(EventRevoker&& other) = default; + ~EventRevoker() = default; + + void operator()() const { + const auto true_resolver = weak_ptr_.lock(); + if (true_resolver) { + (*true_resolver).get().RemoveHandler(token_); } + } + + private: + std::weak_ptr<std::reference_wrapper<details::EventBase>> weak_ptr_; + details::EventBase::EventHandlerToken token_; +}; - private: - std::weak_ptr<EventResolver> resolver_; - long token_; - }; +inline EventRevoker details::EventBase::CreateRevoker(EventHandlerToken token) { + return EventRevoker(resolve_ptr_, token); +} +// A non-copyable non-movable Event class. +// It stores a list of event handlers. +template <typename... TArgs> +class Event : public details::EventBase { public: using EventHandler = std::function<void(TArgs...)>; - Event() - : event_resolver_(new std::function<Event*()>([this] { return this; })) {} + Event() = default; Event(const Event&) = delete; Event& operator=(const Event&) = delete; Event(Event&&) = delete; Event& operator=(Event&&) = delete; ~Event() = default; - EventHandlerRevoker AddHandler(const EventHandler& handler) { + EventRevoker AddHandler(const EventHandler& handler) { const auto token = current_token_++; handlers_.emplace(token, handler); - return EventHandlerRevoker(EventHandlerRevokerImpl(event_resolver_, token)); + return CreateRevoker(token); } - EventHandlerRevoker AddHandler(EventHandler&& handler) { + EventRevoker AddHandler(EventHandler&& handler) { const auto token = current_token_++; handlers_.emplace(token, std::move(handler)); - return EventHandlerRevoker(EventHandlerRevokerImpl(event_resolver_, token)); + return CreateRevoker(token); } template <typename Arg> - EventHandlerRevoker AddHandler(Arg&& handler) { + EventRevoker AddHandler(Arg&& handler) { static_assert(std::is_invocable_v<Arg, TArgs...>, "Handler not invocable."); const auto token = current_token_++; handlers_.emplace(token, EventHandler(std::forward<Arg>(handler))); - return EventHandlerRevoker(EventHandlerRevokerImpl(event_resolver_, token)); + return CreateRevoker(token); } template <typename... Args> @@ -77,15 +106,31 @@ class Event { (handler.second)(std::forward<Args>(args)...); } - private: - void RemoveHandler(const long token) { + protected: + void RemoveHandler(EventHandlerToken token) override { auto find_result = handlers_.find(token); if (find_result != handlers_.cend()) handlers_.erase(find_result); } private: - std::map<long, EventHandler> handlers_{}; - long current_token_ = 0; - std::shared_ptr<EventResolver> event_resolver_; + std::map<EventHandlerToken, EventHandler> handlers_{}; + EventHandlerToken current_token_ = 0; +}; + +class EventRevokerGuard { + public: + EventRevokerGuard() = default; + EventRevokerGuard(const EventRevokerGuard& other) = delete; + EventRevokerGuard(EventRevokerGuard&& other) = delete; + EventRevokerGuard& operator=(const EventRevokerGuard& other) = delete; + EventRevokerGuard& operator=(EventRevokerGuard&& other) = delete; + ~EventRevokerGuard() { + for (const auto revoker : revokers_) revoker(); + } + + void Add(EventRevoker revoker) { revokers_.push_back(std::move(revoker)); } + + private: + std::list<EventRevoker> revokers_; }; } // namespace cru |