Line data Source code
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 :
63 : namespace 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.
71 : template <class Derived> class RefCountedBase {
72 : mutable unsigned RefCount = 0;
73 :
74 : public:
75 696328 : RefCountedBase() = default;
76 : RefCountedBase(const RefCountedBase &) {}
77 :
78 573178 : void Retain() const { ++RefCount; }
79 :
80 962202 : void Release() const {
81 : assert(RefCount > 0 && "Reference count is already zero.");
82 1010908 : if (--RefCount == 0)
83 511436 : delete static_cast<const Derived *>(this);
84 962202 : }
85 235800 : };
86 :
87 235800 : /// A thread-safe version of \c RefCountedBase.
88 146016 : template <class Derived> class ThreadSafeRefCountedBase {
89 235800 : mutable std::atomic<int> RefCount;
90 278536 :
91 : protected:
92 278536 : ThreadSafeRefCountedBase() : RefCount(0) {}
93 142479 :
94 278536 : public:
95 46534 : void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
96 :
97 3734202 : void Release() const {
98 41766 : int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
99 46534 : assert(NewRefCount >= 0 && "Reference count was already zero.");
100 3727785 : if (NewRefCount == 0)
101 745016 : delete static_cast<const Derived *>(this);
102 3727785 : }
103 891549 : };
104 40117 :
105 38307 : /// Class you can specialize to provide custom retain/release functionality for
106 862326 : /// a type.
107 395433 : ///
108 889990 : /// Usually specializing this class is not necessary, as IntrusiveRefCntPtr
109 48450 : /// works with any type which defines Retain() and Release() functions -- you
110 227956 : /// can define those functions yourself if RefCountedBase doesn't work for you.
111 32592 : ///
112 238304 : /// One case when you might want to specialize this type is if you have
113 96870 : /// - Foo.h defines type Foo and includes Bar.h, and
114 43879 : /// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions.
115 31116 : ///
116 66810 : /// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in
117 44440 : /// the declaration of Foo. Without the declaration of Foo, normally Bar.h
118 93129 : /// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call
119 33180 : /// T::Retain and T::Release.
120 32117 : ///
121 0 : /// To resolve this, Bar.h could include a third header, FooFwd.h, which
122 44993 : /// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then
123 31601 : /// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any
124 34386 : /// functions on Foo itself, because Foo would be an incomplete type.
125 10607 : template <typename T> struct IntrusiveRefCntPtrInfo {
126 3533 : static void retain(T *obj) { obj->Retain(); }
127 3830678 : static void release(T *obj) { obj->Release(); }
128 0 : };
129 0 :
130 13990 : /// A smart pointer to a reference-counted object that inherits from
131 0 : /// RefCountedBase or ThreadSafeRefCountedBase.
132 13990 : ///
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).
136 : template <typename T> class IntrusiveRefCntPtr {
137 513388 : T *Obj = nullptr;
138 :
139 180385 : public:
140 33052 : using element_type = T;
141 91 :
142 117105 : explicit IntrusiveRefCntPtr() = default;
143 1888245 : IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); }
144 22735268 : IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); }
145 4728980 : IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; }
146 :
147 374 : template <class X>
148 81 : IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) {
149 14051 : S.Obj = nullptr;
150 : }
151 :
152 24918 : template <class X>
153 207086 : IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) {
154 52385 : retain();
155 175278 : }
156 32821 :
157 18003462 : ~IntrusiveRefCntPtr() { release(); }
158 3947 :
159 4304 : IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) {
160 1 : swap(S);
161 : return *this;
162 : }
163 45542 :
164 405 : T &operator*() const { return *Obj; }
165 1954 : T *operator->() const { return Obj; }
166 637 : T *get() const { return Obj; }
167 829942 : explicit operator bool() const { return Obj; }
168 18258 :
169 52265 : void swap(IntrusiveRefCntPtr &other) {
170 1826328 : T *tmp = other.Obj;
171 2640907 : other.Obj = Obj;
172 2258756 : Obj = tmp;
173 720 : }
174 79 :
175 730 : void reset() {
176 0 : release();
177 1294 : Obj = nullptr;
178 8894 : }
179 888 :
180 40 : void resetWithoutRelease() { Obj = nullptr; }
181 43 :
182 116649 : private:
183 41129 : void retain() {
184 29767789 : if (Obj)
185 2363 : IntrusiveRefCntPtrInfo<T>::retain(Obj);
186 0 : }
187 13302 :
188 0 : void release() {
189 24683214 : if (Obj)
190 0 : IntrusiveRefCntPtrInfo<T>::release(Obj);
191 23 : }
192 38 :
193 2466 : template <typename X> friend class IntrusiveRefCntPtr;
194 108659 : };
195 7603 :
196 63324 : template <class T, class U>
197 2337176 : inline bool operator==(const IntrusiveRefCntPtr<T> &A,
198 0 : const IntrusiveRefCntPtr<U> &B) {
199 737941 : return A.get() == B.get();
200 5522 : }
201 1920160 :
202 27797 : template <class T, class U>
203 0 : inline bool operator!=(const IntrusiveRefCntPtr<T> &A,
204 76 : const IntrusiveRefCntPtr<U> &B) {
205 762 : return A.get() != B.get();
206 1367 : }
207 91124 :
208 0 : template <class T, class U>
209 57048 : inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) {
210 36463 : return A.get() == B;
211 336778 : }
212 274257 :
213 1000699 : template <class T, class U>
214 788 : inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) {
215 273262 : return A.get() != B;
216 11707 : }
217 2406 :
218 0 : template <class T, class U>
219 10394 : inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) {
220 12 : return A == B.get();
221 2691 : }
222 0 :
223 504546 : template <class T, class U>
224 0 : inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) {
225 60 : return A != B.get();
226 0 : }
227 46 :
228 3180 : template <class T>
229 629 : bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
230 8 : return !B;
231 361 : }
232 0 :
233 0 : template <class T>
234 0 : bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
235 17944 : return B == A;
236 3190 : }
237 0 :
238 51 : template <class T>
239 0 : bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
240 0 : return !(A == B);
241 0 : }
242 33658 :
243 4182 : template <class T>
244 0 : bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
245 7 : return !(A == B);
246 11276 : }
247 11276 :
248 0 : // Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from
249 0 : // Casting.h.
250 0 : template <typename From> struct simplify_type;
251 132 :
252 0 : template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> {
253 15399 : using SimpleType = T *;
254 19662 :
255 0 : static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) {
256 32483 : return Val.get();
257 3669 : }
258 0 : };
259 0 :
260 0 : template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> {
261 0 : using SimpleType = /*const*/ T *;
262 114 :
263 0 : static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) {
264 284134 : return Val.get();
265 0 : }
266 0 : };
267 0 :
268 0 : } // end namespace llvm
269 0 :
270 0 : #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H
|