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 
     50     void Retain() const { ++ref_cnt; }
     51     void Release() const {
     52       assert (ref_cnt > 0 && "Reference count is already zero.");
     53       if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
     54     }
     55   };
     56 
     57 //===----------------------------------------------------------------------===//
     58 /// RefCountedBaseVPTR - A class that has the same function as
     59 ///  RefCountedBase, but with a virtual destructor. Should be used
     60 ///  instead of RefCountedBase for classes that already have virtual
     61 ///  methods to enforce dynamic allocation via 'new'. Classes that
     62 ///  inherit from RefCountedBaseVPTR can't be allocated on stack -
     63 ///  attempting to do this will produce a compile error.
     64 //===----------------------------------------------------------------------===//
     65   class RefCountedBaseVPTR {
     66     mutable unsigned ref_cnt;
     67 
     68   protected:
     69     RefCountedBaseVPTR() : ref_cnt(0) {}
     70     virtual ~RefCountedBaseVPTR() {}
     71 
     72     void Retain() const { ++ref_cnt; }
     73     void Release() const {
     74       assert (ref_cnt > 0 && "Reference count is already zero.");
     75       if (--ref_cnt == 0) delete this;
     76     }
     77 
     78     template <typename T>
     79     friend class IntrusiveRefCntPtr;
     80   };
     81 
     82 //===----------------------------------------------------------------------===//
     83 /// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
     84 ///  that assumes the wrapped object has a reference count associated
     85 ///  with it that can be managed via calls to
     86 ///  IntrusivePtrAddRef/IntrusivePtrRelease.  The smart pointers
     87 ///  manage reference counts via the RAII idiom: upon creation of
     88 ///  smart pointer the reference count of the wrapped object is
     89 ///  incremented and upon destruction of the smart pointer the
     90 ///  reference count is decremented.  This class also safely handles
     91 ///  wrapping NULL pointers.
     92 ///
     93 /// Reference counting is implemented via calls to
     94 ///  Obj->Retain()/Obj->Release(). Release() is required to destroy
     95 ///  the object when the reference count reaches zero. Inheriting from
     96 ///  RefCountedBase/RefCountedBaseVPTR takes care of this
     97 ///  automatically.
     98 //===----------------------------------------------------------------------===//
     99   template <typename T>
    100   class IntrusiveRefCntPtr {
    101     T* Obj;
    102     typedef IntrusiveRefCntPtr this_type;
    103   public:
    104     typedef T element_type;
    105 
    106     explicit IntrusiveRefCntPtr() : Obj(0) {}
    107 
    108     explicit IntrusiveRefCntPtr(T* obj) : Obj(obj) {
    109       retain();
    110     }
    111 
    112     IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
    113       retain();
    114     }
    115 
    116     template <class X>
    117     IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
    118       : Obj(S.getPtr()) {
    119       retain();
    120     }
    121 
    122     IntrusiveRefCntPtr& operator=(const IntrusiveRefCntPtr& S) {
    123       replace(S.getPtr());
    124       return *this;
    125     }
    126 
    127     template <class X>
    128     IntrusiveRefCntPtr& operator=(const IntrusiveRefCntPtr<X>& S) {
    129       replace(S.getPtr());
    130       return *this;
    131     }
    132 
    133     IntrusiveRefCntPtr& operator=(T * S) {
    134       replace(S);
    135       return *this;
    136     }
    137 
    138     ~IntrusiveRefCntPtr() { release(); }
    139 
    140     T& operator*() const { return *Obj; }
    141 
    142     T* operator->() const { return Obj; }
    143 
    144     T* getPtr() const { return Obj; }
    145 
    146     typedef T* (IntrusiveRefCntPtr::*unspecified_bool_type) () const;
    147     operator unspecified_bool_type() const {
    148       return Obj == 0 ? 0 : &IntrusiveRefCntPtr::getPtr;
    149     }
    150 
    151     void swap(IntrusiveRefCntPtr& other) {
    152       T* tmp = other.Obj;
    153       other.Obj = Obj;
    154       Obj = tmp;
    155     }
    156 
    157     void resetWithoutRelease() {
    158       Obj = 0;
    159     }
    160 
    161   private:
    162     void retain() { if (Obj) Obj->Retain(); }
    163     void release() { if (Obj) Obj->Release(); }
    164 
    165     void replace(T* S) {
    166       this_type(S).swap(*this);
    167     }
    168   };
    169 
    170   template<class T, class U>
    171   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
    172                          const IntrusiveRefCntPtr<U>& B)
    173   {
    174     return A.getPtr() == B.getPtr();
    175   }
    176 
    177   template<class T, class U>
    178   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
    179                          const IntrusiveRefCntPtr<U>& B)
    180   {
    181     return A.getPtr() != B.getPtr();
    182   }
    183 
    184   template<class T, class U>
    185   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
    186                          U* B)
    187   {
    188     return A.getPtr() == B;
    189   }
    190 
    191   template<class T, class U>
    192   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
    193                          U* B)
    194   {
    195     return A.getPtr() != B;
    196   }
    197 
    198   template<class T, class U>
    199   inline bool operator==(T* A,
    200                          const IntrusiveRefCntPtr<U>& B)
    201   {
    202     return A == B.getPtr();
    203   }
    204 
    205   template<class T, class U>
    206   inline bool operator!=(T* A,
    207                          const IntrusiveRefCntPtr<U>& B)
    208   {
    209     return A != B.getPtr();
    210   }
    211 
    212 //===----------------------------------------------------------------------===//
    213 // LLVM-style downcasting support for IntrusiveRefCntPtr objects
    214 //===----------------------------------------------------------------------===//
    215 
    216   template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
    217     typedef T* SimpleType;
    218     static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
    219       return Val.getPtr();
    220     }
    221   };
    222 
    223   template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
    224     typedef T* SimpleType;
    225     static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
    226       return Val.getPtr();
    227     }
    228   };
    229 
    230 } // end namespace llvm
    231 
    232 #endif // LLVM_ADT_INTRUSIVE_REF_CNT_PTR
    233