Home | History | Annotate | Download | only in ADT
      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 
     21 #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
     22 #define LLVM_ADT_INTRUSIVEREFCNTPTR_H
     23 
     24 #include <atomic>
     25 #include <cassert>
     26 #include <cstddef>
     27 
     28 namespace llvm {
     29 
     30 //===----------------------------------------------------------------------===//
     31 /// RefCountedBase - A generic base class for objects that wish to
     32 ///  have their lifetimes managed using reference counts. Classes
     33 ///  subclass RefCountedBase to obtain such functionality, and are
     34 ///  typically handled with IntrusiveRefCntPtr "smart pointers" (see below)
     35 ///  which automatically handle the management of reference counts.
     36 ///  Objects that subclass RefCountedBase should not be allocated on
     37 ///  the stack, as invoking "delete" (which is called when the
     38 ///  reference count hits 0) on such objects is an error.
     39 //===----------------------------------------------------------------------===//
     40   template <class Derived>
     41   class RefCountedBase {
     42     mutable unsigned ref_cnt = 0;
     43 
     44   public:
     45     RefCountedBase() = default;
     46     RefCountedBase(const RefCountedBase &) : ref_cnt(0) {}
     47 
     48     void Retain() const { ++ref_cnt; }
     49     void Release() const {
     50       assert (ref_cnt > 0 && "Reference count is already zero.");
     51       if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
     52     }
     53   };
     54 
     55 //===----------------------------------------------------------------------===//
     56 /// RefCountedBaseVPTR - A class that has the same function as
     57 ///  RefCountedBase, but with a virtual destructor. Should be used
     58 ///  instead of RefCountedBase for classes that already have virtual
     59 ///  methods to enforce dynamic allocation via 'new'. Classes that
     60 ///  inherit from RefCountedBaseVPTR can't be allocated on stack -
     61 ///  attempting to do this will produce a compile error.
     62 //===----------------------------------------------------------------------===//
     63   class RefCountedBaseVPTR {
     64     mutable unsigned ref_cnt = 0;
     65 
     66     virtual void anchor();
     67 
     68   protected:
     69     RefCountedBaseVPTR() = default;
     70     RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {}
     71 
     72     virtual ~RefCountedBaseVPTR() = default;
     73 
     74     void Retain() const { ++ref_cnt; }
     75     void Release() const {
     76       assert (ref_cnt > 0 && "Reference count is already zero.");
     77       if (--ref_cnt == 0) delete this;
     78     }
     79 
     80     template <typename T>
     81     friend struct IntrusiveRefCntPtrInfo;
     82   };
     83 
     84 
     85   template <typename T> struct IntrusiveRefCntPtrInfo {
     86     static void retain(T *obj) { obj->Retain(); }
     87     static void release(T *obj) { obj->Release(); }
     88   };
     89 
     90 /// \brief A thread-safe version of \c llvm::RefCountedBase.
     91 ///
     92 /// A generic base class for objects that wish to have their lifetimes managed
     93 /// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to
     94 /// obtain such functionality, and are typically handled with
     95 /// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the
     96 /// management of reference counts.
     97 template <class Derived>
     98 class ThreadSafeRefCountedBase {
     99   mutable std::atomic<int> RefCount;
    100 
    101 protected:
    102   ThreadSafeRefCountedBase() : RefCount(0) {}
    103 
    104 public:
    105   void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
    106 
    107   void Release() const {
    108     int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
    109     assert(NewRefCount >= 0 && "Reference count was already zero.");
    110     if (NewRefCount == 0)
    111       delete static_cast<const Derived*>(this);
    112   }
    113 };
    114 
    115 //===----------------------------------------------------------------------===//
    116 /// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
    117 ///  that assumes the wrapped object has a reference count associated
    118 ///  with it that can be managed via calls to
    119 ///  IntrusivePtrAddRef/IntrusivePtrRelease.  The smart pointers
    120 ///  manage reference counts via the RAII idiom: upon creation of
    121 ///  smart pointer the reference count of the wrapped object is
    122 ///  incremented and upon destruction of the smart pointer the
    123 ///  reference count is decremented.  This class also safely handles
    124 ///  wrapping NULL pointers.
    125 ///
    126 /// Reference counting is implemented via calls to
    127 ///  Obj->Retain()/Obj->Release(). Release() is required to destroy
    128 ///  the object when the reference count reaches zero. Inheriting from
    129 ///  RefCountedBase/RefCountedBaseVPTR takes care of this
    130 ///  automatically.
    131 //===----------------------------------------------------------------------===//
    132   template <typename T>
    133   class IntrusiveRefCntPtr {
    134     T* Obj = nullptr;
    135 
    136   public:
    137     typedef T element_type;
    138 
    139     explicit IntrusiveRefCntPtr() = default;
    140 
    141     IntrusiveRefCntPtr(T* obj) : Obj(obj) {
    142       retain();
    143     }
    144 
    145     IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
    146       retain();
    147     }
    148 
    149     IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
    150       S.Obj = nullptr;
    151     }
    152 
    153     template <class X>
    154     IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
    155       S.Obj = nullptr;
    156     }
    157 
    158     template <class X>
    159     IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
    160       : Obj(S.get()) {
    161       retain();
    162     }
    163 
    164     IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
    165       swap(S);
    166       return *this;
    167     }
    168 
    169     ~IntrusiveRefCntPtr() { release(); }
    170 
    171     T& operator*() const { return *Obj; }
    172 
    173     T* operator->() const { return Obj; }
    174 
    175     T* get() const { return Obj; }
    176 
    177     explicit operator bool() const { return Obj; }
    178 
    179     void swap(IntrusiveRefCntPtr& other) {
    180       T* tmp = other.Obj;
    181       other.Obj = Obj;
    182       Obj = tmp;
    183     }
    184 
    185     void reset() {
    186       release();
    187       Obj = nullptr;
    188     }
    189 
    190     void resetWithoutRelease() {
    191       Obj = nullptr;
    192     }
    193 
    194   private:
    195     void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
    196     void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
    197 
    198     template <typename X>
    199     friend class IntrusiveRefCntPtr;
    200   };
    201 
    202   template<class T, class U>
    203   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
    204                          const IntrusiveRefCntPtr<U>& B)
    205   {
    206     return A.get() == B.get();
    207   }
    208 
    209   template<class T, class U>
    210   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
    211                          const IntrusiveRefCntPtr<U>& B)
    212   {
    213     return A.get() != B.get();
    214   }
    215 
    216   template<class T, class U>
    217   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
    218                          U* B)
    219   {
    220     return A.get() == B;
    221   }
    222 
    223   template<class T, class U>
    224   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
    225                          U* B)
    226   {
    227     return A.get() != B;
    228   }
    229 
    230   template<class T, class U>
    231   inline bool operator==(T* A,
    232                          const IntrusiveRefCntPtr<U>& B)
    233   {
    234     return A == B.get();
    235   }
    236 
    237   template<class T, class U>
    238   inline bool operator!=(T* A,
    239                          const IntrusiveRefCntPtr<U>& B)
    240   {
    241     return A != B.get();
    242   }
    243 
    244   template <class T>
    245   bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
    246     return !B;
    247   }
    248 
    249   template <class T>
    250   bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
    251     return B == A;
    252   }
    253 
    254   template <class T>
    255   bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
    256     return !(A == B);
    257   }
    258 
    259   template <class T>
    260   bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
    261     return !(A == B);
    262   }
    263 
    264 //===----------------------------------------------------------------------===//
    265 // LLVM-style downcasting support for IntrusiveRefCntPtr objects
    266 //===----------------------------------------------------------------------===//
    267 
    268   template <typename From> struct simplify_type;
    269 
    270   template<class T> struct simplify_type<IntrusiveRefCntPtr<T>> {
    271     typedef T* SimpleType;
    272     static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
    273       return Val.get();
    274     }
    275   };
    276 
    277   template<class T> struct simplify_type<const IntrusiveRefCntPtr<T>> {
    278     typedef /*const*/ T* SimpleType;
    279     static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
    280       return Val.get();
    281     }
    282   };
    283 
    284 } // end namespace llvm
    285 
    286 #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H
    287