#pragma once #include #include namespace singleapi { namespace pmr { using std::pmr::unsynchronized_pool_resource; using std::pmr::unordered_map; }; template concept is_unique_wrap_t = requires(T* t) { typename T::UniqueType; { t->Ptr() } -> std::same_as; }; template concept is_reinitialize_t = requires(T * t) { { t->reinitialize() }; }; struct MemoryInfo { void* data; bool isAlive; static pmr::unsynchronized_pool_resource* Pool(); static void* Allocate(size_t size, size_t align) { return Pool()->allocate(size, align); } }; class SINGLETON_API GlobalManager { public: MemoryInfo GetInstance(size_t hash, size_t size, size_t align = 8) { auto it = instances.find(hash); if (it == instances.end()) { void* data = MemoryInfo::Allocate(size, align); instances.emplace(hash, MemoryInfo{data, true}); return MemoryInfo{ data, false }; } bool isAlive = it->second.isAlive; it->second.isAlive = true; return MemoryInfo{ it->second.data, isAlive }; } bool KillInstance(size_t hash) { bool isAlive = false; auto it = instances.find(hash); if (it != instances.end()) { isAlive = it->second.isAlive; it->second.isAlive = false; } return isAlive; } GlobalManager(pmr::unsynchronized_pool_resource* pool) : instances{pool} {} ~GlobalManager() {} static GlobalManager* Ptr(); private: pmr::unordered_map instances; }; } template class UniquePtr { protected: inline static T* ms_Singleton = nullptr; public: template UniquePtr(Args&&... args) { using namespace singleapi; MemoryInfo info{}; if constexpr (hash == 0) { size_t tHash = typeid(T).hash_code(); info = GlobalManager::Ptr()->GetInstance(tHash, sizeof(T)); } else { info = GlobalManager::Ptr()->GetInstance(hash, sizeof(T)); } if (info.isAlive) { ms_Singleton = (T*)info.data; } else { ms_Singleton = new(info.data)T(std::forward(args)...); } if constexpr (is_reinitialize_t) { ms_Singleton->reinitialize(); } } ~UniquePtr() { using namespace singleapi; bool isAlive = false; if constexpr (hash == 0) { size_t tHash = typeid(T).hash_code(); isAlive = GlobalManager::Ptr()->KillInstance(tHash); } else { isAlive = GlobalManager::Ptr()->KillInstance(hash); } if (ms_Singleton && isAlive) { ms_Singleton->~T(); } } static T* Ptr(void) { return ms_Singleton; } }; template class UniquePtr { protected: using U = T::UniqueType; inline static T* ms_Singleton = nullptr; public: template UniquePtr(Args&&... args) { using namespace singleapi; MemoryInfo info{}; if constexpr (hash == 0) { size_t tHash = typeid(T).hash_code(); info = GlobalManager::Ptr()->GetInstance(tHash, sizeof(T)); } else { info = GlobalManager::Ptr()->GetInstance(hash, sizeof(T)); } if (info.isAlive) { ms_Singleton = (T*)info.data; } else { ms_Singleton = new(info.data)T(std::forward(args)...); } if constexpr (is_reinitialize_t) { ms_Singleton->reinitialize(); } } ~UniquePtr() { using namespace singleapi; bool isAlive = false; if constexpr (hash == 0) { size_t tHash = typeid(T).hash_code(); isAlive = GlobalManager::Ptr()->KillInstance(tHash); } else { isAlive = GlobalManager::Ptr()->KillInstance(hash); } if (ms_Singleton && isAlive) { ms_Singleton->~T(); } } static U* Ptr(void) { return ms_Singleton->Ptr(); } }; constexpr inline size_t string_hash(std::string_view str) noexcept { constexpr size_t fnv_offset_basis = 0xcbf29ce484222325; constexpr size_t fnv_prime = 0x100000001b3; auto hash = fnv_offset_basis; for (auto& elem : str) { hash *= fnv_prime; hash ^= elem; } hash *= fnv_prime; hash ^= 0; return hash; } #define SINGLETON_IMPL(T) \ protected:\ static T* ms_Singleton;\ public:\ static T* Ptr(void); #define SINGLETON_DEFINE(T) T* T::ms_Singleton = nullptr;\ T* T::Ptr(){ return ms_Singleton; } #define SINGLETON_PTR() ms_Singleton = this; #define UNIQUER_INLINE_STATIC(cls, name, hash) inline static UniquePtr name##Ptr; #define UNIQUER_INLINE(cls, name, hash) inline UniquePtr name##Ptr; #define UNIQUER_STATIC(cls, name, hash) static UniquePtr name##Ptr; #define UNIQUER_VAL(name) (*name##Ptr.Ptr()) #define UNIQUER_PTR(name) name##Ptr.Ptr()