Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// \file
  10. /// This file defines the RefCountedBase, ThreadSafeRefCountedBase, and
  11. /// IntrusiveRefCntPtr classes.
  12. ///
  13. /// IntrusiveRefCntPtr is a smart pointer to an object which maintains a
  14. /// reference count.  (ThreadSafe)RefCountedBase is a mixin class that adds a
  15. /// refcount member variable and methods for updating the refcount.  An object
  16. /// that inherits from (ThreadSafe)RefCountedBase deletes itself when its
  17. /// refcount hits zero.
  18. ///
  19. /// For example:
  20. ///
  21. /// ```
  22. ///   class MyClass : public RefCountedBase<MyClass> {};
  23. ///
  24. ///   void foo() {
  25. ///     // Constructing an IntrusiveRefCntPtr increases the pointee's refcount
  26. ///     // by 1 (from 0 in this case).
  27. ///     IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass());
  28. ///
  29. ///     // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1.
  30. ///     IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1);
  31. ///
  32. ///     // Constructing an IntrusiveRefCntPtr has no effect on the object's
  33. ///     // refcount.  After a move, the moved-from pointer is null.
  34. ///     IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1));
  35. ///     assert(Ptr1 == nullptr);
  36. ///
  37. ///     // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1.
  38. ///     Ptr2.reset();
  39. ///
  40. ///     // The object deletes itself when we return from the function, because
  41. ///     // Ptr3's destructor decrements its refcount to 0.
  42. ///   }
  43. /// ```
  44. ///
  45. /// You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.:
  46. ///
  47. /// ```
  48. ///   IntrusiveRefCntPtr<MyClass> Ptr(new MyClass());
  49. ///   OtherClass *Other = dyn_cast<OtherClass>(Ptr);  // Ptr.get() not required
  50. /// ```
  51. ///
  52. /// IntrusiveRefCntPtr works with any class that
  53. ///
  54. ///  - inherits from (ThreadSafe)RefCountedBase,
  55. ///  - has Retain() and Release() methods, or
  56. ///  - specializes IntrusiveRefCntPtrInfo.
  57. ///
  58. //===----------------------------------------------------------------------===//
  59.  
  60. #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
  61. #define LLVM_ADT_INTRUSIVEREFCNTPTR_H
  62.  
  63. #include <atomic>
  64. #include <cassert>
  65. #include <cstddef>
  66. #include <memory>
  67.  
  68. namespace llvm {
  69.  
  70. /// A CRTP mixin class that adds reference counting to a type.
  71. ///
  72. /// The lifetime of an object which inherits from RefCountedBase is managed by
  73. /// calls to Release() and Retain(), which increment and decrement the object's
  74. /// refcount, respectively.  When a Release() call decrements the refcount to 0,
  75. /// the object deletes itself.
  76. template <class Derived> class RefCountedBase {
  77.   mutable unsigned RefCount = 0;
  78.  
  79. protected:
  80.   RefCountedBase() = default;
  81.   RefCountedBase(const RefCountedBase &) {}
  82.   RefCountedBase &operator=(const RefCountedBase &) = delete;
  83.  
  84. #ifndef NDEBUG
  85.   ~RefCountedBase() {
  86.     assert(RefCount == 0 &&
  87.            "Destruction occurred when there are still references to this.");
  88.   }
  89. #else
  90.   // Default the destructor in release builds, A trivial destructor may enable
  91.   // better codegen.
  92.   ~RefCountedBase() = default;
  93. #endif
  94.  
  95. public:
  96.   void Retain() const { ++RefCount; }
  97.  
  98.   void Release() const {
  99.     assert(RefCount > 0 && "Reference count is already zero.");
  100.     if (--RefCount == 0)
  101.       delete static_cast<const Derived *>(this);
  102.   }
  103. };
  104.  
  105. /// A thread-safe version of \c RefCountedBase.
  106. template <class Derived> class ThreadSafeRefCountedBase {
  107.   mutable std::atomic<int> RefCount{0};
  108.  
  109. protected:
  110.   ThreadSafeRefCountedBase() = default;
  111.   ThreadSafeRefCountedBase(const ThreadSafeRefCountedBase &) {}
  112.   ThreadSafeRefCountedBase &
  113.   operator=(const ThreadSafeRefCountedBase &) = delete;
  114.  
  115. #ifndef NDEBUG
  116.   ~ThreadSafeRefCountedBase() {
  117.     assert(RefCount == 0 &&
  118.            "Destruction occurred when there are still references to this.");
  119.   }
  120. #else
  121.   // Default the destructor in release builds, A trivial destructor may enable
  122.   // better codegen.
  123.   ~ThreadSafeRefCountedBase() = default;
  124. #endif
  125.  
  126. public:
  127.   void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
  128.  
  129.   void Release() const {
  130.     int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
  131.     assert(NewRefCount >= 0 && "Reference count was already zero.");
  132.     if (NewRefCount == 0)
  133.       delete static_cast<const Derived *>(this);
  134.   }
  135. };
  136.  
  137. /// Class you can specialize to provide custom retain/release functionality for
  138. /// a type.
  139. ///
  140. /// Usually specializing this class is not necessary, as IntrusiveRefCntPtr
  141. /// works with any type which defines Retain() and Release() functions -- you
  142. /// can define those functions yourself if RefCountedBase doesn't work for you.
  143. ///
  144. /// One case when you might want to specialize this type is if you have
  145. ///  - Foo.h defines type Foo and includes Bar.h, and
  146. ///  - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions.
  147. ///
  148. /// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in
  149. /// the declaration of Foo.  Without the declaration of Foo, normally Bar.h
  150. /// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call
  151. /// T::Retain and T::Release.
  152. ///
  153. /// To resolve this, Bar.h could include a third header, FooFwd.h, which
  154. /// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>.  Then
  155. /// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any
  156. /// functions on Foo itself, because Foo would be an incomplete type.
  157. template <typename T> struct IntrusiveRefCntPtrInfo {
  158.   static void retain(T *obj) { obj->Retain(); }
  159.   static void release(T *obj) { obj->Release(); }
  160. };
  161.  
  162. /// A smart pointer to a reference-counted object that inherits from
  163. /// RefCountedBase or ThreadSafeRefCountedBase.
  164. ///
  165. /// This class increments its pointee's reference count when it is created, and
  166. /// decrements its refcount when it's destroyed (or is changed to point to a
  167. /// different object).
  168. template <typename T> class IntrusiveRefCntPtr {
  169.   T *Obj = nullptr;
  170.  
  171. public:
  172.   using element_type = T;
  173.  
  174.   explicit IntrusiveRefCntPtr() = default;
  175.   IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); }
  176.   IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); }
  177.   IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; }
  178.  
  179.   template <class X,
  180.             std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true>
  181.   IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> S) : Obj(S.get()) {
  182.     S.Obj = nullptr;
  183.   }
  184.  
  185.   template <class X,
  186.             std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true>
  187.   IntrusiveRefCntPtr(std::unique_ptr<X> S) : Obj(S.release()) {
  188.     retain();
  189.   }
  190.  
  191.   ~IntrusiveRefCntPtr() { release(); }
  192.  
  193.   IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) {
  194.     swap(S);
  195.     return *this;
  196.   }
  197.  
  198.   T &operator*() const { return *Obj; }
  199.   T *operator->() const { return Obj; }
  200.   T *get() const { return Obj; }
  201.   explicit operator bool() const { return Obj; }
  202.  
  203.   void swap(IntrusiveRefCntPtr &other) {
  204.     T *tmp = other.Obj;
  205.     other.Obj = Obj;
  206.     Obj = tmp;
  207.   }
  208.  
  209.   void reset() {
  210.     release();
  211.     Obj = nullptr;
  212.   }
  213.  
  214.   void resetWithoutRelease() { Obj = nullptr; }
  215.  
  216. private:
  217.   void retain() {
  218.     if (Obj)
  219.       IntrusiveRefCntPtrInfo<T>::retain(Obj);
  220.   }
  221.  
  222.   void release() {
  223.     if (Obj)
  224.       IntrusiveRefCntPtrInfo<T>::release(Obj);
  225.   }
  226.  
  227.   template <typename X> friend class IntrusiveRefCntPtr;
  228. };
  229.  
  230. template <class T, class U>
  231. inline bool operator==(const IntrusiveRefCntPtr<T> &A,
  232.                        const IntrusiveRefCntPtr<U> &B) {
  233.   return A.get() == B.get();
  234. }
  235.  
  236. template <class T, class U>
  237. inline bool operator!=(const IntrusiveRefCntPtr<T> &A,
  238.                        const IntrusiveRefCntPtr<U> &B) {
  239.   return A.get() != B.get();
  240. }
  241.  
  242. template <class T, class U>
  243. inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) {
  244.   return A.get() == B;
  245. }
  246.  
  247. template <class T, class U>
  248. inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) {
  249.   return A.get() != B;
  250. }
  251.  
  252. template <class T, class U>
  253. inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) {
  254.   return A == B.get();
  255. }
  256.  
  257. template <class T, class U>
  258. inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) {
  259.   return A != B.get();
  260. }
  261.  
  262. template <class T>
  263. bool operator==(std::nullptr_t, const IntrusiveRefCntPtr<T> &B) {
  264.   return !B;
  265. }
  266.  
  267. template <class T>
  268. bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
  269.   return B == A;
  270. }
  271.  
  272. template <class T>
  273. bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
  274.   return !(A == B);
  275. }
  276.  
  277. template <class T>
  278. bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
  279.   return !(A == B);
  280. }
  281.  
  282. // Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from
  283. // Casting.h.
  284. template <typename From> struct simplify_type;
  285.  
  286. template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> {
  287.   using SimpleType = T *;
  288.  
  289.   static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) {
  290.     return Val.get();
  291.   }
  292. };
  293.  
  294. template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> {
  295.   using SimpleType = /*const*/ T *;
  296.  
  297.   static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) {
  298.     return Val.get();
  299.   }
  300. };
  301.  
  302. /// Factory function for creating intrusive ref counted pointers.
  303. template <typename T, typename... Args>
  304. IntrusiveRefCntPtr<T> makeIntrusiveRefCnt(Args &&...A) {
  305.   return IntrusiveRefCntPtr<T>(new T(std::forward<Args>(A)...));
  306. }
  307.  
  308. } // end namespace llvm
  309.  
  310. #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H
  311.