mirror of
https://github.com/CraftyBoss/SuperMarioOdysseyOnline.git
synced 2024-11-25 12:45:17 +00:00
133 lines
8.9 KiB
C
133 lines
8.9 KiB
C
|
#ifndef SEAD_DISPOSER_H_
|
||
|
#define SEAD_DISPOSER_H_
|
||
|
|
||
|
#include <basis/seadNew.h>
|
||
|
#include <basis/seadRawPrint.h>
|
||
|
#include <basis/seadTypes.h>
|
||
|
#include <container/seadListImpl.h>
|
||
|
|
||
|
namespace sead
|
||
|
{
|
||
|
class Heap;
|
||
|
|
||
|
class IDisposer
|
||
|
{
|
||
|
public:
|
||
|
enum class HeapNullOption
|
||
|
{
|
||
|
// disposer_heap must not be nullptr for this option.
|
||
|
AlwaysUseSpecifiedHeap = 0,
|
||
|
UseSpecifiedOrContainHeap = 1,
|
||
|
DoNotAppendDisposerIfNoHeapSpecified = 2,
|
||
|
UseSpecifiedOrCurrentHeap = 3,
|
||
|
};
|
||
|
|
||
|
IDisposer();
|
||
|
explicit IDisposer(Heap* disposer_heap,
|
||
|
HeapNullOption option = HeapNullOption::UseSpecifiedOrCurrentHeap);
|
||
|
virtual ~IDisposer();
|
||
|
|
||
|
static u32 getListNodeOffset() { return offsetof(IDisposer, mListNode); }
|
||
|
|
||
|
protected:
|
||
|
Heap* getDisposerHeap_() const { return mDisposerHeap; }
|
||
|
|
||
|
private:
|
||
|
friend class Heap;
|
||
|
|
||
|
Heap* mDisposerHeap;
|
||
|
ListNode mListNode;
|
||
|
};
|
||
|
|
||
|
} // namespace sead
|
||
|
|
||
|
#define SEAD_INSTANCE(CLASS) (CLASS::instance())
|
||
|
|
||
|
#define SEAD_SINGLETON_DISPOSER(CLASS) \
|
||
|
public: \
|
||
|
class SingletonDisposer_ : public sead::IDisposer \
|
||
|
{ \
|
||
|
public: \
|
||
|
using sead::IDisposer::IDisposer; \
|
||
|
virtual ~SingletonDisposer_(); \
|
||
|
\
|
||
|
static SingletonDisposer_* sStaticDisposer; \
|
||
|
}; \
|
||
|
\
|
||
|
static CLASS* instance() { return sInstance; } \
|
||
|
static CLASS* createInstance(sead::Heap* heap); \
|
||
|
static void deleteInstance(); \
|
||
|
\
|
||
|
CLASS(const CLASS&) = delete; \
|
||
|
CLASS& operator=(const CLASS&) = delete; \
|
||
|
CLASS(CLASS&&) = delete; \
|
||
|
CLASS& operator=(CLASS&&) = delete; \
|
||
|
\
|
||
|
protected: \
|
||
|
static CLASS* sInstance; \
|
||
|
\
|
||
|
friend class SingletonDisposer_; \
|
||
|
\
|
||
|
/* FIXME: this should just use std::aligned_storage_t with a proper alignment value. */ \
|
||
|
u32 mSingletonDisposerBuf_[sizeof(SingletonDisposer_) / sizeof(u32)];
|
||
|
|
||
|
#define SEAD_CREATE_SINGLETON_INSTANCE(CLASS) \
|
||
|
CLASS* CLASS::createInstance(sead::Heap* heap) \
|
||
|
{ \
|
||
|
if (!sInstance) \
|
||
|
{ \
|
||
|
auto* buffer = new (heap, alignof(CLASS)) u8[sizeof(CLASS)]; \
|
||
|
SEAD_ASSERT_MSG(!SingletonDisposer_::sStaticDisposer, "Create Singleton Twice (%s).", \
|
||
|
#CLASS); \
|
||
|
auto* disposer_buffer = buffer + offsetof(CLASS, mSingletonDisposerBuf_); \
|
||
|
\
|
||
|
/* FIXME: do this after creating the instance to ensure the disposer is not clobbered \
|
||
|
* by CLASS's constructor */ \
|
||
|
SingletonDisposer_::sStaticDisposer = new (disposer_buffer) SingletonDisposer_(heap); \
|
||
|
/* Note: When compiling as C++03 (or a newer standard), this must not be `new CLASS()` \
|
||
|
* as that will value initialize (C++17 [dcl.init]/11), which eventually leads to zero \
|
||
|
* initialisation when CLASS has no user-provided constructor (C++17 [dcl.init]/8). \
|
||
|
* This is dangerous because the singleton disposer would get clobbered. \
|
||
|
*/ \
|
||
|
sInstance = new (buffer) CLASS; \
|
||
|
} \
|
||
|
else \
|
||
|
{ \
|
||
|
SEAD_ASSERT_MSG(false, "Create Singleton Twice (%s) : addr %p", #CLASS, sInstance); \
|
||
|
} \
|
||
|
\
|
||
|
return CLASS::sInstance; \
|
||
|
}
|
||
|
|
||
|
#define SEAD_DELETE_SINGLETON_INSTANCE(CLASS) \
|
||
|
void CLASS::deleteInstance() \
|
||
|
{ \
|
||
|
SingletonDisposer_* staticDisposer = SingletonDisposer_::sStaticDisposer; \
|
||
|
if (SingletonDisposer_::sStaticDisposer != NULL) \
|
||
|
{ \
|
||
|
SingletonDisposer_::sStaticDisposer = NULL; \
|
||
|
staticDisposer->~SingletonDisposer_(); \
|
||
|
\
|
||
|
delete sInstance; \
|
||
|
\
|
||
|
sInstance = NULL; \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
#define SEAD_SINGLETON_DISPOSER_IMPL(CLASS) \
|
||
|
CLASS::SingletonDisposer_::~SingletonDisposer_() \
|
||
|
{ \
|
||
|
if (this == sStaticDisposer) \
|
||
|
{ \
|
||
|
sStaticDisposer = nullptr; \
|
||
|
CLASS::sInstance->~CLASS(); \
|
||
|
CLASS::sInstance = nullptr; \
|
||
|
} \
|
||
|
} \
|
||
|
SEAD_CREATE_SINGLETON_INSTANCE(CLASS) \
|
||
|
SEAD_DELETE_SINGLETON_INSTANCE(CLASS) \
|
||
|
CLASS* CLASS::sInstance = NULL; \
|
||
|
CLASS::SingletonDisposer_* CLASS::SingletonDisposer_::sStaticDisposer = NULL;
|
||
|
|
||
|
#endif // SEAD_DISPOSER_H_
|