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 "llvm/Support/Casting.h"
     25 #include "llvm/Support/Compiler.h"
     26 #include <atomic>
     27 #include <memory>
     28 
     29 namespace llvm {
     30 
     31   template <class T>
     32   class IntrusiveRefCntPtr;
     33 
     34 //===----------------------------------------------------------------------===//
     35 /// RefCountedBase - A generic base class for objects that wish to
     36 ///  have their lifetimes managed using reference counts. Classes
     37 ///  subclass RefCountedBase to obtain such functionality, and are
     38 ///  typically handled with IntrusiveRefCntPtr "smart pointers" (see below)
     39 ///  which automatically handle the management of reference counts.
     40 ///  Objects that subclass RefCountedBase should not be allocated on
     41 ///  the stack, as invoking "delete" (which is called when the
     42 ///  reference count hits 0) on such objects is an error.
     43 //===----------------------------------------------------------------------===//
     44   template <class Derived>
     45   class RefCountedBase {
     46     mutable unsigned ref_cnt;
     47 
     48   public:
     49     RefCountedBase() : ref_cnt(0) {}
     50     RefCountedBase(const RefCountedBase &) : ref_cnt(0) {}
     51 
     52     void Retain() const { ++ref_cnt; }
     53     void Release() const {
     54       assert (ref_cnt > 0 && "Reference count is already zero.");
     55       if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
     56     }
     57   };
     58 
     59 //===----------------------------------------------------------------------===//
     60 /// RefCountedBaseVPTR - A class that has the same function as
     61 ///  RefCountedBase, but with a virtual destructor. Should be used
     62 ///  instead of RefCountedBase for classes that already have virtual
     63 ///  methods to enforce dynamic allocation via 'new'. Classes that
     64 ///  inherit from RefCountedBaseVPTR can't be allocated on stack -
     65 ///  attempting to do this will produce a compile error.
     66 //===----------------------------------------------------------------------===//
     67   class RefCountedBaseVPTR {
     68     mutable unsigned ref_cnt;
     69     virtual void anchor();
     70 
     71   protected:
     72     RefCountedBaseVPTR() : ref_cnt(0) {}
     73     RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {}
     74 
     75     virtual ~RefCountedBaseVPTR() {}
     76 
     77     void Retain() const { ++ref_cnt; }
     78     void Release() const {
     79       assert (ref_cnt > 0 && "Reference count is already zero.");
     80       if (--ref_cnt == 0) delete this;
     81     }
     82 
     83     template <typename T>
     84     friend struct IntrusiveRefCntPtrInfo;
     85   };
     86 
     87 
     88   template <typename T> struct IntrusiveRefCntPtrInfo {
     89     static void retain(T *obj) { obj->Retain(); }
     90     static void release(T *obj) { obj->Release(); }
     91   };
     92 
     93 /// \brief A thread-safe version of \c llvm::RefCountedBase.
     94 ///
     95 /// A generic base class for objects that wish to have their lifetimes managed
     96 /// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to
     97 /// obtain such functionality, and are typically handled with
     98 /// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the
     99 /// management of reference counts.
    100 template <class Derived>
    101 class ThreadSafeRefCountedBase {
    102   mutable std::atomic<int> RefCount;
    103 
    104 protected:
    105   ThreadSafeRefCountedBase() : RefCount(0) {}
    106 
    107 public:
    108   void Retain() const { ++RefCount; }
    109 
    110   void Release() const {
    111     int NewRefCount = --RefCount;
    112     assert(NewRefCount >= 0 && "Reference count was already zero.");
    113     if (NewRefCount == 0)
    114       delete static_cast<const Derived*>(this);
    115   }
    116 };
    117 
    118 //===----------------------------------------------------------------------===//
    119 /// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
    120 ///  that assumes the wrapped object has a reference count associated
    121 ///  with it that can be managed via calls to
    122 ///  IntrusivePtrAddRef/IntrusivePtrRelease.  The smart pointers
    123 ///  manage reference counts via the RAII idiom: upon creation of
    124 ///  smart pointer the reference count of the wrapped object is
    125 ///  incremented and upon destruction of the smart pointer the
    126 ///  reference count is decremented.  This class also safely handles
    127 ///  wrapping NULL pointers.
    128 ///
    129 /// Reference counting is implemented via calls to
    130 ///  Obj->Retain()/Obj->Release(). Release() is required to destroy
    131 ///  the object when the reference count reaches zero. Inheriting from
    132 ///  RefCountedBase/RefCountedBaseVPTR takes care of this
    133 ///  automatically.
    134 //===----------------------------------------------------------------------===//
    135   template <typename T>
    136   class IntrusiveRefCntPtr {
    137     T* Obj;
    138 
    139   public:
    140     typedef T element_type;
    141 
    142     explicit IntrusiveRefCntPtr() : Obj(nullptr) {}
    143 
    144     IntrusiveRefCntPtr(T* obj) : Obj(obj) {
    145       retain();
    146     }
    147 
    148     IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
    149       retain();
    150     }
    151 
    152     IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
    153       S.Obj = nullptr;
    154     }
    155 
    156     template <class X>
    157     IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
    158       S.Obj = 0;
    159     }
    160 
    161     template <class X>
    162     IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
    163       : Obj(S.get()) {
    164       retain();
    165     }
    166 
    167     IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
    168       swap(S);
    169       return *this;
    170     }
    171 
    172     ~IntrusiveRefCntPtr() { release(); }
    173 
    174     T& operator*() const { return *Obj; }
    175 
    176     T* operator->() const { return Obj; }
    177 
    178     T* get() const { return Obj; }
    179 
    180     LLVM_EXPLICIT operator bool() const { return Obj; }
    181 
    182     void swap(IntrusiveRefCntPtr& other) {
    183       T* tmp = other.Obj;
    184       other.Obj = Obj;
    185       Obj = tmp;
    186     }
    187 
    188     void reset() {
    189       release();
    190       Obj = nullptr;
    191     }
    192 
    193     void resetWithoutRelease() {
    194       Obj = 0;
    195     }
    196 
    197   private:
    198     void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
    199     void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
    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<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
    269     typedef T* SimpleType;
    270     static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
    271       return Val.get();
    272     }
    273   };
    274 
    275   template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
    276     typedef /*const*/ T* SimpleType;
    277     static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
    278       return Val.get();
    279     }
    280   };
    281 
    282 } // end namespace llvm
    283 
    284 #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H
    285