IntrusiveRefCntPtr.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. //== llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer ---*- C++ -*-==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file defines IntrusiveRefCntPtr, a template class that
  11. // implements a "smart" pointer for objects that maintain their own
  12. // internal reference count, and RefCountedBase/RefCountedBaseVPTR, two
  13. // generic base classes for objects that wish to have their lifetimes
  14. // managed using reference counting.
  15. //
  16. // IntrusiveRefCntPtr is similar to Boost's intrusive_ptr with added
  17. // LLVM-style casting.
  18. //
  19. //===----------------------------------------------------------------------===//
  20. #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
  21. #define LLVM_ADT_INTRUSIVEREFCNTPTR_H
  22. #include <atomic>
  23. #include <cassert>
  24. #include <cstddef>
  25. namespace llvm {
  26. template <class T>
  27. class IntrusiveRefCntPtr;
  28. //===----------------------------------------------------------------------===//
  29. /// RefCountedBase - A generic base class for objects that wish to
  30. /// have their lifetimes managed using reference counts. Classes
  31. /// subclass RefCountedBase to obtain such functionality, and are
  32. /// typically handled with IntrusiveRefCntPtr "smart pointers" (see below)
  33. /// which automatically handle the management of reference counts.
  34. /// Objects that subclass RefCountedBase should not be allocated on
  35. /// the stack, as invoking "delete" (which is called when the
  36. /// reference count hits 0) on such objects is an error.
  37. //===----------------------------------------------------------------------===//
  38. template <class Derived>
  39. class RefCountedBase {
  40. mutable unsigned ref_cnt;
  41. public:
  42. RefCountedBase() : ref_cnt(0) {}
  43. RefCountedBase(const RefCountedBase &) : ref_cnt(0) {}
  44. void Retain() const { ++ref_cnt; }
  45. void Release() const {
  46. assert (ref_cnt > 0 && "Reference count is already zero.");
  47. if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
  48. }
  49. };
  50. //===----------------------------------------------------------------------===//
  51. /// RefCountedBaseVPTR - A class that has the same function as
  52. /// RefCountedBase, but with a virtual destructor. Should be used
  53. /// instead of RefCountedBase for classes that already have virtual
  54. /// methods to enforce dynamic allocation via 'new'. Classes that
  55. /// inherit from RefCountedBaseVPTR can't be allocated on stack -
  56. /// attempting to do this will produce a compile error.
  57. //===----------------------------------------------------------------------===//
  58. class RefCountedBaseVPTR {
  59. mutable unsigned ref_cnt;
  60. virtual void anchor();
  61. protected:
  62. RefCountedBaseVPTR() : ref_cnt(0) {}
  63. RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {}
  64. virtual ~RefCountedBaseVPTR() {}
  65. void Retain() const { ++ref_cnt; }
  66. void Release() const {
  67. assert (ref_cnt > 0 && "Reference count is already zero.");
  68. if (--ref_cnt == 0) delete this;
  69. }
  70. template <typename T>
  71. friend struct IntrusiveRefCntPtrInfo;
  72. };
  73. template <typename T> struct IntrusiveRefCntPtrInfo {
  74. static void retain(T *obj) { obj->Retain(); }
  75. static void release(T *obj) { obj->Release(); }
  76. };
  77. /// \brief A thread-safe version of \c llvm::RefCountedBase.
  78. ///
  79. /// A generic base class for objects that wish to have their lifetimes managed
  80. /// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to
  81. /// obtain such functionality, and are typically handled with
  82. /// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the
  83. /// management of reference counts.
  84. template <class Derived>
  85. class ThreadSafeRefCountedBase {
  86. mutable std::atomic<int> RefCount;
  87. protected:
  88. ThreadSafeRefCountedBase() : RefCount(0) {}
  89. public:
  90. void Retain() const { ++RefCount; }
  91. void Release() const {
  92. int NewRefCount = --RefCount;
  93. assert(NewRefCount >= 0 && "Reference count was already zero.");
  94. if (NewRefCount == 0)
  95. delete static_cast<const Derived*>(this);
  96. }
  97. };
  98. //===----------------------------------------------------------------------===//
  99. /// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
  100. /// that assumes the wrapped object has a reference count associated
  101. /// with it that can be managed via calls to
  102. /// IntrusivePtrAddRef/IntrusivePtrRelease. The smart pointers
  103. /// manage reference counts via the RAII idiom: upon creation of
  104. /// smart pointer the reference count of the wrapped object is
  105. /// incremented and upon destruction of the smart pointer the
  106. /// reference count is decremented. This class also safely handles
  107. /// wrapping NULL pointers.
  108. ///
  109. /// Reference counting is implemented via calls to
  110. /// Obj->Retain()/Obj->Release(). Release() is required to destroy
  111. /// the object when the reference count reaches zero. Inheriting from
  112. /// RefCountedBase/RefCountedBaseVPTR takes care of this
  113. /// automatically.
  114. //===----------------------------------------------------------------------===//
  115. template <typename T>
  116. class IntrusiveRefCntPtr {
  117. T* Obj;
  118. public:
  119. typedef T element_type;
  120. explicit IntrusiveRefCntPtr() : Obj(nullptr) {}
  121. IntrusiveRefCntPtr(T* obj) : Obj(obj) {
  122. retain();
  123. }
  124. IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
  125. retain();
  126. }
  127. IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
  128. S.Obj = nullptr;
  129. }
  130. template <class X>
  131. IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
  132. S.Obj = 0;
  133. }
  134. template <class X>
  135. IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
  136. : Obj(S.get()) {
  137. retain();
  138. }
  139. IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
  140. swap(S);
  141. return *this;
  142. }
  143. ~IntrusiveRefCntPtr() { release(); }
  144. T& operator*() const { return *Obj; }
  145. T* operator->() const { return Obj; }
  146. T* get() const { return Obj; }
  147. explicit operator bool() const { return Obj != nullptr; } // HLSL Change
  148. void swap(IntrusiveRefCntPtr& other) {
  149. T* tmp = other.Obj;
  150. other.Obj = Obj;
  151. Obj = tmp;
  152. }
  153. void reset() {
  154. release();
  155. Obj = nullptr;
  156. }
  157. void resetWithoutRelease() {
  158. Obj = 0;
  159. }
  160. private:
  161. void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
  162. void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
  163. template <typename X>
  164. friend class IntrusiveRefCntPtr;
  165. };
  166. template<class T, class U>
  167. inline bool operator==(const IntrusiveRefCntPtr<T>& A,
  168. const IntrusiveRefCntPtr<U>& B)
  169. {
  170. return A.get() == B.get();
  171. }
  172. template<class T, class U>
  173. inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
  174. const IntrusiveRefCntPtr<U>& B)
  175. {
  176. return A.get() != B.get();
  177. }
  178. template<class T, class U>
  179. inline bool operator==(const IntrusiveRefCntPtr<T>& A,
  180. U* B)
  181. {
  182. return A.get() == B;
  183. }
  184. template<class T, class U>
  185. inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
  186. U* B)
  187. {
  188. return A.get() != B;
  189. }
  190. template<class T, class U>
  191. inline bool operator==(T* A,
  192. const IntrusiveRefCntPtr<U>& B)
  193. {
  194. return A == B.get();
  195. }
  196. template<class T, class U>
  197. inline bool operator!=(T* A,
  198. const IntrusiveRefCntPtr<U>& B)
  199. {
  200. return A != B.get();
  201. }
  202. template <class T>
  203. bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
  204. return !B;
  205. }
  206. template <class T>
  207. bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
  208. return B == A;
  209. }
  210. template <class T>
  211. bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
  212. return !(A == B);
  213. }
  214. template <class T>
  215. bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
  216. return !(A == B);
  217. }
  218. //===----------------------------------------------------------------------===//
  219. // LLVM-style downcasting support for IntrusiveRefCntPtr objects
  220. // //
  221. ///////////////////////////////////////////////////////////////////////////////
  222. template <typename From> struct simplify_type;
  223. template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
  224. typedef T* SimpleType;
  225. static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
  226. return Val.get();
  227. }
  228. };
  229. template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
  230. typedef /*const*/ T* SimpleType;
  231. static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
  232. return Val.get();
  233. }
  234. };
  235. } // end namespace llvm
  236. #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H