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