/root/doris/be/src/gutil/ref_counted.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 | | // Use of this source code is governed by a BSD-style license that can be |
3 | | // found in the LICENSE file. |
4 | | |
5 | | #pragma once |
6 | | |
7 | | #include <cassert> |
8 | | #include <cstddef> |
9 | | #include <utility> // IWYU pragma: keep |
10 | | |
11 | | #include "gutil/atomicops.h" |
12 | | #include "butil/macros.h" |
13 | | #include "gutil/threading/thread_collision_warner.h" |
14 | | |
15 | | namespace doris { |
16 | | namespace subtle { |
17 | | |
18 | | typedef Atomic32 AtomicRefCount; |
19 | | |
20 | | class RefCountedBase { |
21 | | public: |
22 | 0 | bool HasOneRef() const { return ref_count_ == 1; } |
23 | | |
24 | | protected: |
25 | | RefCountedBase(); |
26 | | ~RefCountedBase(); |
27 | | |
28 | | void AddRef() const; |
29 | | |
30 | | // Returns true if the object should self-delete. |
31 | | bool Release() const; |
32 | | |
33 | | private: |
34 | | mutable int ref_count_; |
35 | | #ifndef NDEBUG |
36 | | mutable bool in_dtor_; |
37 | | #endif |
38 | | |
39 | | DFAKE_MUTEX(add_release_); |
40 | | |
41 | | DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
42 | | }; |
43 | | |
44 | | class RefCountedThreadSafeBase { |
45 | | public: |
46 | | bool HasOneRef() const; |
47 | | |
48 | | protected: |
49 | | RefCountedThreadSafeBase(); |
50 | | ~RefCountedThreadSafeBase(); |
51 | | |
52 | | void AddRef() const; |
53 | | |
54 | | // Returns true if the object should self-delete. |
55 | | bool Release() const; |
56 | | |
57 | | private: |
58 | | mutable AtomicRefCount ref_count_; |
59 | | #ifndef NDEBUG |
60 | | mutable bool in_dtor_; |
61 | | #endif |
62 | | |
63 | | DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
64 | | }; |
65 | | |
66 | | } // namespace subtle |
67 | | |
68 | | // |
69 | | // A base class for reference counted classes. Otherwise, known as a cheap |
70 | | // knock-off of WebKit's RefCounted<T> class. To use this guy just extend your |
71 | | // class from it like so: |
72 | | // |
73 | | // class MyFoo : public RefCounted<MyFoo> { |
74 | | // ... |
75 | | // private: |
76 | | // friend class RefCounted<MyFoo>; |
77 | | // ~MyFoo(); |
78 | | // }; |
79 | | // |
80 | | // You should always make your destructor private, to avoid any code deleting |
81 | | // the object accidentally while there are references to it. |
82 | | template <class T> |
83 | | class RefCounted : public subtle::RefCountedBase { |
84 | | public: |
85 | | RefCounted() {} |
86 | | |
87 | | void AddRef() const { subtle::RefCountedBase::AddRef(); } |
88 | | |
89 | | void Release() const { |
90 | | if (subtle::RefCountedBase::Release()) { |
91 | | delete static_cast<const T*>(this); |
92 | | } |
93 | | } |
94 | | |
95 | | protected: |
96 | | ~RefCounted() {} |
97 | | }; |
98 | | |
99 | | // Forward declaration. |
100 | | template <class T, typename Traits> |
101 | | class RefCountedThreadSafe; |
102 | | |
103 | | // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref |
104 | | // count reaches 0. Overload to delete it on a different thread etc. |
105 | | template <typename T> |
106 | | struct DefaultRefCountedThreadSafeTraits { |
107 | 2.72k | static void Destruct(const T* x) { |
108 | | // Delete through RefCountedThreadSafe to make child classes only need to be |
109 | | // friend with RefCountedThreadSafe instead of this struct, which is an |
110 | | // implementation detail. |
111 | 2.72k | RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal(x); |
112 | 2.72k | } |
113 | | }; |
114 | | |
115 | | // |
116 | | // A thread-safe variant of RefCounted<T> |
117 | | // |
118 | | // class MyFoo : public RefCountedThreadSafe<MyFoo> { |
119 | | // ... |
120 | | // }; |
121 | | // |
122 | | // If you're using the default trait, then you should add compile time |
123 | | // asserts that no one else is deleting your object. i.e. |
124 | | // private: |
125 | | // friend class RefCountedThreadSafe<MyFoo>; |
126 | | // ~MyFoo(); |
127 | | template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>> |
128 | | class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
129 | | public: |
130 | 2.74k | RefCountedThreadSafe() {} |
131 | | |
132 | 6.58k | void AddRef() const { subtle::RefCountedThreadSafeBase::AddRef(); } |
133 | | |
134 | 6.55k | void Release() const { |
135 | 6.55k | if (subtle::RefCountedThreadSafeBase::Release()) { |
136 | 2.72k | Traits::Destruct(static_cast<const T*>(this)); |
137 | 2.72k | } |
138 | 6.55k | } |
139 | | |
140 | | protected: |
141 | 2.72k | ~RefCountedThreadSafe() {} |
142 | | |
143 | | private: |
144 | | friend struct DefaultRefCountedThreadSafeTraits<T>; |
145 | 2.72k | static void DeleteInternal(const T* x) { delete x; } |
146 | | |
147 | | DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe); |
148 | | }; |
149 | | |
150 | | // |
151 | | // A thread-safe wrapper for some piece of data so we can place other |
152 | | // things in scoped_refptrs<>. |
153 | | // |
154 | | template <typename T> |
155 | | class RefCountedData : public doris::RefCountedThreadSafe<doris::RefCountedData<T>> { |
156 | | public: |
157 | | RefCountedData() : data() {} |
158 | | RefCountedData(const T& in_value) : data(in_value) {} |
159 | | |
160 | | T data; |
161 | | |
162 | | private: |
163 | | friend class doris::RefCountedThreadSafe<doris::RefCountedData<T>>; |
164 | | ~RefCountedData() {} |
165 | | }; |
166 | | |
167 | | } // namespace doris |
168 | | |
169 | | // |
170 | | // A smart pointer class for reference counted objects. Use this class instead |
171 | | // of calling AddRef and Release manually on a reference counted object to |
172 | | // avoid common memory leaks caused by forgetting to Release an object |
173 | | // reference. Sample usage: |
174 | | // |
175 | | // class MyFoo : public RefCounted<MyFoo> { |
176 | | // ... |
177 | | // }; |
178 | | // |
179 | | // void some_function() { |
180 | | // scoped_refptr<MyFoo> foo = new MyFoo(); |
181 | | // foo->Method(param); |
182 | | // // |foo| is released when this function returns |
183 | | // } |
184 | | // |
185 | | // void some_other_function() { |
186 | | // scoped_refptr<MyFoo> foo = new MyFoo(); |
187 | | // ... |
188 | | // foo = NULL; // explicitly releases |foo| |
189 | | // ... |
190 | | // if (foo) |
191 | | // foo->Method(param); |
192 | | // } |
193 | | // |
194 | | // The above examples show how scoped_refptr<T> acts like a pointer to T. |
195 | | // Given two scoped_refptr<T> classes, it is also possible to exchange |
196 | | // references between the two objects, like so: |
197 | | // |
198 | | // { |
199 | | // scoped_refptr<MyFoo> a = new MyFoo(); |
200 | | // scoped_refptr<MyFoo> b; |
201 | | // |
202 | | // b.swap(a); |
203 | | // // now, |b| references the MyFoo object, and |a| references NULL. |
204 | | // } |
205 | | // |
206 | | // To make both |a| and |b| in the above example reference the same MyFoo |
207 | | // object, simply use the assignment operator: |
208 | | // |
209 | | // { |
210 | | // scoped_refptr<MyFoo> a = new MyFoo(); |
211 | | // scoped_refptr<MyFoo> b; |
212 | | // |
213 | | // b = a; |
214 | | // // now, |a| and |b| each own a reference to the same MyFoo object. |
215 | | // } |
216 | | // |
217 | | template <class T> |
218 | | class scoped_refptr { |
219 | | public: |
220 | | typedef T element_type; |
221 | | |
222 | 4.56k | scoped_refptr() : ptr_(NULL) {} |
223 | | |
224 | 2.74k | scoped_refptr(T* p) : ptr_(p) { |
225 | 2.74k | if (ptr_) ptr_->AddRef(); |
226 | 2.74k | } |
227 | | |
228 | | // Copy constructor. |
229 | 0 | scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { |
230 | 0 | if (ptr_) ptr_->AddRef(); |
231 | 0 | } |
232 | | |
233 | | // Copy conversion constructor. |
234 | | template <typename U> |
235 | | scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { |
236 | | if (ptr_) ptr_->AddRef(); |
237 | | } |
238 | | |
239 | | // Move constructor. This is required in addition to the conversion |
240 | | // constructor below in order for clang to warn about pessimizing moves. |
241 | 1 | scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.get()) { // NOLINT |
242 | 1 | r.ptr_ = nullptr; |
243 | 1 | } |
244 | | |
245 | | // Move conversion constructor. |
246 | | template <typename U> |
247 | | scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.get()) { // NOLINT |
248 | | r.ptr_ = nullptr; |
249 | | } |
250 | | |
251 | 7.30k | ~scoped_refptr() { |
252 | 7.30k | if (ptr_) ptr_->Release(); |
253 | 7.30k | } |
254 | | |
255 | 2.74k | T* get() const { return ptr_; } |
256 | | |
257 | | typedef T* scoped_refptr::*Testable; |
258 | 2.45k | operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : NULL; } |
259 | | |
260 | 13.0k | T* operator->() const { |
261 | 13.0k | assert(ptr_ != NULL); |
262 | 0 | return ptr_; |
263 | 13.0k | } |
264 | | |
265 | 1.09k | scoped_refptr<T>& operator=(T* p) { |
266 | | // AddRef first so that self assignment should work |
267 | 1.09k | if (p) p->AddRef(); |
268 | 1.09k | T* old_ptr = ptr_; |
269 | 1.09k | ptr_ = p; |
270 | 1.09k | if (old_ptr) old_ptr->Release(); |
271 | 1.09k | return *this; |
272 | 1.09k | } |
273 | | |
274 | 1.09k | scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { return *this = r.ptr_; } |
275 | | |
276 | | template <typename U> |
277 | | scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { |
278 | | return *this = r.get(); |
279 | | } |
280 | | |
281 | | scoped_refptr<T>& operator=(scoped_refptr<T>&& r) { |
282 | | scoped_refptr<T>(std::move(r)).swap(*this); |
283 | | return *this; |
284 | | } |
285 | | |
286 | | template <typename U> |
287 | | scoped_refptr<T>& operator=(scoped_refptr<U>&& r) { |
288 | | scoped_refptr<T>(std::move(r)).swap(*this); |
289 | | return *this; |
290 | | } |
291 | | |
292 | | void swap(T** pp) { |
293 | | T* p = ptr_; |
294 | | ptr_ = *pp; |
295 | | *pp = p; |
296 | | } |
297 | | |
298 | | void swap(scoped_refptr<T>& r) { swap(&r.ptr_); } |
299 | | |
300 | | // Like gscoped_ptr::reset(), drops a reference on the currently held object |
301 | | // (if any), and adds a reference to the passed-in object (if not NULL). |
302 | | void reset(T* p = NULL) { *this = p; } |
303 | | |
304 | | protected: |
305 | | T* ptr_ = nullptr; |
306 | | |
307 | | private: |
308 | | template <typename U> |
309 | | friend class scoped_refptr; |
310 | | }; |
311 | | |
312 | | // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without |
313 | | // having to retype all the template arguments |
314 | | template <typename T> |
315 | | scoped_refptr<T> make_scoped_refptr(T* t) { |
316 | | return scoped_refptr<T>(t); |
317 | | } |
318 | | |
319 | | // equal_to and hash implementations for templated scoped_refptrs suitable for |
320 | | // use with STL unordered_* containers. |
321 | | template <class T> |
322 | | struct ScopedRefPtrEqualToFunctor { |
323 | | bool operator()(const scoped_refptr<T>& x, const scoped_refptr<T>& y) const { |
324 | | return x.get() == y.get(); |
325 | | } |
326 | | }; |
327 | | |
328 | | template <class T> |
329 | | struct ScopedRefPtrHashFunctor { |
330 | | size_t operator()(const scoped_refptr<T>& p) const { return reinterpret_cast<size_t>(p.get()); } |
331 | | }; |