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