#pragma once #include #include "Runtime/IFactory.hpp" #include "Runtime/IObj.hpp" #include "Runtime/IObjectStore.hpp" #include "Runtime/IVParamObj.hpp" #include "Runtime/RetroTypes.hpp" namespace metaforce { class IObjectStore; /** Shared data-structure for CToken references, analogous to std::shared_ptr */ class CObjectReference { friend class CSimplePool; friend class CToken; u16 x0_refCount = 0; u16 x2_lockCount = 0; bool x3_loading = false; /* Rightmost bit of lockCount */ SObjectTag x4_objTag; IObjectStore* xC_objectStore = nullptr; std::unique_ptr x10_object; CVParamTransfer x14_params; /** Mechanism by which CToken decrements 1st ref-count, indicating CToken invalidation or reset. * Reaching 0 indicates the CToken should delete the CObjectReference */ u16 RemoveReference(); CObjectReference(IObjectStore& objStore, std::unique_ptr&& obj, const SObjectTag& objTag, CVParamTransfer buildParams); CObjectReference(std::unique_ptr&& obj); /** Indicates an asynchronous load transaction has been submitted and is not yet finished */ bool IsLoading() const { return x3_loading; } /** Indicates an asynchronous load transaction has finished and object is completely loaded */ bool IsLoaded() const { return x10_object.operator bool(); } /** Decrements 2nd ref-count, performing unload or async-load-cancel if 0 reached */ void Unlock(); /** Increments 2nd ref-count, performing async-factory-load if needed */ void Lock(); void CancelLoad(); /** Pointer-synchronized object-destructor, another building Lock cycle may be performed after */ void Unload(); /** Synchronous object-fetch, guaranteed to return complete object on-demand, blocking build if not ready */ IObj* GetObject(); public: const SObjectTag& GetObjectTag() const { return x4_objTag; } ~CObjectReference(); }; /** Counted meta-object, reference-counting against a shared CObjectReference * This class is analogous to std::shared_ptr and C++11 rvalues have been implemented accordingly * (default/empty constructor, move constructor/assign) */ class CToken { friend class CModel; friend class CSimplePool; CObjectReference* x0_objRef = nullptr; bool x4_lockHeld = false; void RemoveRef(); CToken(CObjectReference* obj); public: /* Added to test for non-null state */ explicit operator bool() const { return HasReference(); } bool HasReference() const { return x0_objRef != nullptr; } void Unlock(); void Lock(); bool IsLocked() const { return x4_lockHeld; } bool IsLoaded() const; IObj* GetObj(); const IObj* GetObj() const { return const_cast(this)->GetObj(); } CToken& operator=(const CToken& other); CToken& operator=(CToken&& other) noexcept; CToken() = default; CToken(const CToken& other); CToken(CToken&& other) noexcept; CToken(IObj* obj); CToken(std::unique_ptr&& obj); const SObjectTag* GetObjectTag() const; ~CToken(); }; template class TToken : public CToken { public: static std::unique_ptr> GetIObjObjectFor(std::unique_ptr&& obj) { return TObjOwnerDerivedFromIObj::GetNewDerivedObject(std::move(obj)); } TToken() = default; virtual ~TToken() = default; TToken(const CToken& other) : CToken(other) {} TToken(CToken&& other) : CToken(std::move(other)) {} TToken(std::unique_ptr&& obj) : CToken(GetIObjObjectFor(std::move(obj))) {} TToken& operator=(std::unique_ptr&& obj) { *this = CToken(GetIObjObjectFor(std::move(obj))); return *this; } virtual void Unlock() { CToken::Unlock(); } virtual void Lock() { CToken::Lock(); } virtual T* GetObj() { TObjOwnerDerivedFromIObj* owner = static_cast*>(CToken::GetObj()); if (owner) return owner->GetObj(); return nullptr; } virtual const T* GetObj() const { return const_cast*>(this)->GetObj(); } virtual TToken& operator=(const CToken& other) { CToken::operator=(other); return *this; } T* operator->() { return GetObj(); } const T* operator->() const { return GetObj(); } T& operator*() { return *GetObj(); } const T& operator*() const { return *GetObj(); } }; template class TCachedToken : public TToken { protected: T* m_obj = nullptr; public: TCachedToken() = default; TCachedToken(const CToken& other) : TToken(other) {} TCachedToken(CToken&& other) : TToken(std::move(other)) {} T* GetObj() override { if (!m_obj) m_obj = TToken::GetObj(); return m_obj; } const T* GetObj() const override { return const_cast*>(this)->GetObj(); } void Unlock() override { TToken::Unlock(); m_obj = nullptr; } TCachedToken& operator=(const TCachedToken& other) { TToken::operator=(other); m_obj = nullptr; return *this; } TCachedToken& operator=(const CToken& other) override { TToken::operator=(other); m_obj = nullptr; return *this; } bool IsNull() const { return m_obj == nullptr; } }; template class TLockedToken : public TCachedToken { public: TLockedToken() = default; TLockedToken(const TLockedToken& other) : TCachedToken(other) { CToken::Lock(); } TLockedToken& operator=(const TLockedToken& other) { CToken oldTok = std::move(*this); TCachedToken::operator=(other); CToken::Lock(); return *this; } TLockedToken(const CToken& other) : TCachedToken(other) { CToken::Lock(); } TLockedToken& operator=(const CToken& other) override { CToken oldTok = std::move(*this); TCachedToken::operator=(other); CToken::Lock(); return *this; } TLockedToken(CToken&& other) { CToken oldTok = std::move(*this); *this = TCachedToken(std::move(other)); CToken::Lock(); } }; } // namespace metaforce