blob: 5b866d14c812fc9645a0ef8285c0369ba93301ac [file] [log] [blame]
mnaganov@chromium.org08a60f52012-01-05 19:52:55 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
levin@chromium.org5c528682011-03-28 10:54:15 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_MEMORY_REF_COUNTED_H_
6#define BASE_MEMORY_REF_COUNTED_H_
levin@chromium.org5c528682011-03-28 10:54:15 +09007
robpercivalb2444342016-05-19 09:48:51 +09008#include <stddef.h>
9
akalin@chromium.orgee0b43d2012-01-31 11:16:55 +090010#include <cassert>
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +090011#include <iosfwd>
piman5e318662016-04-20 10:04:40 +090012#include <type_traits>
akalin@chromium.orgee0b43d2012-01-31 11:16:55 +090013
levin@chromium.org5c528682011-03-28 10:54:15 +090014#include "base/atomic_ref_count.h"
darin@chromium.orge585bed2011-08-06 00:34:00 +090015#include "base/base_export.h"
xiaomings@google.comb5c3d672012-08-29 05:19:51 +090016#include "base/compiler_specific.h"
avi67511492015-12-24 17:44:47 +090017#include "base/macros.h"
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090018#ifndef NDEBUG
19#include "base/logging.h"
20#endif
levin@chromium.org5c528682011-03-28 10:54:15 +090021#include "base/threading/thread_collision_warner.h"
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +090022#include "build/build_config.h"
23
levin@chromium.org5c528682011-03-28 10:54:15 +090024namespace base {
25
26namespace subtle {
27
darin@chromium.orge585bed2011-08-06 00:34:00 +090028class BASE_EXPORT RefCountedBase {
levin@chromium.org5c528682011-03-28 10:54:15 +090029 public:
levin@chromium.org5c528682011-03-28 10:54:15 +090030 bool HasOneRef() const { return ref_count_ == 1; }
31
32 protected:
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090033 RefCountedBase()
34 : ref_count_(0)
35 #ifndef NDEBUG
36 , in_dtor_(false)
37 #endif
38 {
39 }
levin@chromium.org5c528682011-03-28 10:54:15 +090040
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090041 ~RefCountedBase() {
42 #ifndef NDEBUG
43 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
44 #endif
45 }
46
47
48 void AddRef() const {
49 // TODO(maruel): Add back once it doesn't assert 500 times/sec.
50 // Current thread books the critical section "AddRelease"
51 // without release it.
52 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
53 #ifndef NDEBUG
54 DCHECK(!in_dtor_);
55 #endif
56 ++ref_count_;
57 }
levin@chromium.org5c528682011-03-28 10:54:15 +090058
59 // Returns true if the object should self-delete.
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090060 bool Release() const {
61 // TODO(maruel): Add back once it doesn't assert 500 times/sec.
62 // Current thread books the critical section "AddRelease"
63 // without release it.
64 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
65 #ifndef NDEBUG
66 DCHECK(!in_dtor_);
67 #endif
68 if (--ref_count_ == 0) {
69 #ifndef NDEBUG
70 in_dtor_ = true;
71 #endif
72 return true;
73 }
74 return false;
75 }
levin@chromium.org5c528682011-03-28 10:54:15 +090076
77 private:
78 mutable int ref_count_;
79#ifndef NDEBUG
80 mutable bool in_dtor_;
81#endif
82
83 DFAKE_MUTEX(add_release_);
84
85 DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
86};
87
darin@chromium.orge585bed2011-08-06 00:34:00 +090088class BASE_EXPORT RefCountedThreadSafeBase {
levin@chromium.org5c528682011-03-28 10:54:15 +090089 public:
levin@chromium.org5c528682011-03-28 10:54:15 +090090 bool HasOneRef() const;
91
92 protected:
93 RefCountedThreadSafeBase();
94 ~RefCountedThreadSafeBase();
95
96 void AddRef() const;
97
98 // Returns true if the object should self-delete.
99 bool Release() const;
100
101 private:
102 mutable AtomicRefCount ref_count_;
103#ifndef NDEBUG
104 mutable bool in_dtor_;
105#endif
106
107 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
108};
109
110} // namespace subtle
111
112//
113// A base class for reference counted classes. Otherwise, known as a cheap
114// knock-off of WebKit's RefCounted<T> class. To use this guy just extend your
115// class from it like so:
116//
117// class MyFoo : public base::RefCounted<MyFoo> {
118// ...
119// private:
120// friend class base::RefCounted<MyFoo>;
121// ~MyFoo();
122// };
123//
hashimotocbfd67e2016-01-07 15:24:06 +0900124// You should always make your destructor non-public, to avoid any code deleting
levin@chromium.org5c528682011-03-28 10:54:15 +0900125// the object accidently while there are references to it.
126template <class T>
127class RefCounted : public subtle::RefCountedBase {
128 public:
rsleevi@chromium.orgd55e9a42012-06-26 15:23:00 +0900129 RefCounted() {}
levin@chromium.org5c528682011-03-28 10:54:15 +0900130
131 void AddRef() const {
132 subtle::RefCountedBase::AddRef();
133 }
134
135 void Release() const {
136 if (subtle::RefCountedBase::Release()) {
137 delete static_cast<const T*>(this);
138 }
139 }
140
rsleevi@chromium.orgd55e9a42012-06-26 15:23:00 +0900141 protected:
142 ~RefCounted() {}
143
levin@chromium.org5c528682011-03-28 10:54:15 +0900144 private:
145 DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
146};
147
148// Forward declaration.
149template <class T, typename Traits> class RefCountedThreadSafe;
150
151// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref
152// count reaches 0. Overload to delete it on a different thread etc.
153template<typename T>
154struct DefaultRefCountedThreadSafeTraits {
155 static void Destruct(const T* x) {
156 // Delete through RefCountedThreadSafe to make child classes only need to be
157 // friend with RefCountedThreadSafe instead of this struct, which is an
158 // implementation detail.
159 RefCountedThreadSafe<T,
160 DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
161 }
162};
163
164//
165// A thread-safe variant of RefCounted<T>
166//
167// class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
168// ...
169// };
170//
171// If you're using the default trait, then you should add compile time
172// asserts that no one else is deleting your object. i.e.
173// private:
174// friend class base::RefCountedThreadSafe<MyFoo>;
175// ~MyFoo();
176template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
177class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
178 public:
rsleevi@chromium.orgd55e9a42012-06-26 15:23:00 +0900179 RefCountedThreadSafe() {}
levin@chromium.org5c528682011-03-28 10:54:15 +0900180
181 void AddRef() const {
182 subtle::RefCountedThreadSafeBase::AddRef();
183 }
184
185 void Release() const {
186 if (subtle::RefCountedThreadSafeBase::Release()) {
187 Traits::Destruct(static_cast<const T*>(this));
188 }
189 }
190
rsleevi@chromium.orgd55e9a42012-06-26 15:23:00 +0900191 protected:
192 ~RefCountedThreadSafe() {}
193
levin@chromium.org5c528682011-03-28 10:54:15 +0900194 private:
195 friend struct DefaultRefCountedThreadSafeTraits<T>;
196 static void DeleteInternal(const T* x) { delete x; }
197
198 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
199};
200
201//
akalin@chromium.org4c0f0602012-11-14 19:05:22 +0900202// A thread-safe wrapper for some piece of data so we can place other
203// things in scoped_refptrs<>.
levin@chromium.org5c528682011-03-28 10:54:15 +0900204//
205template<typename T>
akalin@chromium.org4c0f0602012-11-14 19:05:22 +0900206class RefCountedData
207 : public base::RefCountedThreadSafe< base::RefCountedData<T> > {
levin@chromium.org5c528682011-03-28 10:54:15 +0900208 public:
209 RefCountedData() : data() {}
210 RefCountedData(const T& in_value) : data(in_value) {}
211
212 T data;
rsleevi@chromium.org3c3d9372012-06-25 17:15:42 +0900213
214 private:
akalin@chromium.org4c0f0602012-11-14 19:05:22 +0900215 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >;
rsleevi@chromium.org3c3d9372012-06-25 17:15:42 +0900216 ~RefCountedData() {}
levin@chromium.org5c528682011-03-28 10:54:15 +0900217};
218
219} // namespace base
220
221//
222// A smart pointer class for reference counted objects. Use this class instead
223// of calling AddRef and Release manually on a reference counted object to
224// avoid common memory leaks caused by forgetting to Release an object
225// reference. Sample usage:
226//
227// class MyFoo : public RefCounted<MyFoo> {
228// ...
229// };
230//
231// void some_function() {
232// scoped_refptr<MyFoo> foo = new MyFoo();
233// foo->Method(param);
234// // |foo| is released when this function returns
235// }
236//
237// void some_other_function() {
238// scoped_refptr<MyFoo> foo = new MyFoo();
239// ...
240// foo = NULL; // explicitly releases |foo|
241// ...
242// if (foo)
243// foo->Method(param);
244// }
245//
246// The above examples show how scoped_refptr<T> acts like a pointer to T.
247// Given two scoped_refptr<T> classes, it is also possible to exchange
248// references between the two objects, like so:
249//
250// {
251// scoped_refptr<MyFoo> a = new MyFoo();
252// scoped_refptr<MyFoo> b;
253//
254// b.swap(a);
255// // now, |b| references the MyFoo object, and |a| references NULL.
256// }
257//
258// To make both |a| and |b| in the above example reference the same MyFoo
259// object, simply use the assignment operator:
260//
261// {
262// scoped_refptr<MyFoo> a = new MyFoo();
263// scoped_refptr<MyFoo> b;
264//
265// b = a;
266// // now, |a| and |b| each own a reference to the same MyFoo object.
267// }
268//
269template <class T>
270class scoped_refptr {
271 public:
xhwang@chromium.org87cb6e32012-06-20 03:33:38 +0900272 typedef T element_type;
273
levin@chromium.org5c528682011-03-28 10:54:15 +0900274 scoped_refptr() : ptr_(NULL) {
275 }
276
277 scoped_refptr(T* p) : ptr_(p) {
278 if (ptr_)
mdempsky46ffec32014-10-10 07:17:09 +0900279 AddRef(ptr_);
levin@chromium.org5c528682011-03-28 10:54:15 +0900280 }
281
danakj1a336142015-12-05 05:12:27 +0900282 // Copy constructor.
levin@chromium.org5c528682011-03-28 10:54:15 +0900283 scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
284 if (ptr_)
mdempsky46ffec32014-10-10 07:17:09 +0900285 AddRef(ptr_);
levin@chromium.org5c528682011-03-28 10:54:15 +0900286 }
287
danakj1a336142015-12-05 05:12:27 +0900288 // Copy conversion constructor.
piman5e318662016-04-20 10:04:40 +0900289 template <typename U,
290 typename = typename std::enable_if<
291 std::is_convertible<U*, T*>::value>::type>
levin@chromium.org5c528682011-03-28 10:54:15 +0900292 scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
293 if (ptr_)
mdempsky46ffec32014-10-10 07:17:09 +0900294 AddRef(ptr_);
levin@chromium.org5c528682011-03-28 10:54:15 +0900295 }
296
danakj1a336142015-12-05 05:12:27 +0900297 // Move constructor. This is required in addition to the conversion
298 // constructor below in order for clang to warn about pessimizing moves.
299 scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }
300
301 // Move conversion constructor.
piman5e318662016-04-20 10:04:40 +0900302 template <typename U,
303 typename = typename std::enable_if<
304 std::is_convertible<U*, T*>::value>::type>
kkimlabs56bcfba2015-04-14 05:49:43 +0900305 scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
306 r.ptr_ = nullptr;
307 }
308
levin@chromium.org5c528682011-03-28 10:54:15 +0900309 ~scoped_refptr() {
310 if (ptr_)
mdempsky46ffec32014-10-10 07:17:09 +0900311 Release(ptr_);
levin@chromium.org5c528682011-03-28 10:54:15 +0900312 }
313
314 T* get() const { return ptr_; }
mikhail.pozdnyakov@intel.com3d815722013-10-21 23:16:31 +0900315
dcheng8d031e12014-08-26 17:37:27 +0900316 T& operator*() const {
317 assert(ptr_ != NULL);
318 return *ptr_;
319 }
320
akalin@chromium.orgee0b43d2012-01-31 11:16:55 +0900321 T* operator->() const {
322 assert(ptr_ != NULL);
323 return ptr_;
324 }
levin@chromium.org5c528682011-03-28 10:54:15 +0900325
levin@chromium.org5c528682011-03-28 10:54:15 +0900326 scoped_refptr<T>& operator=(T* p) {
327 // AddRef first so that self assignment should work
328 if (p)
mdempsky46ffec32014-10-10 07:17:09 +0900329 AddRef(p);
mnaganov@chromium.org08a60f52012-01-05 19:52:55 +0900330 T* old_ptr = ptr_;
levin@chromium.org5c528682011-03-28 10:54:15 +0900331 ptr_ = p;
mnaganov@chromium.org08a60f52012-01-05 19:52:55 +0900332 if (old_ptr)
mdempsky46ffec32014-10-10 07:17:09 +0900333 Release(old_ptr);
levin@chromium.org5c528682011-03-28 10:54:15 +0900334 return *this;
335 }
336
337 scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
338 return *this = r.ptr_;
339 }
340
341 template <typename U>
342 scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
343 return *this = r.get();
344 }
345
kkimlabs56bcfba2015-04-14 05:49:43 +0900346 scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
danakj800d2ea2015-11-25 14:29:58 +0900347 scoped_refptr<T>(std::move(r)).swap(*this);
kkimlabs56bcfba2015-04-14 05:49:43 +0900348 return *this;
349 }
350
351 template <typename U>
352 scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
danakj800d2ea2015-11-25 14:29:58 +0900353 scoped_refptr<T>(std::move(r)).swap(*this);
kkimlabs56bcfba2015-04-14 05:49:43 +0900354 return *this;
355 }
356
levin@chromium.org5c528682011-03-28 10:54:15 +0900357 void swap(T** pp) {
358 T* p = ptr_;
359 ptr_ = *pp;
360 *pp = p;
361 }
362
363 void swap(scoped_refptr<T>& r) {
364 swap(&r.ptr_);
365 }
366
scheibd8068c42016-05-12 15:18:46 +0900367 explicit operator bool() const { return ptr_ != nullptr; }
dcheng5c3b6f32014-11-26 11:35:08 +0900368
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900369 template <typename U>
370 bool operator==(const scoped_refptr<U>& rhs) const {
371 return ptr_ == rhs.get();
372 }
373
374 template <typename U>
375 bool operator!=(const scoped_refptr<U>& rhs) const {
376 return !operator==(rhs);
377 }
378
379 template <typename U>
380 bool operator<(const scoped_refptr<U>& rhs) const {
381 return ptr_ < rhs.get();
382 }
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900383
levin@chromium.org5c528682011-03-28 10:54:15 +0900384 protected:
385 T* ptr_;
mdempsky46ffec32014-10-10 07:17:09 +0900386
387 private:
scheibd8068c42016-05-12 15:18:46 +0900388 // Friend required for move constructors that set r.ptr_ to null.
389 template <typename U>
390 friend class scoped_refptr;
391
mdempsky46ffec32014-10-10 07:17:09 +0900392 // Non-inline helpers to allow:
393 // class Opaque;
394 // extern template class scoped_refptr<Opaque>;
395 // Otherwise the compiler will complain that Opaque is an incomplete type.
396 static void AddRef(T* ptr);
397 static void Release(T* ptr);
levin@chromium.org5c528682011-03-28 10:54:15 +0900398};
399
mdempsky46ffec32014-10-10 07:17:09 +0900400template <typename T>
401void scoped_refptr<T>::AddRef(T* ptr) {
402 ptr->AddRef();
403}
404
405template <typename T>
406void scoped_refptr<T>::Release(T* ptr) {
407 ptr->Release();
408}
409
levin@chromium.org5c528682011-03-28 10:54:15 +0900410// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without
411// having to retype all the template arguments
412template <typename T>
413scoped_refptr<T> make_scoped_refptr(T* t) {
414 return scoped_refptr<T>(t);
415}
416
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900417template <typename T, typename U>
418bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
419 return lhs.get() == rhs;
420}
421
422template <typename T, typename U>
423bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
424 return lhs == rhs.get();
425}
426
robpercivalb2444342016-05-19 09:48:51 +0900427template <typename T>
428bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
429 return !static_cast<bool>(lhs);
430}
431
432template <typename T>
433bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
434 return !static_cast<bool>(rhs);
435}
436
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900437template <typename T, typename U>
438bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
439 return !operator==(lhs, rhs);
440}
441
442template <typename T, typename U>
443bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
444 return !operator==(lhs, rhs);
445}
446
447template <typename T>
robpercivalb2444342016-05-19 09:48:51 +0900448bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
449 return !operator==(lhs, null);
450}
451
452template <typename T>
453bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
454 return !operator==(null, rhs);
455}
456
457template <typename T>
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900458std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
459 return out << p.get();
460}
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900461
levin@chromium.org5c528682011-03-28 10:54:15 +0900462#endif // BASE_MEMORY_REF_COUNTED_H_