#ifndef FUNDAMENTAL_LIB_SMART_POINTER_H #define FUNDAMENTAL_LIB_SMART_POINTER_H #include "common.h" #include "hash.h" #include "type-traits.h" #include #include "../../slang.h" namespace Slang { // TODO: Need to centralize these typedefs typedef uintptr_t UInt; typedef intptr_t Int; // Base class for all reference-counted objects class RefObject { private: UInt referenceCount; public: RefObject() : referenceCount(0) {} RefObject(const RefObject &) : referenceCount(0) {} virtual ~RefObject() {} UInt addReference() { return ++referenceCount; } UInt decreaseReference() { return --referenceCount; } UInt releaseReference() { SLANG_ASSERT(referenceCount != 0); if(--referenceCount == 0) { delete this; return 0; } return referenceCount; } bool isUniquelyReferenced() { SLANG_ASSERT(referenceCount != 0); return referenceCount == 1; } UInt debugGetReferenceCount() { return referenceCount; } }; SLANG_FORCE_INLINE void addReference(RefObject* obj) { if(obj) obj->addReference(); } SLANG_FORCE_INLINE void releaseReference(RefObject* obj) { if(obj) obj->releaseReference(); } // For straight dynamic cast. // Use instead of dynamic_cast as it allows for replacement without using Rtti in the future template SLANG_FORCE_INLINE T* dynamicCast(RefObject* obj) { return dynamic_cast(obj); } template SLANG_FORCE_INLINE const T* dynamicCast(const RefObject* obj) { return dynamic_cast(obj); } // Like a dynamicCast, but allows a type to implement a specific implementation that is suitable for it template SLANG_FORCE_INLINE T* as(RefObject* obj) { return dynamicCast(obj); } template SLANG_FORCE_INLINE const T* as(const RefObject* obj) { return dynamicCast(obj); } // "Smart" pointer to a reference-counted object template struct RefPtr { RefPtr() : pointer(nullptr) {} RefPtr(T* p) : pointer(p) { addReference(p); } RefPtr(RefPtr const& p) : pointer(p.pointer) { addReference(p.pointer); } RefPtr(RefPtr&& p) : pointer(p.pointer) { p.pointer = nullptr; } template RefPtr(RefPtr const& p, typename EnableIf::Value, void>::type * = 0) : pointer((U*) p) { addReference((U*) p); } #if 0 void operator=(T* p) { T* old = pointer; addReference(p); pointer = p; releaseReference(old); } #endif void operator=(RefPtr const& p) { T* old = pointer; addReference(p.pointer); pointer = p.pointer; releaseReference(old); } void operator=(RefPtr&& p) { T* old = pointer; pointer = p.pointer; p.pointer = old; } template typename EnableIf::value, void>::type operator=(RefPtr const& p) { T* old = pointer; addReference(p.pointer); pointer = p.pointer; releaseReference(old); } int GetHashCode() { // Note: We need a `RefPtr` to hash the same as a `T*`, // so that a `T*` can be used as a key in a dictionary with // `RefPtr` keys, and vice versa. // return Slang::GetHashCode(pointer); } bool operator==(const T * ptr) const { return pointer == ptr; } bool operator!=(const T * ptr) const { return pointer != ptr; } bool operator==(RefPtr const& ptr) const { return pointer == ptr.pointer; } bool operator!=(RefPtr const& ptr) const { return pointer != ptr.pointer; } template RefPtr dynamicCast() const { return RefPtr(Slang::dynamicCast(pointer)); } template RefPtr as() const { return RefPtr(Slang::as(pointer)); } template bool is() const { return Slang::as(pointer) != nullptr; } ~RefPtr() { releaseReference((Slang::RefObject*) pointer); } T& operator*() const { return *pointer; } T* operator->() const { return pointer; } T * Ptr() const { return pointer; } operator T*() const { return pointer; } void attach(T* p) { T* old = pointer; pointer = p; releaseReference(old); } T* detach() { auto rs = pointer; pointer = nullptr; return rs; } /// Get ready for writing (nulls contents) SLANG_FORCE_INLINE T** writeRef() { *this = nullptr; return &pointer; } /// Get for read access SLANG_FORCE_INLINE T*const* readRef() const { return &pointer; } private: T* pointer; }; } #endif