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 <memory>
     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 //===----------------------------------------------------------------------===//
     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 #if LLVM_HAS_RVALUE_REFERENCES
    127     IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
    128       S.Obj = 0;
    129     }
    130 
    131     template <class X>
    132     IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.getPtr()) {
    133       S.Obj = 0;
    134     }
    135 #endif
    136 
    137     template <class X>
    138     IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
    139       : Obj(S.getPtr()) {
    140       retain();
    141     }
    142 
    143     IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
    144       swap(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 
    181   template<class T, class U>
    182   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
    183                          const IntrusiveRefCntPtr<U>& B)
    184   {
    185     return A.getPtr() == B.getPtr();
    186   }
    187 
    188   template<class T, class U>
    189   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
    190                          const IntrusiveRefCntPtr<U>& B)
    191   {
    192     return A.getPtr() != B.getPtr();
    193   }
    194 
    195   template<class T, class U>
    196   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
    197                          U* B)
    198   {
    199     return A.getPtr() == B;
    200   }
    201 
    202   template<class T, class U>
    203   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
    204                          U* B)
    205   {
    206     return A.getPtr() != B;
    207   }
    208 
    209   template<class T, class U>
    210   inline bool operator==(T* A,
    211                          const IntrusiveRefCntPtr<U>& B)
    212   {
    213     return A == B.getPtr();
    214   }
    215 
    216   template<class T, class U>
    217   inline bool operator!=(T* A,
    218                          const IntrusiveRefCntPtr<U>& B)
    219   {
    220     return A != B.getPtr();
    221   }
    222 
    223 //===----------------------------------------------------------------------===//
    224 // LLVM-style downcasting support for IntrusiveRefCntPtr objects
    225 //===----------------------------------------------------------------------===//
    226 
    227   template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
    228     typedef T* SimpleType;
    229     static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
    230       return Val.getPtr();
    231     }
    232   };
    233 
    234   template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
    235     typedef T* SimpleType;
    236     static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
    237       return Val.getPtr();
    238     }
    239   };
    240 
    241 } // end namespace llvm
    242 
    243 #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H
    244