metaforce/Runtime/CToken.hpp

192 lines
5.8 KiB
C++

#pragma once
#include <memory>
#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<IObj> 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<IObj>&& obj, const SObjectTag& objTag,
CVParamTransfer buildParams);
CObjectReference(std::unique_ptr<IObj>&& 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<CToken*>(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<IObj>&& obj);
const SObjectTag* GetObjectTag() const;
const CObjectReference* GetObjectReference() const { return x0_objRef; }
~CToken();
};
template <class T>
class TToken : public CToken {
public:
static std::unique_ptr<TObjOwnerDerivedFromIObj<T>> GetIObjObjectFor(std::unique_ptr<T>&& obj) {
return TObjOwnerDerivedFromIObj<T>::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<T>&& obj) : CToken(GetIObjObjectFor(std::move(obj))) {}
TToken& operator=(std::unique_ptr<T>&& obj) {
*this = CToken(GetIObjObjectFor(std::move(obj)));
return *this;
}
virtual void Unlock() { CToken::Unlock(); }
virtual void Lock() { CToken::Lock(); }
virtual T* GetObj() {
TObjOwnerDerivedFromIObj<T>* owner = static_cast<TObjOwnerDerivedFromIObj<T>*>(CToken::GetObj());
if (owner)
return owner->GetObj();
return nullptr;
}
virtual const T* GetObj() const { return const_cast<TToken<T>*>(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 T>
class TCachedToken : public TToken<T> {
protected:
T* m_obj = nullptr;
public:
TCachedToken() = default;
TCachedToken(const CToken& other) : TToken<T>(other) {}
TCachedToken(CToken&& other) : TToken<T>(std::move(other)) {}
T* GetObj() override {
if (!m_obj)
m_obj = TToken<T>::GetObj();
return m_obj;
}
const T* GetObj() const override { return const_cast<TCachedToken<T>*>(this)->GetObj(); }
void Unlock() override {
TToken<T>::Unlock();
m_obj = nullptr;
}
TCachedToken& operator=(const TCachedToken& other) {
TToken<T>::operator=(other);
m_obj = nullptr;
return *this;
}
TCachedToken& operator=(const CToken& other) override {
TToken<T>::operator=(other);
m_obj = nullptr;
return *this;
}
bool IsNull() const { return m_obj == nullptr; }
};
template <class T>
class TLockedToken : public TCachedToken<T> {
public:
TLockedToken() = default;
TLockedToken(const TLockedToken& other) : TCachedToken<T>(other) { CToken::Lock(); }
TLockedToken& operator=(const TLockedToken& other) {
CToken oldTok = std::move(*this);
TCachedToken<T>::operator=(other);
CToken::Lock();
return *this;
}
TLockedToken(const CToken& other) : TCachedToken<T>(other) { CToken::Lock(); }
TLockedToken& operator=(const CToken& other) override {
CToken oldTok = std::move(*this);
TCachedToken<T>::operator=(other);
CToken::Lock();
return *this;
}
TLockedToken(CToken&& other) {
CToken oldTok = std::move(*this);
*this = TCachedToken<T>(std::move(other));
CToken::Lock();
}
};
} // namespace metaforce