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