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