From c9f31440d65a867e2316e9a19ee3f5db2d0e53a7 Mon Sep 17 00:00:00 2001 From: Yuqian Yang Date: Mon, 17 Nov 2025 13:31:04 +0800 Subject: Revert removing SelfResolvable. --- include/cru/base/SelfResolvable.h | 153 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 include/cru/base/SelfResolvable.h (limited to 'include/cru/base/SelfResolvable.h') diff --git a/include/cru/base/SelfResolvable.h b/include/cru/base/SelfResolvable.h new file mode 100644 index 00000000..84fa54f6 --- /dev/null +++ b/include/cru/base/SelfResolvable.h @@ -0,0 +1,153 @@ +#pragma once + +#include +#include +#include +#include + +namespace cru { +template +class SelfResolvable; + +template +class ObjectResolver { + friend SelfResolvable; + template + friend class ObjectResolver; + + private: + template + using Accessor_ = std::function&)>; + using ThisAccessor_ = Accessor_; + + explicit ObjectResolver(T* o) + : shared_object_ptr_(new void*(o)), + accessor_([](const std::shared_ptr& ptr) { + return static_cast(*ptr); + }) {} + explicit ObjectResolver(std::shared_ptr ptr, ThisAccessor_ accessor) + : shared_object_ptr_(std::move(ptr)), accessor_(std::move(accessor)) {} + + template + static ThisAccessor_ CreateAccessor(Accessor_ parent_accessor) { + return [parent_accessor = + std::move(parent_accessor)](const std::shared_ptr& ptr) { + return static_cast(parent_accessor(ptr)); + }; + } + + public: + template >> + ObjectResolver(const ObjectResolver& other) + : shared_object_ptr_(other.shared_object_ptr_), + accessor_(CreateAccessor(other.accessor_)) {} + + template >> + ObjectResolver(ObjectResolver&& 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 >> + ObjectResolver& operator=(const ObjectResolver& other) { + if (this != &other) { + this->shared_object_ptr_ = other.shared_object_ptr_; + this->accessor_ = CreateAccessor(other.accessor_); + } + return *this; + } + + template >> + ObjectResolver& operator=(ObjectResolver&& 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->accessor_(this->shared_object_ptr_); + } + + /** + * @remarks So this class can be used as a functor. + */ + T* operator()() const { return Resolve(); } + + template >> + operator ObjectResolver() const { + return ObjectResolver(*this); + } + + private: + void SetResolvedObject(T* o) { + assert(IsValid()); + *this->shared_object_ptr_ = o; + } + + private: + std::shared_ptr shared_object_ptr_; + std::function&)> accessor_; +}; + +/** + * @remarks + * This class is not copyable and movable since subclass is polymorphic and + * copying is then nonsense. However, you can even delete move capability in + * subclass because it may also be nonsense for subclass. The move capability is + * optional. + * + * Whether this class needs to be thread-safe still has to be considered. + */ +template +class SelfResolvable { + public: + SelfResolvable() : resolver_(CastToSubClass()) {} + SelfResolvable(const SelfResolvable&) = delete; + SelfResolvable& operator=(const SelfResolvable&) = delete; + + // Resolvers to old object will resolve to new object. + SelfResolvable(SelfResolvable&& other) + : resolver_(std::move(other.resolver_)) { + this->resolver_.SetResolvedObject(CastToSubClass()); + } + + // Old resolvers for this object will resolve to nullptr. + // Other's resolvers will now resolve to this. + SelfResolvable& operator=(SelfResolvable&& other) { + if (this != &other) { + this->resolver_ = std::move(other.resolver_); + this->resolver_.SetResolvedObject(CastToSubClass()); + } + return *this; + } + + virtual ~SelfResolvable() { + if (this->resolver_.IsValid()) { + this->resolver_.SetResolvedObject(nullptr); + } + } + + ObjectResolver CreateResolver() { return resolver_; } + + private: + T* CastToSubClass() { return static_cast(this); } + + private: + ObjectResolver resolver_; +}; +} // namespace cru -- cgit v1.2.3