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