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 //===----------------------------------------------------------------------===// 31 /// RefCountedBase - A generic base class for objects that wish to 32 /// have their lifetimes managed using reference counts. Classes 33 /// subclass RefCountedBase to obtain such functionality, and are 34 /// typically handled with IntrusiveRefCntPtr "smart pointers" (see below) 35 /// which automatically handle the management of reference counts. 36 /// Objects that subclass RefCountedBase should not be allocated on 37 /// the stack, as invoking "delete" (which is called when the 38 /// reference count hits 0) on such objects is an error. 39 //===----------------------------------------------------------------------===// 40 template <class Derived> 41 class RefCountedBase { 42 mutable unsigned ref_cnt = 0; 43 44 public: 45 RefCountedBase() = default; RefCountedBase(const RefCountedBase &)46 RefCountedBase(const RefCountedBase &) : ref_cnt(0) {} 47 Retain()48 void Retain() const { ++ref_cnt; } Release()49 void Release() const { 50 assert (ref_cnt > 0 && "Reference count is already zero."); 51 if (--ref_cnt == 0) delete static_cast<const Derived*>(this); 52 } 53 }; 54 55 //===----------------------------------------------------------------------===// 56 /// RefCountedBaseVPTR - A class that has the same function as 57 /// RefCountedBase, but with a virtual destructor. Should be used 58 /// instead of RefCountedBase for classes that already have virtual 59 /// methods to enforce dynamic allocation via 'new'. Classes that 60 /// inherit from RefCountedBaseVPTR can't be allocated on stack - 61 /// attempting to do this will produce a compile error. 62 //===----------------------------------------------------------------------===// 63 class RefCountedBaseVPTR { 64 mutable unsigned ref_cnt = 0; 65 66 virtual void anchor(); 67 68 protected: 69 RefCountedBaseVPTR() = default; RefCountedBaseVPTR(const RefCountedBaseVPTR &)70 RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {} 71 72 virtual ~RefCountedBaseVPTR() = default; 73 Retain()74 void Retain() const { ++ref_cnt; } Release()75 void Release() const { 76 assert (ref_cnt > 0 && "Reference count is already zero."); 77 if (--ref_cnt == 0) delete this; 78 } 79 80 template <typename T> 81 friend struct IntrusiveRefCntPtrInfo; 82 }; 83 84 85 template <typename T> struct IntrusiveRefCntPtrInfo { retainIntrusiveRefCntPtrInfo86 static void retain(T *obj) { obj->Retain(); } releaseIntrusiveRefCntPtrInfo87 static void release(T *obj) { obj->Release(); } 88 }; 89 90 /// \brief A thread-safe version of \c llvm::RefCountedBase. 91 /// 92 /// A generic base class for objects that wish to have their lifetimes managed 93 /// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to 94 /// obtain such functionality, and are typically handled with 95 /// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the 96 /// management of reference counts. 97 template <class Derived> 98 class ThreadSafeRefCountedBase { 99 mutable std::atomic<int> RefCount; 100 101 protected: ThreadSafeRefCountedBase()102 ThreadSafeRefCountedBase() : RefCount(0) {} 103 104 public: Retain()105 void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } 106 Release()107 void Release() const { 108 int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; 109 assert(NewRefCount >= 0 && "Reference count was already zero."); 110 if (NewRefCount == 0) 111 delete static_cast<const Derived*>(this); 112 } 113 }; 114 115 //===----------------------------------------------------------------------===// 116 /// IntrusiveRefCntPtr - A template class that implements a "smart pointer" 117 /// that assumes the wrapped object has a reference count associated 118 /// with it that can be managed via calls to 119 /// IntrusivePtrAddRef/IntrusivePtrRelease. The smart pointers 120 /// manage reference counts via the RAII idiom: upon creation of 121 /// smart pointer the reference count of the wrapped object is 122 /// incremented and upon destruction of the smart pointer the 123 /// reference count is decremented. This class also safely handles 124 /// wrapping NULL pointers. 125 /// 126 /// Reference counting is implemented via calls to 127 /// Obj->Retain()/Obj->Release(). Release() is required to destroy 128 /// the object when the reference count reaches zero. Inheriting from 129 /// RefCountedBase/RefCountedBaseVPTR takes care of this 130 /// automatically. 131 //===----------------------------------------------------------------------===// 132 template <typename T> 133 class IntrusiveRefCntPtr { 134 T* Obj = nullptr; 135 136 public: 137 typedef T element_type; 138 139 explicit IntrusiveRefCntPtr() = default; 140 IntrusiveRefCntPtr(T * obj)141 IntrusiveRefCntPtr(T* obj) : Obj(obj) { 142 retain(); 143 } 144 IntrusiveRefCntPtr(const IntrusiveRefCntPtr & S)145 IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) { 146 retain(); 147 } 148 IntrusiveRefCntPtr(IntrusiveRefCntPtr && S)149 IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) { 150 S.Obj = nullptr; 151 } 152 153 template <class X> IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> && S)154 IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) { 155 S.Obj = nullptr; 156 } 157 158 template <class X> IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> & S)159 IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S) 160 : Obj(S.get()) { 161 retain(); 162 } 163 164 IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) { 165 swap(S); 166 return *this; 167 } 168 ~IntrusiveRefCntPtr()169 ~IntrusiveRefCntPtr() { release(); } 170 171 T& operator*() const { return *Obj; } 172 173 T* operator->() const { return Obj; } 174 get()175 T* get() const { return Obj; } 176 177 explicit operator bool() const { return Obj; } 178 swap(IntrusiveRefCntPtr & other)179 void swap(IntrusiveRefCntPtr& other) { 180 T* tmp = other.Obj; 181 other.Obj = Obj; 182 Obj = tmp; 183 } 184 reset()185 void reset() { 186 release(); 187 Obj = nullptr; 188 } 189 resetWithoutRelease()190 void resetWithoutRelease() { 191 Obj = nullptr; 192 } 193 194 private: retain()195 void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); } release()196 void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); } 197 198 template <typename X> 199 friend class IntrusiveRefCntPtr; 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 <typename From> struct simplify_type; 269 270 template<class T> struct simplify_type<IntrusiveRefCntPtr<T>> { 271 typedef T* SimpleType; 272 static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) { 273 return Val.get(); 274 } 275 }; 276 277 template<class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { 278 typedef /*const*/ T* SimpleType; 279 static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) { 280 return Val.get(); 281 } 282 }; 283 284 } // end namespace llvm 285 286 #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H 287