diff options
-rw-r--r-- | include/cru/common/Event2.h | 30 | ||||
-rw-r--r-- | include/cru/common/SelfResolvable.h | 67 |
2 files changed, 82 insertions, 15 deletions
diff --git a/include/cru/common/Event2.h b/include/cru/common/Event2.h index 5677828a..62fb366d 100644 --- a/include/cru/common/Event2.h +++ b/include/cru/common/Event2.h @@ -10,6 +10,13 @@ #include <vector> namespace cru { +class Event2Base { + public: + virtual ~Event2Base() = default; + + virtual void RevokeHandler(int token_value) = 0; +}; + template <typename TArgument, typename TResult> class EventContext { public: @@ -46,20 +53,19 @@ constexpr bool is_event2_v = false; template <typename TArgument, typename TResult> constexpr bool is_event2_v<Event2<TArgument, TResult>> = true; -template <typename TEvent2> class EventHandlerToken { - static_assert(is_event2_v<TEvent2>, "TEvent2 must be Event2 class."); - public: - EventHandlerToken(ObjectResolver<TEvent2> event_resolver, int token_value) + EventHandlerToken(ObjectResolver<Event2Base> event_resolver, int token_value) : event_resolver_(std::move(event_resolver)), token_value_(token_value) {} - ObjectResolver<TEvent2> GetEventResolver() const { return event_resolver_; } + ObjectResolver<Event2Base> GetEventResolver() const { + return event_resolver_; + } int GetTokenValue() const { return token_value_; } - void RevokeHandler() const; + inline void RevokeHandler() const; private: - ObjectResolver<TEvent2> event_resolver_; + ObjectResolver<Event2Base> event_resolver_; int token_value_; }; @@ -79,9 +85,10 @@ struct Event2BehaviorFlags { template <typename TArgument = std::nullptr_t, typename TResult = std::nullptr_t> -class Event2 : public SelfResolvable<Event2<TArgument, TResult>> { +class Event2 : public Event2Base, + public SelfResolvable<Event2<TArgument, TResult>> { public: - using HandlerToken = EventHandlerToken<Event2>; + using HandlerToken = EventHandlerToken; using Context = EventContext<TArgument, TResult>; using Handler = std::function<void(Context*)>; using SpyOnlyHandler = std::function<void()>; @@ -122,7 +129,7 @@ class Event2 : public SelfResolvable<Event2<TArgument, TResult>> { return HandlerToken(this->CreateResolver(), token); } - void RevokeHandler(int token_value) { + void RevokeHandler(int token_value) override { auto iter = this->handlers_.cbegin(); auto end = this->handlers_.cend(); for (; iter != end; ++iter) { @@ -184,8 +191,7 @@ class Event2 : public SelfResolvable<Event2<TArgument, TResult>> { Event2BehaviorFlag flags_; }; -template <typename TEvent2> -void EventHandlerToken<TEvent2>::RevokeHandler() const { +inline void EventHandlerToken::RevokeHandler() const { auto event = this->event_resolver_.Resolve(); if (event) { event->RevokeHandler(this->token_value_); diff --git a/include/cru/common/SelfResolvable.h b/include/cru/common/SelfResolvable.h index ce5b1628..84fa54f6 100644 --- a/include/cru/common/SelfResolvable.h +++ b/include/cru/common/SelfResolvable.h @@ -1,7 +1,9 @@ #pragma once #include <cassert> +#include <functional> #include <memory> +#include <type_traits> namespace cru { template <typename T> @@ -10,22 +12,74 @@ class SelfResolvable; template <typename T> class ObjectResolver { friend SelfResolvable<T>; + template <typename U> + friend class ObjectResolver; private: - explicit ObjectResolver(T* o) : shared_object_ptr_(new T*(o)) {} + template <typename U> + using Accessor_ = std::function<U*(const std::shared_ptr<void*>&)>; + using ThisAccessor_ = Accessor_<T>; + + explicit ObjectResolver(T* o) + : shared_object_ptr_(new void*(o)), + accessor_([](const std::shared_ptr<void*>& ptr) { + return static_cast<T*>(*ptr); + }) {} + explicit ObjectResolver(std::shared_ptr<void*> ptr, ThisAccessor_ accessor) + : shared_object_ptr_(std::move(ptr)), accessor_(std::move(accessor)) {} + + template <typename U> + static ThisAccessor_ CreateAccessor(Accessor_<U> parent_accessor) { + return [parent_accessor = + std::move(parent_accessor)](const std::shared_ptr<void*>& ptr) { + return static_cast<T*>(parent_accessor(ptr)); + }; + } public: + template <typename U, + typename = std::enable_if_t<std::is_convertible_v<U*, T*>>> + ObjectResolver(const ObjectResolver<U>& other) + : shared_object_ptr_(other.shared_object_ptr_), + accessor_(CreateAccessor(other.accessor_)) {} + + template <typename U, + typename = std::enable_if_t<std::is_convertible_v<U*, T*>>> + ObjectResolver(ObjectResolver<U>&& other) + : shared_object_ptr_(std::move(other.shared_object_ptr_)), + accessor_(CreateAccessor(std::move(other.accessor_))) {} + ObjectResolver(const ObjectResolver&) = default; ObjectResolver& operator=(const ObjectResolver&) = default; ObjectResolver(ObjectResolver&&) = default; ObjectResolver& operator=(ObjectResolver&&) = default; ~ObjectResolver() = default; + template <typename U, + typename = std::enable_if_t<std::is_convertible_v<U*, T*>>> + ObjectResolver& operator=(const ObjectResolver<U>& other) { + if (this != &other) { + this->shared_object_ptr_ = other.shared_object_ptr_; + this->accessor_ = CreateAccessor(other.accessor_); + } + return *this; + } + + template <typename U, + typename = std::enable_if_t<std::is_convertible_v<U*, T*>>> + ObjectResolver& operator=(ObjectResolver<U>&& other) { + if (this != &other) { + this->shared_object_ptr_ = std::move(other.shared_object_ptr_); + this->accessor_ = CreateAccessor(std::move(other.shared_object_ptr_)); + } + return *this; + } + bool IsValid() const { return this->shared_object_ptr_ != nullptr; } T* Resolve() const { assert(IsValid()); - return *this->shared_object_ptr_; + return this->accessor_(this->shared_object_ptr_); } /** @@ -33,6 +87,12 @@ class ObjectResolver { */ T* operator()() const { return Resolve(); } + template <typename U, + typename = std::enable_if_t<std::is_convertible_v<T*, U*>>> + operator ObjectResolver<U>() const { + return ObjectResolver<U>(*this); + } + private: void SetResolvedObject(T* o) { assert(IsValid()); @@ -40,7 +100,8 @@ class ObjectResolver { } private: - std::shared_ptr<T*> shared_object_ptr_; + std::shared_ptr<void*> shared_object_ptr_; + std::function<T*(const std::shared_ptr<void*>&)> accessor_; }; /** |