#pragma once #include "Containers/Map.h" #include "EngineTypes.h" #include "Math/Math.h" #include #define DEFINE_REF(x) \ typedef RefPtr P##x; \ typedef UniquePtr UP##x; \ typedef WeakPtr W##x; #define DECLARE_REF(x) \ class x; \ typedef RefPtr P##x; \ typedef UniquePtr UP##x; \ typedef WeakPtr W##x; #define DECLARE_NAME_REF(nmsp, x) \ namespace nmsp \ { \ class x; \ typedef RefPtr P##x; \ typedef UniquePtr UP##x; \ typedef WeakPtr W##x; \ } extern std::map registeredObjects; extern std::mutex registeredObjectsLock; namespace Seele { template class RefPtr; template class RefObject { public: RefObject(T *ptr, Deleter&& deleter) : handle(ptr) , deleter(std::move(deleter)) , refCount(1) { } RefObject(const RefObject &rhs) = delete; RefObject(RefObject &&rhs) : handle(std::move(rhs.handle)), refCount(std::move(rhs.refCount)) { } ~RefObject() { { std::unique_lock lock(registeredObjectsLock); registeredObjects.erase(handle); } // #pragma warning( disable: 4150) deleter(handle); handle = nullptr; // #pragma warning( default: 4150) } RefObject &operator=(const RefObject &rhs) = delete; RefObject &operator=(RefObject &&rhs) { if (*this != rhs) { handle = std::move(rhs.handle); refCount = std::move(rhs.refCount); rhs.handle = nullptr; rhs.refCount = 0; } return *this; } bool operator==(const RefObject &rhs) const { return handle == rhs.handle; } auto operator<=>(const RefObject& rhs) const { return handle <=> rhs.handle; } void addRef() { refCount++; } void removeRef() { refCount--; if (refCount == 0) { delete this; } } T *getHandle() const { return handle; } private: T *handle; Deleter deleter; std::atomic_uint64_t refCount; friend class RefPtr; }; template > class RefPtr { public: RefPtr() { object = nullptr; } RefPtr(nullptr_t) { object = nullptr; } RefPtr(T *ptr, Deleter deleter = Deleter()) { std::unique_lock l(registeredObjectsLock); auto registeredObj = registeredObjects.find(ptr); // get here for thread safetly auto registeredEnd = registeredObjects.end(); if (registeredObj == registeredEnd) { object = new RefObject(ptr, std::move(deleter)); registeredObjects[ptr] = object; } else { object = (RefObject *)registeredObj->second; object->addRef(); } } explicit RefPtr(RefObject *other) : object(other) { object->addRef(); } inline RefPtr(const RefPtr &other) : object(other.object) { if (object != nullptr) { object->addRef(); } } RefPtr(RefPtr &&rhs) : object(std::move(rhs.object)) { rhs.object = nullptr; //Dont change references, they stay the same } template RefPtr(const RefPtr &other) { F *f = other.getObject()->getHandle(); assert(static_cast(f)); object = (RefObject *)other.getObject(); object->addRef(); } template > RefPtr cast() { T *t = object->getHandle(); F *f = dynamic_cast(t); if (f == nullptr) { return nullptr; } RefObject *newObject = (RefObject *)object; return RefPtr(newObject); } template > const RefPtr cast() const { T *t = object->getHandle(); F *f = dynamic_cast(t); if (f == nullptr) { return nullptr; } RefObject *newObject = (RefObject *)object; return RefPtr(newObject); } RefPtr &operator=(const RefPtr &other) { if (this != &other) { if (object != nullptr) { object->removeRef(); } object = other.object; if (object != nullptr) { object->addRef(); } } return *this; } RefPtr &operator=(RefPtr &&rhs) { if (this != &rhs) { if (object != nullptr) { object->removeRef(); } object = std::move(rhs.object); rhs.object = nullptr; } return *this; } ~RefPtr() { if (object != nullptr) { object->removeRef(); } } bool operator==(const RefPtr& rhs) const { return object == rhs.object; } auto operator<=>(const RefPtr &rhs) const { return object <=> rhs.object; } inline T *operator->() { assert(object != nullptr); return object->handle; } inline const T *operator->() const { assert(object != nullptr); return object->handle; } RefObject *getObject() const { return object; } inline T *getHandle() { return object->getHandle(); } inline const T *getHandle() const { return object->getHandle(); } private: RefObject *object; friend class boost::serialization::access; template void serialize(Archive& ar, const unsigned int) { ar & *object->getHandle(); } }; template class UniquePtr { public: UniquePtr() : handle(nullptr) { } UniquePtr(nullptr_t) : handle(nullptr) { } UniquePtr(T *ptr) : handle(ptr) { } UniquePtr(const UniquePtr &rhs) = delete; UniquePtr(UniquePtr &&rhs) noexcept : handle(rhs.handle) { rhs.handle = nullptr; } UniquePtr &operator=(const UniquePtr &rhs) = delete; UniquePtr &operator=(UniquePtr &&rhs) { handle = rhs.handle; rhs.handle = nullptr; return *this; } ~UniquePtr() { delete handle; } inline bool operator==(const UniquePtr &other) const { return handle == other.handle; } inline bool operator!=(const UniquePtr &other) const { return handle != other.handle; } inline T *operator->() { return handle; } inline T* getHandle() { return handle; } bool isValid() { return handle != nullptr; } private: T *handle; friend class boost::serialization::access; template void serialize(Archive& ar, const unsigned int version) { ar & *handle; } }; //A weak pointer has no ownership over an object and thus cant delete it template class WeakPtr { public: WeakPtr() : pointer(nullptr) { } WeakPtr(RefPtr &sharedPtr) : pointer(sharedPtr) { } WeakPtr &operator=(WeakPtr &weakPtr) { pointer = weakPtr.pointer; return *this; } WeakPtr &operator=(RefPtr &sharedPtr) { pointer = sharedPtr; return *this; } private: RefPtr pointer; }; } // namespace Seele using namespace Seele;