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 <atomic> 25 #include <cassert> 26 #include <cstddef> 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 /// \brief A thread-safe version of \c llvm::RefCountedBase. 93 /// 94 /// A generic base class for objects that wish to have their lifetimes managed 95 /// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to 96 /// obtain such functionality, and are typically handled with 97 /// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the 98 /// management of reference counts. 99 template <class Derived> 100 class ThreadSafeRefCountedBase { 101 mutable std::atomic<int> RefCount; 102 103 protected: 104 ThreadSafeRefCountedBase() : RefCount(0) {} 105 106 public: 107 void Retain() const { ++RefCount; } 108 109 void Release() const { 110 int NewRefCount = --RefCount; 111 assert(NewRefCount >= 0 && "Reference count was already zero."); 112 if (NewRefCount == 0) 113 delete static_cast<const Derived*>(this); 114 } 115 }; 116 117 //===----------------------------------------------------------------------===// 118 /// IntrusiveRefCntPtr - A template class that implements a "smart pointer" 119 /// that assumes the wrapped object has a reference count associated 120 /// with it that can be managed via calls to 121 /// IntrusivePtrAddRef/IntrusivePtrRelease. The smart pointers 122 /// manage reference counts via the RAII idiom: upon creation of 123 /// smart pointer the reference count of the wrapped object is 124 /// incremented and upon destruction of the smart pointer the 125 /// reference count is decremented. This class also safely handles 126 /// wrapping NULL pointers. 127 /// 128 /// Reference counting is implemented via calls to 129 /// Obj->Retain()/Obj->Release(). Release() is required to destroy 130 /// the object when the reference count reaches zero. Inheriting from 131 /// RefCountedBase/RefCountedBaseVPTR takes care of this 132 /// automatically. 133 //===----------------------------------------------------------------------===// 134 template <typename T> 135 class IntrusiveRefCntPtr { 136 T* Obj; 137 138 public: 139 typedef T element_type; 140 141 explicit IntrusiveRefCntPtr() : Obj(nullptr) {} 142 143 IntrusiveRefCntPtr(T* obj) : Obj(obj) { 144 retain(); 145 } 146 147 IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) { 148 retain(); 149 } 150 151 IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) { 152 S.Obj = nullptr; 153 } 154 155 template <class X> 156 IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) { 157 S.Obj = nullptr; 158 } 159 160 template <class X> 161 IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S) 162 : Obj(S.get()) { 163 retain(); 164 } 165 166 IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) { 167 swap(S); 168 return *this; 169 } 170 171 ~IntrusiveRefCntPtr() { release(); } 172 173 T& operator*() const { return *Obj; } 174 175 T* operator->() const { return Obj; } 176 177 T* get() const { return Obj; } 178 179 explicit operator bool() const { return Obj; } 180 181 void swap(IntrusiveRefCntPtr& other) { 182 T* tmp = other.Obj; 183 other.Obj = Obj; 184 Obj = tmp; 185 } 186 187 void reset() { 188 release(); 189 Obj = nullptr; 190 } 191 192 void resetWithoutRelease() { 193 Obj = nullptr; 194 } 195 196 private: 197 void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); } 198 void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); } 199 200 template <typename X> 201 friend class IntrusiveRefCntPtr; 202 }; 203 204 template<class T, class U> 205 inline bool operator==(const IntrusiveRefCntPtr<T>& A, 206 const IntrusiveRefCntPtr<U>& B) 207 { 208 return A.get() == B.get(); 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 U* B) 221 { 222 return A.get() == B; 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==(T* A, 234 const IntrusiveRefCntPtr<U>& B) 235 { 236 return A == B.get(); 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> 247 bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { 248 return !B; 249 } 250 251 template <class T> 252 bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { 253 return B == A; 254 } 255 256 template <class T> 257 bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { 258 return !(A == B); 259 } 260 261 template <class T> 262 bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { 263 return !(A == B); 264 } 265 266 //===----------------------------------------------------------------------===// 267 // LLVM-style downcasting support for IntrusiveRefCntPtr objects 268 //===----------------------------------------------------------------------===// 269 270 template <typename From> struct simplify_type; 271 272 template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > { 273 typedef T* SimpleType; 274 static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) { 275 return Val.get(); 276 } 277 }; 278 279 template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > { 280 typedef /*const*/ T* SimpleType; 281 static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) { 282 return Val.get(); 283 } 284 }; 285 286 } // end namespace llvm 287 288 #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H 289