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