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 the RefCountedBase, ThreadSafeRefCountedBase, and 11// IntrusiveRefCntPtr classes. 12// 13// IntrusiveRefCntPtr is a smart pointer to an object which maintains a 14// reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a 15// refcount member variable and methods for updating the refcount. An object 16// that inherits from (ThreadSafe)RefCountedBase deletes itself when its 17// refcount hits zero. 18// 19// For example: 20// 21// class MyClass : public RefCountedBase<MyClass> {}; 22// 23// void foo() { 24// // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by 25// // 1 (from 0 in this case). 26// IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass()); 27// 28// // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1. 29// IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1); 30// 31// // Constructing an IntrusiveRefCntPtr has no effect on the object's 32// // refcount. After a move, the moved-from pointer is null. 33// IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1)); 34// assert(Ptr1 == nullptr); 35// 36// // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1. 37// Ptr2.reset(); 38// 39// // The object deletes itself when we return from the function, because 40// // Ptr3's destructor decrements its refcount to 0. 41// } 42// 43// You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.: 44// 45// IntrusiveRefCntPtr<MyClass> Ptr(new MyClass()); 46// OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required 47// 48// IntrusiveRefCntPtr works with any class that 49// 50// - inherits from (ThreadSafe)RefCountedBase, 51// - has Retain() and Release() methods, or 52// - specializes IntrusiveRefCntPtrInfo. 53// 54//===----------------------------------------------------------------------===// 55 56#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H 57#define LLVM_ADT_INTRUSIVEREFCNTPTR_H 58 59#include <atomic> 60#include <cassert> 61#include <cstddef> 62 63namespace llvm { 64 65/// A CRTP mixin class that adds reference counting to a type. 66/// 67/// The lifetime of an object which inherits from RefCountedBase is managed by 68/// calls to Release() and Retain(), which increment and decrement the object's 69/// refcount, respectively. When a Release() call decrements the refcount to 0, 70/// the object deletes itself. 71template <class Derived> class RefCountedBase { 72 mutable unsigned RefCount = 0; 73 74public: 75 RefCountedBase() = default; 76 RefCountedBase(const RefCountedBase &) {} 77 78 void Retain() const { ++RefCount; } 79 80 void Release() const { 81 assert(RefCount > 0 && "Reference count is already zero."); 82 if (--RefCount == 0) 83 delete static_cast<const Derived *>(this); 84 } 85}; 86 87/// A thread-safe version of \c RefCountedBase. 88template <class Derived> class ThreadSafeRefCountedBase { 89 mutable std::atomic<int> RefCount; 90 91protected: 92 ThreadSafeRefCountedBase() : RefCount(0) {} 93 94public: 95 void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } 96 97 void Release() const { 98 int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; 99 assert(NewRefCount >= 0 && "Reference count was already zero."); 100 if (NewRefCount == 0) 101 delete static_cast<const Derived *>(this); 102 } 103}; 104 105/// Class you can specialize to provide custom retain/release functionality for 106/// a type. 107/// 108/// Usually specializing this class is not necessary, as IntrusiveRefCntPtr 109/// works with any type which defines Retain() and Release() functions -- you 110/// can define those functions yourself if RefCountedBase doesn't work for you. 111/// 112/// One case when you might want to specialize this type is if you have 113/// - Foo.h defines type Foo and includes Bar.h, and 114/// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions. 115/// 116/// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in 117/// the declaration of Foo. Without the declaration of Foo, normally Bar.h 118/// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call 119/// T::Retain and T::Release. 120/// 121/// To resolve this, Bar.h could include a third header, FooFwd.h, which 122/// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then 123/// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any 124/// functions on Foo itself, because Foo would be an incomplete type. 125template <typename T> struct IntrusiveRefCntPtrInfo { 126 static void retain(T *obj) { obj->Retain(); } 127 static void release(T *obj) { obj->Release(); } 128}; 129 130/// A smart pointer to a reference-counted object that inherits from 131/// RefCountedBase or ThreadSafeRefCountedBase. 132/// 133/// This class increments its pointee's reference count when it is created, and 134/// decrements its refcount when it's destroyed (or is changed to point to a 135/// different object). 136template <typename T> class IntrusiveRefCntPtr { 137 T *Obj = nullptr; 138 139public: 140 using element_type = T; 141 142 explicit IntrusiveRefCntPtr() = default; 143 IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } 144 IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } 145 IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } 146 147 template <class X> 148 IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) { 149 S.Obj = nullptr; 150 } 151 152 template <class X> 153 IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) { 154 retain(); 155 } 156 157 ~IntrusiveRefCntPtr() { release(); } 158 159 IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { 160 swap(S); 161 return *this; 162 } 163 164 T &operator*() const { return *Obj; } 165 T *operator->() const { return Obj; } 166 T *get() const { return Obj; } 167 explicit operator bool() const { return Obj; } 168 169 void swap(IntrusiveRefCntPtr &other) { 170 T *tmp = other.Obj; 171 other.Obj = Obj; 172 Obj = tmp; 173 } 174 175 void reset() { 176 release(); 177 Obj = nullptr; 178 } 179 180 void resetWithoutRelease() { Obj = nullptr; } 181 182private: 183 void retain() { 184 if (Obj) 185 IntrusiveRefCntPtrInfo<T>::retain(Obj); 186 } 187 188 void release() { 189 if (Obj) 190 IntrusiveRefCntPtrInfo<T>::release(Obj); 191 } 192 193 template <typename X> friend class IntrusiveRefCntPtr; 194}; 195 196template <class T, class U> 197inline bool operator==(const IntrusiveRefCntPtr<T> &A, 198 const IntrusiveRefCntPtr<U> &B) { 199 return A.get() == B.get(); 200} 201 202template <class T, class U> 203inline bool operator!=(const IntrusiveRefCntPtr<T> &A, 204 const IntrusiveRefCntPtr<U> &B) { 205 return A.get() != B.get(); 206} 207 208template <class T, class U> 209inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) { 210 return A.get() == B; 211} 212 213template <class T, class U> 214inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) { 215 return A.get() != B; 216} 217 218template <class T, class U> 219inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) { 220 return A == B.get(); 221} 222 223template <class T, class U> 224inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) { 225 return A != B.get(); 226} 227 228template <class T> 229bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { 230 return !B; 231} 232 233template <class T> 234bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { 235 return B == A; 236} 237 238template <class T> 239bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { 240 return !(A == B); 241} 242 243template <class T> 244bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { 245 return !(A == B); 246} 247 248// Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from 249// Casting.h. 250template <typename From> struct simplify_type; 251 252template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> { 253 using SimpleType = T *; 254 255 static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { 256 return Val.get(); 257 } 258}; 259 260template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { 261 using SimpleType = /*const*/ T *; 262 263 static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { 264 return Val.get(); 265 } 266}; 267 268} // end namespace llvm 269 270#endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H 271