#pragma once #include "Base.h" #include #include #include namespace cru { template class SelfResolvable; template class ObjectResolver { friend SelfResolvable; template friend class ObjectResolver; private: explicit ObjectResolver(std::shared_ptr destroyed, T* ptr) : destroyed_(std::move(destroyed)), ptr_(ptr) {} public: CRU_DEFAULT_COPY(ObjectResolver) CRU_DEFAULT_MOVE(ObjectResolver) template ObjectResolver(const ObjectResolver& other) requires(std::is_convertible_v) : destroyed_(other.destroyed_), ptr_(static_cast(other.ptr_)) {} template ObjectResolver(ObjectResolver&& other) requires(std::is_convertible_v) : destroyed_(std::move(other.destroyed_)), ptr_(static_cast(other.ptr_)) {} template ObjectResolver& operator=(const ObjectResolver& other) requires(std::is_convertible_v) { if (this != &other) { this->destroyed_ = other.destroyed_; this->ptr_ = static_cast(other.ptr_); } return *this; } template ObjectResolver& operator=(ObjectResolver&& other) requires(std::is_convertible_v) { if (this != &other) { this->destroyed_ = std::move(other.destroyed_); this->ptr_ = static_cast(other.ptr_); } return *this; } bool IsValid() const { return this->destroyed_ != nullptr; } T* Resolve() const { assert(IsValid()); return *destroyed_ ? nullptr : ptr_; } /** * @remarks So this class can be used as a functor. */ T* operator()() const { return Resolve(); } template operator ObjectResolver() const requires(std::is_convertible_v) { return ObjectResolver(*this); } private: std::shared_ptr destroyed_; T* ptr_; }; /** * Currently the implementation is NOT thread-safe. */ template class SelfResolvable { public: SelfResolvable() : destroyed_(new bool(false)) {} CRU_DELETE_COPY(SelfResolvable) virtual ~SelfResolvable() { *destroyed_ = true; } ObjectResolver CreateResolver() { return ObjectResolver(destroyed_, static_cast(this)); } private: std::shared_ptr destroyed_; }; } // namespace cru