IntrusiveRefCntPtr.h revision 221345
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 28namespace 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