1//==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8/// 9/// \file 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/// ``` 22/// class MyClass : public RefCountedBase<MyClass> {}; 23/// 24/// void foo() { 25/// // Constructing an IntrusiveRefCntPtr increases the pointee's refcount 26/// // by 1 (from 0 in this case). 27/// IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass()); 28/// 29/// // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1. 30/// IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1); 31/// 32/// // Constructing an IntrusiveRefCntPtr has no effect on the object's 33/// // refcount. After a move, the moved-from pointer is null. 34/// IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1)); 35/// assert(Ptr1 == nullptr); 36/// 37/// // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1. 38/// Ptr2.reset(); 39/// 40/// // The object deletes itself when we return from the function, because 41/// // Ptr3's destructor decrements its refcount to 0. 42/// } 43/// ``` 44/// 45/// You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.: 46/// 47/// ``` 48/// IntrusiveRefCntPtr<MyClass> Ptr(new MyClass()); 49/// OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required 50/// ``` 51/// 52/// IntrusiveRefCntPtr works with any class that 53/// 54/// - inherits from (ThreadSafe)RefCountedBase, 55/// - has Retain() and Release() methods, or 56/// - specializes IntrusiveRefCntPtrInfo. 57/// 58//===----------------------------------------------------------------------===// 59 60#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H 61#define LLVM_ADT_INTRUSIVEREFCNTPTR_H 62 63#include <atomic> 64#include <cassert> 65#include <cstddef> 66#include <memory> 67 68namespace llvm { 69 70/// A CRTP mixin class that adds reference counting to a type. 71/// 72/// The lifetime of an object which inherits from RefCountedBase is managed by 73/// calls to Release() and Retain(), which increment and decrement the object's 74/// refcount, respectively. When a Release() call decrements the refcount to 0, 75/// the object deletes itself. 76template <class Derived> class RefCountedBase { 77 mutable unsigned RefCount = 0; 78 79protected: 80 RefCountedBase() = default; 81 RefCountedBase(const RefCountedBase &) {} 82 RefCountedBase &operator=(const RefCountedBase &) = delete; 83 84#ifndef NDEBUG 85 ~RefCountedBase() { 86 assert(RefCount == 0 && 87 "Destruction occurred when there are still references to this."); 88 } 89#else 90 // Default the destructor in release builds, A trivial destructor may enable 91 // better codegen. 92 ~RefCountedBase() = default; 93#endif 94 95public: 96 unsigned UseCount() const { return RefCount; } 97 98 void Retain() const { ++RefCount; } 99 100 void Release() const { 101 assert(RefCount > 0 && "Reference count is already zero."); 102 if (--RefCount == 0) 103 delete static_cast<const Derived *>(this); 104 } 105}; 106 107/// A thread-safe version of \c RefCountedBase. 108template <class Derived> class ThreadSafeRefCountedBase { 109 mutable std::atomic<int> RefCount{0}; 110 111protected: 112 ThreadSafeRefCountedBase() = default; 113 ThreadSafeRefCountedBase(const ThreadSafeRefCountedBase &) {} 114 ThreadSafeRefCountedBase & 115 operator=(const ThreadSafeRefCountedBase &) = delete; 116 117#ifndef NDEBUG 118 ~ThreadSafeRefCountedBase() { 119 assert(RefCount == 0 && 120 "Destruction occurred when there are still references to this."); 121 } 122#else 123 // Default the destructor in release builds, A trivial destructor may enable 124 // better codegen. 125 ~ThreadSafeRefCountedBase() = default; 126#endif 127 128public: 129 unsigned UseCount() const { return RefCount.load(std::memory_order_relaxed); } 130 131 void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } 132 133 void Release() const { 134 int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; 135 assert(NewRefCount >= 0 && "Reference count was already zero."); 136 if (NewRefCount == 0) 137 delete static_cast<const Derived *>(this); 138 } 139}; 140 141/// Class you can specialize to provide custom retain/release functionality for 142/// a type. 143/// 144/// Usually specializing this class is not necessary, as IntrusiveRefCntPtr 145/// works with any type which defines Retain() and Release() functions -- you 146/// can define those functions yourself if RefCountedBase doesn't work for you. 147/// 148/// One case when you might want to specialize this type is if you have 149/// - Foo.h defines type Foo and includes Bar.h, and 150/// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions. 151/// 152/// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in 153/// the declaration of Foo. Without the declaration of Foo, normally Bar.h 154/// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call 155/// T::Retain and T::Release. 156/// 157/// To resolve this, Bar.h could include a third header, FooFwd.h, which 158/// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then 159/// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any 160/// functions on Foo itself, because Foo would be an incomplete type. 161template <typename T> struct IntrusiveRefCntPtrInfo { 162 static unsigned useCount(const T *obj) { return obj->UseCount(); } 163 static void retain(T *obj) { obj->Retain(); } 164 static void release(T *obj) { obj->Release(); } 165}; 166 167/// A smart pointer to a reference-counted object that inherits from 168/// RefCountedBase or ThreadSafeRefCountedBase. 169/// 170/// This class increments its pointee's reference count when it is created, and 171/// decrements its refcount when it's destroyed (or is changed to point to a 172/// different object). 173template <typename T> class IntrusiveRefCntPtr { 174 T *Obj = nullptr; 175 176public: 177 using element_type = T; 178 179 explicit IntrusiveRefCntPtr() = default; 180 IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } 181 IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } 182 IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } 183 184 template <class X, 185 std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true> 186 IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> S) : Obj(S.get()) { 187 S.Obj = nullptr; 188 } 189 190 template <class X, 191 std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true> 192 IntrusiveRefCntPtr(std::unique_ptr<X> S) : Obj(S.release()) { 193 retain(); 194 } 195 196 ~IntrusiveRefCntPtr() { release(); } 197 198 IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { 199 swap(S); 200 return *this; 201 } 202 203 T &operator*() const { return *Obj; } 204 T *operator->() const { return Obj; } 205 T *get() const { return Obj; } 206 explicit operator bool() const { return Obj; } 207 208 void swap(IntrusiveRefCntPtr &other) { 209 T *tmp = other.Obj; 210 other.Obj = Obj; 211 Obj = tmp; 212 } 213 214 void reset() { 215 release(); 216 Obj = nullptr; 217 } 218 219 void resetWithoutRelease() { Obj = nullptr; } 220 221 unsigned useCount() const { 222 return Obj ? IntrusiveRefCntPtrInfo<T>::useCount(Obj) : 0; 223 } 224 225private: 226 void retain() { 227 if (Obj) 228 IntrusiveRefCntPtrInfo<T>::retain(Obj); 229 } 230 231 void release() { 232 if (Obj) 233 IntrusiveRefCntPtrInfo<T>::release(Obj); 234 } 235 236 template <typename X> friend class IntrusiveRefCntPtr; 237}; 238 239template <class T, class U> 240inline bool operator==(const IntrusiveRefCntPtr<T> &A, 241 const IntrusiveRefCntPtr<U> &B) { 242 return A.get() == B.get(); 243} 244 245template <class T, class U> 246inline bool operator!=(const IntrusiveRefCntPtr<T> &A, 247 const IntrusiveRefCntPtr<U> &B) { 248 return A.get() != B.get(); 249} 250 251template <class T, class U> 252inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) { 253 return A.get() == B; 254} 255 256template <class T, class U> 257inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) { 258 return A.get() != B; 259} 260 261template <class T, class U> 262inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) { 263 return A == B.get(); 264} 265 266template <class T, class U> 267inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) { 268 return A != B.get(); 269} 270 271template <class T> 272bool operator==(std::nullptr_t, const IntrusiveRefCntPtr<T> &B) { 273 return !B; 274} 275 276template <class T> 277bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { 278 return B == A; 279} 280 281template <class T> 282bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { 283 return !(A == B); 284} 285 286template <class T> 287bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { 288 return !(A == B); 289} 290 291// Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from 292// Casting.h. 293template <typename From> struct simplify_type; 294 295template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> { 296 using SimpleType = T *; 297 298 static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { 299 return Val.get(); 300 } 301}; 302 303template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { 304 using SimpleType = /*const*/ T *; 305 306 static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { 307 return Val.get(); 308 } 309}; 310 311/// Factory function for creating intrusive ref counted pointers. 312template <typename T, typename... Args> 313IntrusiveRefCntPtr<T> makeIntrusiveRefCnt(Args &&...A) { 314 return IntrusiveRefCntPtr<T>(new T(std::forward<Args>(A)...)); 315} 316 317} // end namespace llvm 318 319#endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H 320