Reference.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <atomic>
  5. namespace JPH {
  6. // Forward declares
  7. template <class T> class Ref;
  8. template <class T> class RefConst;
  9. /// Simple class to facilitate reference counting / releasing
  10. /// Derive your class from RefTarget and you can reference it by using Ref<classname> or RefConst<classname>
  11. ///
  12. /// Reference counting classes keep an integer which indicates how many references
  13. /// to the object are active. Reference counting objects are derived from RefTarget
  14. /// and staT & their life with a reference count of zero. They can then be assigned
  15. /// to equivalents of pointers (Ref) which will increase the reference count immediately.
  16. /// If the destructor of Ref is called or another object is assigned to the reference
  17. /// counting pointer it will decrease the reference count of the object again. If this
  18. /// reference count becomes zero, the object is destroyed.
  19. ///
  20. /// This provides a very powerful mechanism to prevent memory leaks, but also gives
  21. /// some responsibility to the programmer. The most notable point is that you cannot
  22. /// have one object reference another and have the other reference the first one
  23. /// back, because this way the reference count of both objects will never become
  24. /// lower than 1, resulting in a memory leak. By carefully designing your classses
  25. /// (and particularly identifying who owns who in the class hierarchy) you can avoid
  26. /// these problems.
  27. template <class T>
  28. class RefTarget
  29. {
  30. public:
  31. /// Constructor
  32. inline RefTarget() : mRefCount(0) { }
  33. inline RefTarget(const RefTarget &) : mRefCount(0) { }
  34. inline ~RefTarget() { JPH_ASSERT(mRefCount == 0 || mRefCount == cEmbedded); } ///< assert no one is referencing us
  35. /// Mark this class as embedded, this means the type can be used in a compound or constructed on the stack.
  36. /// The Release function will never destruct the object, it is assumed the destructor will be called by whoever allocated
  37. /// the object and at that point in time it is checked that no references are left to the structure.
  38. inline void SetEmbedded() { JPH_ASSERT(mRefCount < cEmbedded); mRefCount += cEmbedded; }
  39. /// Assignment operator
  40. inline RefTarget & operator = (const RefTarget &inRHS) { return *this; }
  41. /// Get current refcount of this object
  42. uint32 GetRefCount() const { return mRefCount; }
  43. /// Add or release a reference to this object
  44. inline void AddRef() const { ++mRefCount; }
  45. inline void Release() const { if (--mRefCount == 0) delete static_cast<const T *>(this); }
  46. /// INTERNAL HELPER FUNCTION USED BY SERIALIZATION
  47. static int sInternalGetRefCountOffset() { return offsetof(T, mRefCount); }
  48. /// INTERNAL HELPER FUNCTION TO OVERRIDE THE REFCOUNT OF AN OBJECT. USE WITH GREAT CARE!
  49. inline void SetRefCountInternal(uint32 inRefCount) { JPH_ASSERT(inRefCount >= 0); mRefCount = inRefCount; }
  50. protected:
  51. static constexpr uint32 cEmbedded = 0x0ebedded; ///< A large value that gets added to the refcount to mark the object as embedded
  52. mutable atomic<uint32> mRefCount; ///< Current reference count
  53. };
  54. /// Pure virtual version of RefTarget
  55. class RefTargetVirtual
  56. {
  57. public:
  58. /// Virtual destructor
  59. virtual ~RefTargetVirtual() = default;
  60. /// Virtual add reference
  61. virtual void AddRef() = 0;
  62. /// Virtual release reference
  63. virtual void Release() = 0;
  64. };
  65. /// Class for automatic referencing, this is the equivalent of a pointer to type T
  66. /// if you assign a value to this class it will increment the reference count by one
  67. /// of this object, and if you assign something else it will decrease the reference
  68. /// count of the first object again. If it reaches a reference count of zero it will
  69. /// be deleted
  70. template <class T>
  71. class Ref
  72. {
  73. public:
  74. /// Constructor
  75. inline Ref() : mPtr(nullptr) { }
  76. inline Ref(T *inRHS) : mPtr(inRHS) { AddRef(); }
  77. inline Ref(const Ref<T> &inRHS) : mPtr(inRHS.mPtr) { AddRef(); }
  78. inline Ref(Ref<T> &&inRHS) noexcept : mPtr(inRHS.mPtr) { inRHS.mPtr = nullptr; }
  79. inline ~Ref() { Release(); }
  80. /// Assignment operators
  81. inline Ref<T> & operator = (T *inRHS) { if (mPtr != inRHS) { Release(); mPtr = inRHS; AddRef(); } return *this; }
  82. inline Ref<T> & operator = (const Ref<T> &inRHS) { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; AddRef(); } return *this; }
  83. inline Ref<T> & operator = (Ref<T> &&inRHS) noexcept { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; inRHS.mPtr = nullptr; } return *this; }
  84. /// Casting operators
  85. inline operator T * const () const { return mPtr; }
  86. inline operator T *() { return mPtr; }
  87. /// Access like a normal pointer
  88. inline T * const operator -> () const { return mPtr; }
  89. inline T * operator -> () { return mPtr; }
  90. inline T & operator * () const { return *mPtr; }
  91. /// Comparison
  92. inline bool operator == (const T * inRHS) const { return mPtr == inRHS; }
  93. inline bool operator == (const Ref<T> &inRHS) const { return mPtr == inRHS.mPtr; }
  94. inline bool operator != (const T * inRHS) const { return mPtr != inRHS; }
  95. inline bool operator != (const Ref<T> &inRHS) const { return mPtr != inRHS.mPtr; }
  96. /// Get pointer
  97. inline T * GetPtr() const { return mPtr; }
  98. inline T * GetPtr() { return mPtr; }
  99. /// INTERNAL HELPER FUNCTION USED BY SERIALIZATION
  100. void ** InternalGetPointer() { return reinterpret_cast<void **>(&mPtr); }
  101. private:
  102. template <class T2> friend class RefConst;
  103. /// Use "variable = nullptr;" to release an object, do not call these functions
  104. inline void AddRef() { if (mPtr != nullptr) mPtr->AddRef(); }
  105. inline void Release() { if (mPtr != nullptr) mPtr->Release(); }
  106. T * mPtr; ///< Pointer to object that we are reference counting
  107. };
  108. /// Class for automatic referencing, this is the equivalent of a CONST pointer to type T
  109. /// if you assign a value to this class it will increment the reference count by one
  110. /// of this object, and if you assign something else it will decrease the reference
  111. /// count of the first object again. If it reaches a reference count of zero it will
  112. /// be deleted
  113. template <class T>
  114. class RefConst
  115. {
  116. public:
  117. /// Constructor
  118. inline RefConst() : mPtr(nullptr) { }
  119. inline RefConst(const T * inRHS) : mPtr(inRHS) { AddRef(); }
  120. inline RefConst(const RefConst<T> &inRHS) : mPtr(inRHS.mPtr) { AddRef(); }
  121. inline RefConst(RefConst<T> &&inRHS) noexcept : mPtr(inRHS.mPtr) { inRHS.mPtr = nullptr; }
  122. inline RefConst(const Ref<T> &inRHS) : mPtr(inRHS.mPtr) { AddRef(); }
  123. inline RefConst(Ref<T> &&inRHS) noexcept : mPtr(inRHS.mPtr) { inRHS.mPtr = nullptr; }
  124. inline ~RefConst() { Release(); }
  125. /// Assignment operators
  126. inline RefConst<T> & operator = (const T * inRHS) { if (mPtr != inRHS) { Release(); mPtr = inRHS; AddRef(); } return *this; }
  127. inline RefConst<T> & operator = (const RefConst<T> &inRHS) { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; AddRef(); } return *this; }
  128. inline RefConst<T> & operator = (RefConst<T> &&inRHS) noexcept { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; inRHS.mPtr = nullptr; } return *this; }
  129. inline RefConst<T> & operator = (const Ref<T> &inRHS) { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; AddRef(); } return *this; }
  130. inline RefConst<T> & operator = (Ref<T> &&inRHS) noexcept { if (mPtr != inRHS.mPtr) { Release(); mPtr = inRHS.mPtr; inRHS.mPtr = nullptr; } return *this; }
  131. /// Casting operators
  132. inline operator const T * () const { return mPtr; }
  133. /// Access like a normal pointer
  134. inline const T * operator -> () const { return mPtr; }
  135. inline const T & operator * () const { return *mPtr; }
  136. /// Comparison
  137. inline bool operator == (const T * inRHS) const { return mPtr == inRHS; }
  138. inline bool operator == (const RefConst<T> &inRHS) const { return mPtr == inRHS.mPtr; }
  139. inline bool operator == (const Ref<T> &inRHS) const { return mPtr == inRHS.mPtr; }
  140. inline bool operator != (const T * inRHS) const { return mPtr != inRHS; }
  141. inline bool operator != (const RefConst<T> &inRHS) const { return mPtr != inRHS.mPtr; }
  142. inline bool operator != (const Ref<T> &inRHS) const { return mPtr != inRHS.mPtr; }
  143. /// Get pointer
  144. inline const T * GetPtr() const { return mPtr; }
  145. /// INTERNAL HELPER FUNCTION USED BY SERIALIZATION
  146. void ** InternalGetPointer() { return const_cast<void **>(reinterpret_cast<const void **>(&mPtr)); }
  147. private:
  148. /// Use "variable = nullptr;" to release an object, do not call these functions
  149. inline void AddRef() { if (mPtr != nullptr) mPtr->AddRef(); }
  150. inline void Release() { if (mPtr != nullptr) mPtr->Release(); }
  151. const T * mPtr; ///< Pointer to object that we are reference counting
  152. };
  153. } // JPH
  154. namespace std
  155. {
  156. /// Declare std::hash for Ref
  157. template <class T>
  158. struct hash<JPH::Ref<T>>
  159. {
  160. size_t operator () (const JPH::Ref<T> &inRHS) const
  161. {
  162. return hash<T *> { }(inRHS.GetPtr());
  163. }
  164. };
  165. /// Declare std::hash for RefConst
  166. template <class T>
  167. struct hash<JPH::RefConst<T>>
  168. {
  169. size_t operator () (const JPH::RefConst<T> &inRHS) const
  170. {
  171. return hash<const T *> { }(inRHS.GetPtr());
  172. }
  173. };
  174. }