/src/brpc/src/butil/memory/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 | | #ifndef BUTIL_MEMORY_REF_COUNTED_H_ |
6 | | #define BUTIL_MEMORY_REF_COUNTED_H_ |
7 | | |
8 | | #include <cassert> |
9 | | |
10 | | #include "butil/atomic_ref_count.h" |
11 | | #include "butil/base_export.h" |
12 | | #include "butil/compiler_specific.h" |
13 | | #ifndef NDEBUG |
14 | | #include "butil/logging.h" |
15 | | #endif |
16 | | #include "butil/threading/thread_collision_warner.h" |
17 | | |
18 | | namespace butil { |
19 | | |
20 | | namespace subtle { |
21 | | |
22 | | class BUTIL_EXPORT RefCountedBase { |
23 | | public: |
24 | 0 | bool HasOneRef() const { return ref_count_ == 1; } |
25 | | |
26 | | protected: |
27 | | RefCountedBase() |
28 | | : ref_count_(0) |
29 | | , in_dtor_(false) |
30 | 0 | { |
31 | 0 | } |
32 | | |
33 | 0 | ~RefCountedBase() { |
34 | 0 | #ifndef NDEBUG |
35 | 0 | DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; |
36 | 0 | #endif |
37 | 0 | } |
38 | | |
39 | | |
40 | 0 | void AddRef() const { |
41 | 0 | // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
42 | 0 | // Current thread books the critical section "AddRelease" |
43 | 0 | // without release it. |
44 | 0 | // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
45 | 0 | #ifndef NDEBUG |
46 | 0 | DCHECK(!in_dtor_); |
47 | 0 | #endif |
48 | 0 | ++ref_count_; |
49 | 0 | } |
50 | | |
51 | | // Returns true if the object should self-delete. |
52 | 0 | bool Release() const { |
53 | 0 | // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
54 | 0 | // Current thread books the critical section "AddRelease" |
55 | 0 | // without release it. |
56 | 0 | // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
57 | 0 | #ifndef NDEBUG |
58 | 0 | DCHECK(!in_dtor_); |
59 | 0 | #endif |
60 | 0 | if (--ref_count_ == 0) { |
61 | 0 | #ifndef NDEBUG |
62 | 0 | in_dtor_ = true; |
63 | 0 | #endif |
64 | 0 | return true; |
65 | 0 | } |
66 | 0 | return false; |
67 | 0 | } |
68 | | |
69 | | private: |
70 | | mutable int ref_count_; |
71 | | #if defined(__clang__) |
72 | | mutable bool ALLOW_UNUSED in_dtor_; |
73 | | #else |
74 | | mutable bool in_dtor_; |
75 | | #endif |
76 | | DFAKE_MUTEX(add_release_); |
77 | | |
78 | | DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
79 | | }; |
80 | | |
81 | | class BUTIL_EXPORT RefCountedThreadSafeBase { |
82 | | public: |
83 | | bool HasOneRef() const; |
84 | | |
85 | | protected: |
86 | | RefCountedThreadSafeBase(); |
87 | | ~RefCountedThreadSafeBase(); |
88 | | |
89 | | void AddRef() const; |
90 | | |
91 | | // Returns true if the object should self-delete. |
92 | | bool Release() const; |
93 | | |
94 | | private: |
95 | | mutable AtomicRefCount ref_count_; |
96 | | #if defined(__clang__) |
97 | | mutable bool ALLOW_UNUSED in_dtor_; |
98 | | #else |
99 | | mutable bool in_dtor_; |
100 | | #endif |
101 | | |
102 | | DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
103 | | }; |
104 | | |
105 | | } // namespace subtle |
106 | | |
107 | | // |
108 | | // A base class for reference counted classes. Otherwise, known as a cheap |
109 | | // knock-off of WebKit's RefCounted<T> class. To use this guy just extend your |
110 | | // class from it like so: |
111 | | // |
112 | | // class MyFoo : public butil::RefCounted<MyFoo> { |
113 | | // ... |
114 | | // private: |
115 | | // friend class butil::RefCounted<MyFoo>; |
116 | | // ~MyFoo(); |
117 | | // }; |
118 | | // |
119 | | // You should always make your destructor private, to avoid any code deleting |
120 | | // the object accidently while there are references to it. |
121 | | template <class T> |
122 | | class RefCounted : public subtle::RefCountedBase { |
123 | | public: |
124 | | RefCounted() {} |
125 | | |
126 | | void AddRef() const { |
127 | | subtle::RefCountedBase::AddRef(); |
128 | | } |
129 | | |
130 | | void Release() const { |
131 | | if (subtle::RefCountedBase::Release()) { |
132 | | delete static_cast<const T*>(this); |
133 | | } |
134 | | } |
135 | | |
136 | | protected: |
137 | | ~RefCounted() {} |
138 | | |
139 | | private: |
140 | | DISALLOW_COPY_AND_ASSIGN(RefCounted); |
141 | | }; |
142 | | |
143 | | // Forward declaration. |
144 | | template <class T, typename Traits> class RefCountedThreadSafe; |
145 | | |
146 | | // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref |
147 | | // count reaches 0. Overload to delete it on a different thread etc. |
148 | | template<typename T> |
149 | | struct DefaultRefCountedThreadSafeTraits { |
150 | 0 | static void Destruct(const T* x) { |
151 | | // Delete through RefCountedThreadSafe to make child classes only need to be |
152 | | // friend with RefCountedThreadSafe instead of this struct, which is an |
153 | | // implementation detail. |
154 | 0 | RefCountedThreadSafe<T, |
155 | 0 | DefaultRefCountedThreadSafeTraits>::DeleteInternal(x); |
156 | 0 | } |
157 | | }; |
158 | | |
159 | | // |
160 | | // A thread-safe variant of RefCounted<T> |
161 | | // |
162 | | // class MyFoo : public butil::RefCountedThreadSafe<MyFoo> { |
163 | | // ... |
164 | | // }; |
165 | | // |
166 | | // If you're using the default trait, then you should add compile time |
167 | | // asserts that no one else is deleting your object. i.e. |
168 | | // private: |
169 | | // friend class butil::RefCountedThreadSafe<MyFoo>; |
170 | | // ~MyFoo(); |
171 | | template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
172 | | class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
173 | | public: |
174 | 0 | RefCountedThreadSafe() {} |
175 | | |
176 | 0 | void AddRef() const { |
177 | 0 | subtle::RefCountedThreadSafeBase::AddRef(); |
178 | 0 | } |
179 | | |
180 | 0 | void Release() const { |
181 | 0 | if (subtle::RefCountedThreadSafeBase::Release()) { |
182 | 0 | Traits::Destruct(static_cast<const T*>(this)); |
183 | 0 | } |
184 | 0 | } |
185 | | |
186 | | protected: |
187 | | ~RefCountedThreadSafe() {} |
188 | | |
189 | | private: |
190 | | friend struct DefaultRefCountedThreadSafeTraits<T>; |
191 | 0 | static void DeleteInternal(const T* x) { delete x; } |
192 | | |
193 | | DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe); |
194 | | }; |
195 | | |
196 | | // |
197 | | // A thread-safe wrapper for some piece of data so we can place other |
198 | | // things in scoped_refptrs<>. |
199 | | // |
200 | | template<typename T> |
201 | | class RefCountedData |
202 | | : public butil::RefCountedThreadSafe< butil::RefCountedData<T> > { |
203 | | public: |
204 | | RefCountedData() : data() {} |
205 | | RefCountedData(const T& in_value) : data(in_value) {} |
206 | | |
207 | | T data; |
208 | | |
209 | | private: |
210 | | friend class butil::RefCountedThreadSafe<butil::RefCountedData<T> >; |
211 | | ~RefCountedData() {} |
212 | | }; |
213 | | |
214 | | } // namespace butil |
215 | | |
216 | | // |
217 | | // A smart pointer class for reference counted objects. Use this class instead |
218 | | // of calling AddRef and Release manually on a reference counted object to |
219 | | // avoid common memory leaks caused by forgetting to Release an object |
220 | | // reference. Sample usage: |
221 | | // |
222 | | // class MyFoo : public RefCounted<MyFoo> { |
223 | | // ... |
224 | | // }; |
225 | | // |
226 | | // void some_function() { |
227 | | // scoped_refptr<MyFoo> foo = new MyFoo(); |
228 | | // foo->Method(param); |
229 | | // // |foo| is released when this function returns |
230 | | // } |
231 | | // |
232 | | // void some_other_function() { |
233 | | // scoped_refptr<MyFoo> foo = new MyFoo(); |
234 | | // ... |
235 | | // foo = NULL; // explicitly releases |foo| |
236 | | // ... |
237 | | // if (foo) |
238 | | // foo->Method(param); |
239 | | // } |
240 | | // |
241 | | // The above examples show how scoped_refptr<T> acts like a pointer to T. |
242 | | // Given two scoped_refptr<T> classes, it is also possible to exchange |
243 | | // references between the two objects, like so: |
244 | | // |
245 | | // { |
246 | | // scoped_refptr<MyFoo> a = new MyFoo(); |
247 | | // scoped_refptr<MyFoo> b; |
248 | | // |
249 | | // b.swap(a); |
250 | | // // now, |b| references the MyFoo object, and |a| references NULL. |
251 | | // } |
252 | | // |
253 | | // To make both |a| and |b| in the above example reference the same MyFoo |
254 | | // object, simply use the assignment operator: |
255 | | // |
256 | | // { |
257 | | // scoped_refptr<MyFoo> a = new MyFoo(); |
258 | | // scoped_refptr<MyFoo> b; |
259 | | // |
260 | | // b = a; |
261 | | // // now, |a| and |b| each own a reference to the same MyFoo object. |
262 | | // } |
263 | | // |
264 | | template <class T> |
265 | | class scoped_refptr { |
266 | | public: |
267 | | typedef T element_type; |
268 | | |
269 | | scoped_refptr() : ptr_(NULL) { |
270 | | } |
271 | | |
272 | 0 | scoped_refptr(T* p) : ptr_(p) { |
273 | 0 | if (ptr_) |
274 | 0 | ptr_->AddRef(); |
275 | 0 | } |
276 | | |
277 | | scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { |
278 | | if (ptr_) |
279 | | ptr_->AddRef(); |
280 | | } |
281 | | |
282 | | template <typename U> |
283 | | scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { |
284 | | if (ptr_) |
285 | | ptr_->AddRef(); |
286 | | } |
287 | | |
288 | | scoped_refptr(scoped_refptr<T>&& r) noexcept { |
289 | | ptr_ = r.ptr_; |
290 | | r.ptr_ = nullptr; |
291 | | } |
292 | | |
293 | | template <typename U> |
294 | | scoped_refptr(scoped_refptr<U>&& r) noexcept { |
295 | | ptr_ = r.ptr_; |
296 | | r.ptr_ = nullptr; |
297 | | } |
298 | | |
299 | 0 | ~scoped_refptr() { |
300 | 0 | if (ptr_) |
301 | 0 | ptr_->Release(); |
302 | 0 | } |
303 | | |
304 | | T* get() const { return ptr_; } |
305 | | |
306 | | // Allow scoped_refptr<C> to be used in boolean expression |
307 | | // and comparison operations. |
308 | | operator T*() const { return ptr_; } |
309 | | |
310 | 0 | T* operator->() const { |
311 | 0 | assert(ptr_ != NULL); |
312 | 0 | return ptr_; |
313 | 0 | } |
314 | | |
315 | | scoped_refptr<T>& operator=(T* p) { |
316 | | // AddRef first so that self assignment should work |
317 | | if (p) |
318 | | p->AddRef(); |
319 | | T* old_ptr = ptr_; |
320 | | ptr_ = p; |
321 | | if (old_ptr) |
322 | | old_ptr->Release(); |
323 | | return *this; |
324 | | } |
325 | | |
326 | | scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { |
327 | | return *this = r.ptr_; |
328 | | } |
329 | | |
330 | | template <typename U> |
331 | | scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { |
332 | | return *this = r.get(); |
333 | | } |
334 | | |
335 | | void swap(T** pp) { |
336 | | T* p = ptr_; |
337 | | ptr_ = *pp; |
338 | | *pp = p; |
339 | | } |
340 | | |
341 | | void swap(scoped_refptr<T>& r) { |
342 | | swap(&r.ptr_); |
343 | | } |
344 | | |
345 | | // Release ownership of ptr_, keeping its reference counter unchanged. |
346 | | T* release() WARN_UNUSED_RESULT { |
347 | | T* saved_ptr = NULL; |
348 | | swap(&saved_ptr); |
349 | | return saved_ptr; |
350 | | } |
351 | | |
352 | | protected: |
353 | | T* ptr_; |
354 | | }; |
355 | | |
356 | | // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without |
357 | | // having to retype all the template arguments |
358 | | template <typename T> |
359 | | scoped_refptr<T> make_scoped_refptr(T* t) { |
360 | | return scoped_refptr<T>(t); |
361 | | } |
362 | | |
363 | | #endif // BUTIL_MEMORY_REF_COUNTED_H_ |