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: 49 RefCountedBase() : ref_cnt(0) {} 50 RefCountedBase(const RefCountedBase &) : ref_cnt(0) {} 51 52 void Retain() const { ++ref_cnt; } 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: 72 RefCountedBaseVPTR() : ref_cnt(0) {} 73 RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {} 74 75 virtual ~RefCountedBaseVPTR() {} 76 77 void Retain() const { ++ref_cnt; } 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 { 89 static void retain(T *obj) { obj->Retain(); } 90 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: 105 ThreadSafeRefCountedBase() : RefCount(0) {} 106 107 public: 108 void Retain() const { ++RefCount; } 109 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 142 explicit IntrusiveRefCntPtr() : Obj(nullptr) {} 143 144 IntrusiveRefCntPtr(T* obj) : Obj(obj) { 145 retain(); 146 } 147 148 IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) { 149 retain(); 150 } 151 152 IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) { 153 S.Obj = nullptr; 154 } 155 156 template <class X> 157 IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) { 158 S.Obj = 0; 159 } 160 161 template <class X> 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 172 ~IntrusiveRefCntPtr() { release(); } 173 174 T& operator*() const { return *Obj; } 175 176 T* operator->() const { return Obj; } 177 178 T* get() const { return Obj; } 179 180 LLVM_EXPLICIT operator bool() const { return Obj; } 181 182 void swap(IntrusiveRefCntPtr& other) { 183 T* tmp = other.Obj; 184 other.Obj = Obj; 185 Obj = tmp; 186 } 187 188 void reset() { 189 release(); 190 Obj = nullptr; 191 } 192 193 void resetWithoutRelease() { 194 Obj = 0; 195 } 196 197 private: 198 void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); } 199 void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); } 200 }; 201 202 template<class T, class U> 203 inline bool operator==(const IntrusiveRefCntPtr<T>& A, 204 const IntrusiveRefCntPtr<U>& B) 205 { 206 return A.get() == B.get(); 207 } 208 209 template<class T, class U> 210 inline bool operator!=(const IntrusiveRefCntPtr<T>& A, 211 const IntrusiveRefCntPtr<U>& B) 212 { 213 return A.get() != B.get(); 214 } 215 216 template<class T, class U> 217 inline bool operator==(const IntrusiveRefCntPtr<T>& A, 218 U* B) 219 { 220 return A.get() == B; 221 } 222 223 template<class T, class U> 224 inline bool operator!=(const IntrusiveRefCntPtr<T>& A, 225 U* B) 226 { 227 return A.get() != B; 228 } 229 230 template<class T, class U> 231 inline bool operator==(T* A, 232 const IntrusiveRefCntPtr<U>& B) 233 { 234 return A == B.get(); 235 } 236 237 template<class T, class U> 238 inline bool operator!=(T* A, 239 const IntrusiveRefCntPtr<U>& B) 240 { 241 return A != B.get(); 242 } 243 244 template <class T> 245 bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { 246 return !B; 247 } 248 249 template <class T> 250 bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { 251 return B == A; 252 } 253 254 template <class T> 255 bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { 256 return !(A == B); 257 } 258 259 template <class T> 260 bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { 261 return !(A == B); 262 } 263 264 //===----------------------------------------------------------------------===// 265 // LLVM-style downcasting support for IntrusiveRefCntPtr objects 266 //===----------------------------------------------------------------------===// 267 268 template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > { 269 typedef T* SimpleType; 270 static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) { 271 return Val.get(); 272 } 273 }; 274 275 template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > { 276 typedef /*const*/ T* SimpleType; 277 static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) { 278 return Val.get(); 279 } 280 }; 281 282 } // end namespace llvm 283 284 #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H 285