metaforce/Runtime/CToken.hpp

318 lines
8.3 KiB
C++
Raw Normal View History

2016-04-13 06:07:23 +00:00
#ifndef __URDE_CTOKEN_HPP__
#define __URDE_CTOKEN_HPP__
2015-08-21 00:06:39 +00:00
2015-08-22 01:58:41 +00:00
#include <memory>
2015-08-23 06:42:29 +00:00
#include "IObj.hpp"
2015-08-22 01:58:41 +00:00
#include "RetroTypes.hpp"
2015-08-23 06:42:29 +00:00
#include "IVParamObj.hpp"
2015-08-22 01:58:41 +00:00
#include "IObjectStore.hpp"
2015-08-23 06:42:29 +00:00
#include "IFactory.hpp"
2015-08-22 01:58:41 +00:00
2016-03-04 23:04:53 +00:00
namespace urde
2015-08-21 00:06:39 +00:00
{
2015-08-22 01:58:41 +00:00
class IObjectStore;
2016-02-09 05:05:36 +00:00
/** Shared data-structure for CToken references, analogous to std::shared_ptr */
2015-08-22 01:58:41 +00:00
class CObjectReference
{
friend class CToken;
2016-04-01 01:00:37 +00:00
friend class CSimplePool;
2015-08-22 01:58:41 +00:00
u16 x0_refCount = 0;
u16 x2_lockCount = 0;
bool x3_loading = false; /* Rightmost bit of lockCount */
2015-08-22 01:58:41 +00:00
SObjectTag x4_objTag;
IObjectStore* xC_objectStore = nullptr;
IObj* x10_object = nullptr;
2015-08-22 01:58:41 +00:00
CVParamTransfer x14_params;
2016-04-01 01:00:37 +00:00
/** Mechanism by which CToken decrements 1st ref-count, indicating CToken invalidation or reset.
* Reaching 0 indicates the CToken should delete the CObjectReference */
u16 RemoveReference()
{
--x0_refCount;
if (x0_refCount == 0)
{
if (x10_object)
Unload();
if (IsLoading())
CancelLoad();
xC_objectStore->ObjectUnreferenced(x4_objTag);
}
return x0_refCount;
}
2015-08-22 01:58:41 +00:00
CObjectReference(IObjectStore& objStore, std::unique_ptr<IObj>&& obj,
const SObjectTag& objTag, CVParamTransfer buildParams)
: x4_objTag(objTag), xC_objectStore(&objStore),
x10_object(obj.release()), x14_params(buildParams) {}
CObjectReference(std::unique_ptr<IObj>&& obj)
: x10_object(obj.release()) {}
2015-08-22 01:58:41 +00:00
2016-02-09 05:05:36 +00:00
/** Indicates an asynchronous load transaction has been submitted and is not yet finished */
2015-08-22 01:58:41 +00:00
bool IsLoading() const {return x3_loading;}
2016-02-09 05:05:36 +00:00
2016-03-20 00:32:30 +00:00
/** Indicates an asynchronous load transaction has finished and object is completely loaded */
bool IsLoaded() const {return x10_object != nullptr;}
2016-02-09 05:05:36 +00:00
/** Decrements 2nd ref-count, performing unload or async-load-cancel if 0 reached */
void Unlock()
{
--x2_lockCount;
if (x2_lockCount)
return;
if (x10_object && xC_objectStore)
Unload();
else if (IsLoading())
CancelLoad();
}
2016-02-09 05:05:36 +00:00
/** Increments 2nd ref-count, performing async-factory-load if needed */
void Lock()
{
++x2_lockCount;
if (!x10_object && !x3_loading)
{
IFactory& fac = xC_objectStore->GetFactory();
fac.BuildAsync(x4_objTag, x14_params, &x10_object);
x3_loading = true;
}
}
2016-02-09 05:05:36 +00:00
void CancelLoad()
{
if (xC_objectStore && IsLoading())
{
xC_objectStore->GetFactory().CancelBuild(x4_objTag);
x3_loading = false;
}
2015-08-23 06:42:29 +00:00
}
2016-02-09 05:05:36 +00:00
/** Pointer-synchronized object-destructor, another building Lock cycle may be performed after */
2015-08-23 06:42:29 +00:00
void Unload()
{
2016-03-11 00:23:16 +00:00
std::default_delete<IObj>()(x10_object);
x10_object = nullptr;
x3_loading = false;
}
2016-02-09 05:05:36 +00:00
/** Synchronous object-fetch, guaranteed to return complete object on-demand, blocking build if not ready */
IObj* GetObject()
{
if (!x10_object)
{
IFactory& factory = xC_objectStore->GetFactory();
x10_object = factory.Build(x4_objTag, x14_params).release();
}
2015-08-23 06:42:29 +00:00
x3_loading = false;
return x10_object;
2015-08-23 06:42:29 +00:00
}
2016-02-07 07:25:34 +00:00
const SObjectTag& GetObjectTag() const
{
return x4_objTag;
}
2016-04-01 01:00:37 +00:00
public:
~CObjectReference()
2015-08-23 06:42:29 +00:00
{
if (x10_object)
2016-03-11 00:23:16 +00:00
std::default_delete<IObj>()(x10_object);
else if (x3_loading)
xC_objectStore->GetFactory().CancelBuild(x4_objTag);
2015-08-23 06:42:29 +00:00
}
2015-08-22 01:58:41 +00:00
};
2015-08-21 00:06:39 +00:00
2016-02-09 05:05:36 +00:00
/** 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) */
2015-08-21 00:06:39 +00:00
class CToken
{
2016-04-01 01:00:37 +00:00
friend class CSimplePool;
CObjectReference* x0_objRef = nullptr;
2015-08-22 01:58:41 +00:00
bool x4_lockHeld = false;
2016-04-01 01:00:37 +00:00
void RemoveRef()
{
if (x0_objRef && x0_objRef->RemoveReference() == 0)
{
std::default_delete<CObjectReference>()(x0_objRef);
x0_objRef = nullptr;
}
}
CToken(CObjectReference* obj)
{
x0_objRef = obj;
++x0_objRef->x0_refCount;
}
2015-08-22 01:58:41 +00:00
public:
2016-02-09 05:05:36 +00:00
/* Added to test for non-null state */
2016-02-07 07:25:34 +00:00
operator bool() const {return x0_objRef != nullptr;}
2015-08-23 06:42:29 +00:00
void Unlock()
2015-08-22 01:58:41 +00:00
{
if (x0_objRef && x4_lockHeld)
2015-08-23 06:42:29 +00:00
{
x0_objRef->Unlock();
2015-08-23 06:42:29 +00:00
x4_lockHeld = false;
}
}
void Lock()
{
if (x0_objRef && !x4_lockHeld)
2015-08-23 06:42:29 +00:00
{
x0_objRef->Lock();
2015-08-23 06:42:29 +00:00
x4_lockHeld = true;
}
}
2016-03-31 02:44:43 +00:00
bool IsLocked() const {return x4_lockHeld;}
2016-03-20 00:32:30 +00:00
bool IsLoaded() const
{
if (!x0_objRef)
return false;
return x0_objRef->IsLoaded();
}
IObj* GetObj()
2015-08-23 06:42:29 +00:00
{
if (!x0_objRef)
return nullptr;
2015-08-23 06:42:29 +00:00
Lock();
return x0_objRef->GetObject();
2015-08-23 06:42:29 +00:00
}
2016-03-20 06:37:08 +00:00
const IObj* GetObj() const
{
return ((CToken*)this)->GetObj();
}
CToken& operator=(const CToken& other)
2015-08-23 06:42:29 +00:00
{
Unlock();
RemoveRef();
x0_objRef = other.x0_objRef;
if (x0_objRef)
{
++x0_objRef->x0_refCount;
if (other.x4_lockHeld)
Lock();
}
return *this;
}
CToken& operator=(CToken&& other)
{
Unlock();
RemoveRef();
x0_objRef = other.x0_objRef;
other.x0_objRef = nullptr;
x4_lockHeld = other.x4_lockHeld;
other.x4_lockHeld = false;
return *this;
}
2016-02-07 07:25:34 +00:00
CToken() = default;
CToken(const CToken& other)
: x0_objRef(other.x0_objRef)
{
2016-03-11 00:23:16 +00:00
if (x0_objRef)
++x0_objRef->x0_refCount;
}
CToken(CToken&& other)
: x0_objRef(other.x0_objRef), x4_lockHeld(other.x4_lockHeld)
{
other.x0_objRef = nullptr;
other.x4_lockHeld = false;
}
CToken(IObj* obj)
{
x0_objRef = new CObjectReference(std::unique_ptr<IObj>(obj));
++x0_objRef->x0_refCount;
Lock();
}
2016-03-31 02:44:43 +00:00
CToken(std::unique_ptr<IObj>&& obj)
{
x0_objRef = new CObjectReference(std::move(obj));
++x0_objRef->x0_refCount;
Lock();
}
2016-02-07 07:25:34 +00:00
const SObjectTag* GetObjectTag() const
{
if (!x0_objRef)
return nullptr;
return &x0_objRef->GetObjectTag();
}
2015-08-23 06:42:29 +00:00
~CToken()
{
if (x0_objRef)
{
if (x4_lockHeld)
x0_objRef->Unlock();
RemoveRef();
}
2015-08-23 06:42:29 +00:00
}
2015-08-21 00:06:39 +00:00
};
2016-02-08 05:10:17 +00:00
template <class T>
class TToken : public CToken
2015-08-21 00:06:39 +00:00
{
public:
static std::unique_ptr<TObjOwnerDerivedFromIObj<T>> GetIObjObjectFor(std::unique_ptr<T>&& obj)
{
return TObjOwnerDerivedFromIObj<T>::GetNewDerivedObject(std::move(obj));
}
2016-02-07 07:25:34 +00:00
TToken() = default;
TToken(const CToken& other) : CToken(other) {}
2016-02-08 05:10:17 +00:00
TToken(CToken&& other) : CToken(std::move(other)) {}
2016-03-31 02:44:43 +00:00
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;
}
2016-02-16 07:01:55 +00:00
T* GetObj()
{
2016-03-31 02:44:43 +00:00
TObjOwnerDerivedFromIObj<T>* owner = static_cast<TObjOwnerDerivedFromIObj<T>*>(CToken::GetObj());
if (owner)
return owner->GetObj();
2016-02-16 07:01:55 +00:00
return nullptr;
}
2016-03-20 06:37:08 +00:00
const T* GetObj() const
{
return ((TToken<T>*)this)->GetObj();
}
2016-02-11 22:38:25 +00:00
T* operator->() {return GetObj();}
2016-03-21 00:25:53 +00:00
const T* operator->() const {return GetObj();}
};
2016-02-08 05:10:17 +00:00
template <class T>
2016-03-31 02:44:43 +00:00
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()
{
if (!m_obj)
m_obj = TToken<T>::GetObj();
return m_obj;
}
const T* GetObj() const
{
return ((TCachedToken<T>*)this)->GetObj();
}
T* operator->() {return GetObj();}
const T* operator->() const {return GetObj();}
void Unlock() {TToken<T>::Unlock(); m_obj = nullptr;}
};
template <class T>
class TLockedToken : public TCachedToken<T>
{
public:
2016-03-31 02:44:43 +00:00
TLockedToken() = default;
2016-04-01 04:25:00 +00:00
TLockedToken(const CToken& other) : TCachedToken<T>(other) {CToken::Lock();}
TLockedToken(CToken&& other) : TCachedToken<T>(std::move(other)) {CToken::Lock();}
2015-08-21 00:06:39 +00:00
};
}
2016-04-13 06:07:23 +00:00
#endif // __URDE_CTOKEN_HPP__