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_INTRUSIVE_REF_CNT_PTR
     22 #define LLVM_ADT_INTRUSIVE_REF_CNT_PTR
     23 
     24 #include <cassert>
     25 
     26 #include "llvm/Support/Casting.h"
     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 IntrusivePtr "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 //===----------------------------------------------------------------------===//
     93 /// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
     94 ///  that assumes the wrapped object has a reference count associated
     95 ///  with it that can be managed via calls to
     96 ///  IntrusivePtrAddRef/IntrusivePtrRelease.  The smart pointers
     97 ///  manage reference counts via the RAII idiom: upon creation of
     98 ///  smart pointer the reference count of the wrapped object is
     99 ///  incremented and upon destruction of the smart pointer the
    100 ///  reference count is decremented.  This class also safely handles
    101 ///  wrapping NULL pointers.
    102 ///
    103 /// Reference counting is implemented via calls to
    104 ///  Obj->Retain()/Obj->Release(). Release() is required to destroy
    105 ///  the object when the reference count reaches zero. Inheriting from
    106 ///  RefCountedBase/RefCountedBaseVPTR takes care of this
    107 ///  automatically.
    108 //===----------------------------------------------------------------------===//
    109   template <typename T>
    110   class IntrusiveRefCntPtr {
    111     T* Obj;
    112     typedef IntrusiveRefCntPtr this_type;
    113   public:
    114     typedef T element_type;
    115 
    116     explicit IntrusiveRefCntPtr() : Obj(0) {}
    117 
    118     IntrusiveRefCntPtr(T* obj) : Obj(obj) {
    119       retain();
    120     }
    121 
    122     IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
    123       retain();
    124     }
    125 
    126     template <class X>
    127     IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
    128       : Obj(S.getPtr()) {
    129       retain();
    130     }
    131 
    132     IntrusiveRefCntPtr& operator=(const IntrusiveRefCntPtr& S) {
    133       replace(S.getPtr());
    134       return *this;
    135     }
    136 
    137     template <class X>
    138     IntrusiveRefCntPtr& operator=(const IntrusiveRefCntPtr<X>& S) {
    139       replace(S.getPtr());
    140       return *this;
    141     }
    142 
    143     IntrusiveRefCntPtr& operator=(T * S) {
    144       replace(S);
    145       return *this;
    146     }
    147 
    148     ~IntrusiveRefCntPtr() { release(); }
    149 
    150     T& operator*() const { return *Obj; }
    151 
    152     T* operator->() const { return Obj; }
    153 
    154     T* getPtr() const { return Obj; }
    155 
    156     typedef T* (IntrusiveRefCntPtr::*unspecified_bool_type) () const;
    157     operator unspecified_bool_type() const {
    158       return Obj == 0 ? 0 : &IntrusiveRefCntPtr::getPtr;
    159     }
    160 
    161     void swap(IntrusiveRefCntPtr& other) {
    162       T* tmp = other.Obj;
    163       other.Obj = Obj;
    164       Obj = tmp;
    165     }
    166 
    167     void reset() {
    168       release();
    169       Obj = 0;
    170     }
    171 
    172     void resetWithoutRelease() {
    173       Obj = 0;
    174     }
    175 
    176   private:
    177     void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
    178     void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
    179 
    180     void replace(T* S) {
    181       this_type(S).swap(*this);
    182     }
    183   };
    184 
    185   template<class T, class U>
    186   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
    187                          const IntrusiveRefCntPtr<U>& B)
    188   {
    189     return A.getPtr() == B.getPtr();
    190   }
    191 
    192   template<class T, class U>
    193   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
    194                          const IntrusiveRefCntPtr<U>& B)
    195   {
    196     return A.getPtr() != B.getPtr();
    197   }
    198 
    199   template<class T, class U>
    200   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
    201                          U* B)
    202   {
    203     return A.getPtr() == B;
    204   }
    205 
    206   template<class T, class U>
    207   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
    208                          U* B)
    209   {
    210     return A.getPtr() != B;
    211   }
    212 
    213   template<class T, class U>
    214   inline bool operator==(T* A,
    215                          const IntrusiveRefCntPtr<U>& B)
    216   {
    217     return A == B.getPtr();
    218   }
    219 
    220   template<class T, class U>
    221   inline bool operator!=(T* A,
    222                          const IntrusiveRefCntPtr<U>& B)
    223   {
    224     return A != B.getPtr();
    225   }
    226 
    227 //===----------------------------------------------------------------------===//
    228 // LLVM-style downcasting support for IntrusiveRefCntPtr objects
    229 //===----------------------------------------------------------------------===//
    230 
    231   template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
    232     typedef T* SimpleType;
    233     static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
    234       return Val.getPtr();
    235     }
    236   };
    237 
    238   template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
    239     typedef T* SimpleType;
    240     static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
    241       return Val.getPtr();
    242     }
    243   };
    244 
    245 } // end namespace llvm
    246 
    247 #endif // LLVM_ADT_INTRUSIVE_REF_CNT_PTR
    248