aboutsummaryrefslogtreecommitdiff
path: root/include/cru/common
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2024-01-01 22:20:21 +0800
committercrupest <crupest@outlook.com>2024-01-27 01:02:14 +0800
commit8673907e4e3f2f9ff6e8bd18aaf3ddc6d84c0e64 (patch)
treedaa8acf69dbf57f47deaba816961e377399a6f38 /include/cru/common
parente96f5b6713814dd59814f17cb9bb437e3a6fca47 (diff)
downloadcru-8673907e4e3f2f9ff6e8bd18aaf3ddc6d84c0e64.tar.gz
cru-8673907e4e3f2f9ff6e8bd18aaf3ddc6d84c0e64.tar.bz2
cru-8673907e4e3f2f9ff6e8bd18aaf3ddc6d84c0e64.zip
NEED TEST: add support for pointer conversion in ObjectResolver.
Diffstat (limited to 'include/cru/common')
-rw-r--r--include/cru/common/Event2.h30
-rw-r--r--include/cru/common/SelfResolvable.h67
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_;
};
/**