blob: 6c363ccd709b71d1be8a8494f73c4b1f6c2f4a43 [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"
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090017#include "base/logging.h"
gab9ef4fb62016-10-28 04:06:02 +090018#include "base/macros.h"
tzik8a083482017-04-01 06:31:24 +090019#include "base/sequence_checker.h"
levin@chromium.org5c528682011-03-28 10:54:15 +090020#include "base/threading/thread_collision_warner.h"
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +090021#include "build/build_config.h"
22
tzikbfc67702017-04-03 14:27:34 +090023template <class T>
24class scoped_refptr;
25
levin@chromium.org5c528682011-03-28 10:54:15 +090026namespace base {
27
tzikbfc67702017-04-03 14:27:34 +090028template <typename T>
29scoped_refptr<T> AdoptRef(T* t);
30
levin@chromium.org5c528682011-03-28 10:54:15 +090031namespace subtle {
32
tzikbfc67702017-04-03 14:27:34 +090033enum AdoptRefTag { kAdoptRefTag };
34enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
35enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
36
darin@chromium.orge585bed2011-08-06 00:34:00 +090037class BASE_EXPORT RefCountedBase {
levin@chromium.org5c528682011-03-28 10:54:15 +090038 public:
levin@chromium.org5c528682011-03-28 10:54:15 +090039 bool HasOneRef() const { return ref_count_ == 1; }
40
41 protected:
tzikbfc67702017-04-03 14:27:34 +090042 explicit RefCountedBase(StartRefCountFromZeroTag) {
tzik8a083482017-04-01 06:31:24 +090043#if DCHECK_IS_ON()
44 sequence_checker_.DetachFromSequence();
45#endif
46 }
levin@chromium.org5c528682011-03-28 10:54:15 +090047
tzikbfc67702017-04-03 14:27:34 +090048 explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {
49#if DCHECK_IS_ON()
50 needs_adopt_ref_ = true;
51 sequence_checker_.DetachFromSequence();
52#endif
53 }
54
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090055 ~RefCountedBase() {
gab9ef4fb62016-10-28 04:06:02 +090056#if DCHECK_IS_ON()
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090057 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
gab9ef4fb62016-10-28 04:06:02 +090058#endif
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090059 }
60
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090061 void AddRef() const {
62 // TODO(maruel): Add back once it doesn't assert 500 times/sec.
63 // Current thread books the critical section "AddRelease"
64 // without release it.
65 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
gab9ef4fb62016-10-28 04:06:02 +090066#if DCHECK_IS_ON()
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090067 DCHECK(!in_dtor_);
tzikbfc67702017-04-03 14:27:34 +090068 DCHECK(!needs_adopt_ref_)
69 << "This RefCounted object is created with non-zero reference count."
70 << " The first reference to such a object has to be made by AdoptRef or"
Taiju Tsuiki6bd129a2017-05-18 15:45:43 +090071 << " MakeRefCounted.";
tzik8a083482017-04-01 06:31:24 +090072 if (ref_count_ >= 1) {
73 DCHECK(CalledOnValidSequence());
74 }
gab9ef4fb62016-10-28 04:06:02 +090075#endif
tzik08aaedd2017-03-31 00:13:25 +090076
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090077 ++ref_count_;
78 }
levin@chromium.org5c528682011-03-28 10:54:15 +090079
80 // Returns true if the object should self-delete.
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090081 bool Release() const {
tzik08aaedd2017-03-31 00:13:25 +090082 --ref_count_;
83
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090084 // TODO(maruel): Add back once it doesn't assert 500 times/sec.
85 // Current thread books the critical section "AddRelease"
86 // without release it.
87 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
tzik08aaedd2017-03-31 00:13:25 +090088
gab9ef4fb62016-10-28 04:06:02 +090089#if DCHECK_IS_ON()
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090090 DCHECK(!in_dtor_);
tzik08aaedd2017-03-31 00:13:25 +090091 if (ref_count_ == 0)
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +090092 in_dtor_ = true;
tzik8a083482017-04-01 06:31:24 +090093
94 if (ref_count_ >= 1)
95 DCHECK(CalledOnValidSequence());
96 if (ref_count_ == 1)
97 sequence_checker_.DetachFromSequence();
gab9ef4fb62016-10-28 04:06:02 +090098#endif
tzik08aaedd2017-03-31 00:13:25 +090099
100 return ref_count_ == 0;
mikhail.pozdnyakov@intel.comd45f3e32013-12-20 05:48:41 +0900101 }
levin@chromium.org5c528682011-03-28 10:54:15 +0900102
103 private:
tzikbfc67702017-04-03 14:27:34 +0900104 template <typename U>
105 friend scoped_refptr<U> base::AdoptRef(U*);
106
107 void Adopted() const {
108#if DCHECK_IS_ON()
109 DCHECK(needs_adopt_ref_);
110 needs_adopt_ref_ = false;
111#endif
112 }
113
tzik8a083482017-04-01 06:31:24 +0900114#if DCHECK_IS_ON()
115 bool CalledOnValidSequence() const;
116#endif
117
tzik08aaedd2017-03-31 00:13:25 +0900118 mutable size_t ref_count_ = 0;
tzik8a083482017-04-01 06:31:24 +0900119
gab9ef4fb62016-10-28 04:06:02 +0900120#if DCHECK_IS_ON()
tzikbfc67702017-04-03 14:27:34 +0900121 mutable bool needs_adopt_ref_ = false;
tzik08aaedd2017-03-31 00:13:25 +0900122 mutable bool in_dtor_ = false;
tzik8a083482017-04-01 06:31:24 +0900123 mutable SequenceChecker sequence_checker_;
levin@chromium.org5c528682011-03-28 10:54:15 +0900124#endif
125
126 DFAKE_MUTEX(add_release_);
127
128 DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
129};
130
darin@chromium.orge585bed2011-08-06 00:34:00 +0900131class BASE_EXPORT RefCountedThreadSafeBase {
levin@chromium.org5c528682011-03-28 10:54:15 +0900132 public:
agrievea7fd5f12016-09-27 09:15:51 +0900133 bool HasOneRef() const;
levin@chromium.org5c528682011-03-28 10:54:15 +0900134
135 protected:
tzikbfc67702017-04-03 14:27:34 +0900136 explicit RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
137 explicit RefCountedThreadSafeBase(StartRefCountFromOneTag) : ref_count_(1) {
138#if DCHECK_IS_ON()
139 needs_adopt_ref_ = true;
140#endif
141 }
142
agrievea7fd5f12016-09-27 09:15:51 +0900143 ~RefCountedThreadSafeBase();
levin@chromium.org5c528682011-03-28 10:54:15 +0900144
agrievea7fd5f12016-09-27 09:15:51 +0900145 void AddRef() const;
levin@chromium.org5c528682011-03-28 10:54:15 +0900146
147 // Returns true if the object should self-delete.
agrievea7fd5f12016-09-27 09:15:51 +0900148 bool Release() const;
levin@chromium.org5c528682011-03-28 10:54:15 +0900149
150 private:
tzikbfc67702017-04-03 14:27:34 +0900151 template <typename U>
152 friend scoped_refptr<U> base::AdoptRef(U*);
153
154 void Adopted() const {
155#if DCHECK_IS_ON()
156 DCHECK(needs_adopt_ref_);
157 needs_adopt_ref_ = false;
158#endif
159 }
160
tzik4f3e21e2017-03-03 04:26:16 +0900161 mutable AtomicRefCount ref_count_ = 0;
gab9ef4fb62016-10-28 04:06:02 +0900162#if DCHECK_IS_ON()
tzikbfc67702017-04-03 14:27:34 +0900163 mutable bool needs_adopt_ref_ = false;
tzik4f3e21e2017-03-03 04:26:16 +0900164 mutable bool in_dtor_ = false;
levin@chromium.org5c528682011-03-28 10:54:15 +0900165#endif
166
167 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
168};
169
170} // namespace subtle
171
tzik8a083482017-04-01 06:31:24 +0900172// ScopedAllowCrossThreadRefCountAccess disables the check documented on
173// RefCounted below for rare pre-existing use cases where thread-safety was
174// guaranteed through other means (e.g. explicit sequencing of calls across
175// execution sequences when bouncing between threads in order). New callers
176// should refrain from using this (callsites handling thread-safety through
177// locks should use RefCountedThreadSafe per the overhead of its atomics being
178// negligible compared to locks anyways and callsites doing explicit sequencing
179// should properly std::move() the ref to avoid hitting this check).
180// TODO(tzik): Cleanup existing use cases and remove
181// ScopedAllowCrossThreadRefCountAccess.
182class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final {
183 public:
184#if DCHECK_IS_ON()
185 ScopedAllowCrossThreadRefCountAccess();
186 ~ScopedAllowCrossThreadRefCountAccess();
187#else
188 ScopedAllowCrossThreadRefCountAccess() {}
189 ~ScopedAllowCrossThreadRefCountAccess() {}
190#endif
191};
192
levin@chromium.org5c528682011-03-28 10:54:15 +0900193//
194// A base class for reference counted classes. Otherwise, known as a cheap
thakisab3fed82016-06-15 17:28:13 +0900195// knock-off of WebKit's RefCounted<T> class. To use this, just extend your
levin@chromium.org5c528682011-03-28 10:54:15 +0900196// class from it like so:
197//
198// class MyFoo : public base::RefCounted<MyFoo> {
199// ...
200// private:
201// friend class base::RefCounted<MyFoo>;
202// ~MyFoo();
203// };
204//
hashimotocbfd67e2016-01-07 15:24:06 +0900205// You should always make your destructor non-public, to avoid any code deleting
levin@chromium.org5c528682011-03-28 10:54:15 +0900206// the object accidently while there are references to it.
tzik8a083482017-04-01 06:31:24 +0900207//
tzikbfc67702017-04-03 14:27:34 +0900208//
tzik8a083482017-04-01 06:31:24 +0900209// The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
210// to trap unsafe cross thread usage. A subclass instance of RefCounted can be
211// passed to another execution sequence only when its ref count is 1. If the ref
212// count is more than 1, the RefCounted class verifies the ref updates are made
213// on the same execution sequence as the previous ones.
tzikbfc67702017-04-03 14:27:34 +0900214//
215//
216// The reference count starts from zero by default, and we intended to migrate
217// to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
218// the ref counted class to opt-in.
219//
220// If an object has start-from-one ref count, the first scoped_refptr need to be
Taiju Tsuiki6bd129a2017-05-18 15:45:43 +0900221// created by base::AdoptRef() or base::MakeRefCounted(). We can use
222// base::MakeRefCounted() to create create both type of ref counted object.
tzikbfc67702017-04-03 14:27:34 +0900223//
224// The motivations to use start-from-one ref count are:
225// - Start-from-one ref count doesn't need the ref count increment for the
226// first reference.
227// - It can detect an invalid object acquisition for a being-deleted object
228// that has zero ref count. That tends to happen on custom deleter that
229// delays the deletion.
230// TODO(tzik): Implement invalid acquisition detection.
231// - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
232// And start-from-one ref count is a step to merge WTF::RefCounted into
233// base::RefCounted.
234//
235#define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \
236 static constexpr ::base::subtle::StartRefCountFromOneTag \
237 kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag
238
levin@chromium.org5c528682011-03-28 10:54:15 +0900239template <class T>
240class RefCounted : public subtle::RefCountedBase {
241 public:
tzikbfc67702017-04-03 14:27:34 +0900242 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
243 subtle::kStartRefCountFromZeroTag;
244
245 RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {}
levin@chromium.org5c528682011-03-28 10:54:15 +0900246
247 void AddRef() const {
248 subtle::RefCountedBase::AddRef();
249 }
250
251 void Release() const {
252 if (subtle::RefCountedBase::Release()) {
253 delete static_cast<const T*>(this);
254 }
255 }
256
rsleevi@chromium.orgd55e9a42012-06-26 15:23:00 +0900257 protected:
gab9ef4fb62016-10-28 04:06:02 +0900258 ~RefCounted() = default;
rsleevi@chromium.orgd55e9a42012-06-26 15:23:00 +0900259
levin@chromium.org5c528682011-03-28 10:54:15 +0900260 private:
tzikbfc67702017-04-03 14:27:34 +0900261 DISALLOW_COPY_AND_ASSIGN(RefCounted);
levin@chromium.org5c528682011-03-28 10:54:15 +0900262};
263
264// Forward declaration.
265template <class T, typename Traits> class RefCountedThreadSafe;
266
267// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref
268// count reaches 0. Overload to delete it on a different thread etc.
269template<typename T>
270struct DefaultRefCountedThreadSafeTraits {
271 static void Destruct(const T* x) {
272 // Delete through RefCountedThreadSafe to make child classes only need to be
273 // friend with RefCountedThreadSafe instead of this struct, which is an
274 // implementation detail.
275 RefCountedThreadSafe<T,
276 DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
277 }
278};
279
280//
281// A thread-safe variant of RefCounted<T>
282//
283// class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
284// ...
285// };
286//
287// If you're using the default trait, then you should add compile time
288// asserts that no one else is deleting your object. i.e.
289// private:
290// friend class base::RefCountedThreadSafe<MyFoo>;
291// ~MyFoo();
tzikbfc67702017-04-03 14:27:34 +0900292//
293// We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
294// too. See the comment above the RefCounted definition for details.
levin@chromium.org5c528682011-03-28 10:54:15 +0900295template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
296class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
297 public:
tzikbfc67702017-04-03 14:27:34 +0900298 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
299 subtle::kStartRefCountFromZeroTag;
300
301 explicit RefCountedThreadSafe()
302 : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {}
levin@chromium.org5c528682011-03-28 10:54:15 +0900303
304 void AddRef() const {
305 subtle::RefCountedThreadSafeBase::AddRef();
306 }
307
308 void Release() const {
309 if (subtle::RefCountedThreadSafeBase::Release()) {
310 Traits::Destruct(static_cast<const T*>(this));
311 }
312 }
313
rsleevi@chromium.orgd55e9a42012-06-26 15:23:00 +0900314 protected:
gab9ef4fb62016-10-28 04:06:02 +0900315 ~RefCountedThreadSafe() = default;
rsleevi@chromium.orgd55e9a42012-06-26 15:23:00 +0900316
levin@chromium.org5c528682011-03-28 10:54:15 +0900317 private:
318 friend struct DefaultRefCountedThreadSafeTraits<T>;
319 static void DeleteInternal(const T* x) { delete x; }
320
321 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
322};
323
324//
akalin@chromium.org4c0f0602012-11-14 19:05:22 +0900325// A thread-safe wrapper for some piece of data so we can place other
326// things in scoped_refptrs<>.
levin@chromium.org5c528682011-03-28 10:54:15 +0900327//
328template<typename T>
akalin@chromium.org4c0f0602012-11-14 19:05:22 +0900329class RefCountedData
330 : public base::RefCountedThreadSafe< base::RefCountedData<T> > {
levin@chromium.org5c528682011-03-28 10:54:15 +0900331 public:
332 RefCountedData() : data() {}
333 RefCountedData(const T& in_value) : data(in_value) {}
334
335 T data;
rsleevi@chromium.org3c3d9372012-06-25 17:15:42 +0900336
337 private:
akalin@chromium.org4c0f0602012-11-14 19:05:22 +0900338 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >;
gab9ef4fb62016-10-28 04:06:02 +0900339 ~RefCountedData() = default;
levin@chromium.org5c528682011-03-28 10:54:15 +0900340};
341
tzikbfc67702017-04-03 14:27:34 +0900342// Creates a scoped_refptr from a raw pointer without incrementing the reference
343// count. Use this only for a newly created object whose reference count starts
344// from 1 instead of 0.
345template <typename T>
346scoped_refptr<T> AdoptRef(T* obj) {
347 using Tag = typename std::decay<decltype(T::kRefCountPreference)>::type;
348 static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value,
349 "Use AdoptRef only for the reference count starts from one.");
350
351 DCHECK(obj);
352 DCHECK(obj->HasOneRef());
353 obj->Adopted();
354 return scoped_refptr<T>(obj, subtle::kAdoptRefTag);
355}
356
357namespace subtle {
358
359template <typename T>
360scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) {
361 return scoped_refptr<T>(obj);
362}
363
364template <typename T>
365scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) {
366 return AdoptRef(obj);
367}
368
369} // namespace subtle
370
371// Constructs an instance of T, which is a ref counted type, and wraps the
372// object into a scoped_refptr.
373template <typename T, typename... Args>
Taiju Tsuiki6bd129a2017-05-18 15:45:43 +0900374scoped_refptr<T> MakeRefCounted(Args&&... args) {
tzikbfc67702017-04-03 14:27:34 +0900375 T* obj = new T(std::forward<Args>(args)...);
376 return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference);
377}
378
levin@chromium.org5c528682011-03-28 10:54:15 +0900379} // namespace base
380
381//
382// A smart pointer class for reference counted objects. Use this class instead
383// of calling AddRef and Release manually on a reference counted object to
384// avoid common memory leaks caused by forgetting to Release an object
385// reference. Sample usage:
386//
387// class MyFoo : public RefCounted<MyFoo> {
388// ...
tnagelb5d98a32016-12-01 10:19:50 +0900389// private:
390// friend class RefCounted<MyFoo>; // Allow destruction by RefCounted<>.
391// ~MyFoo(); // Destructor must be private/protected.
levin@chromium.org5c528682011-03-28 10:54:15 +0900392// };
393//
394// void some_function() {
395// scoped_refptr<MyFoo> foo = new MyFoo();
396// foo->Method(param);
397// // |foo| is released when this function returns
398// }
399//
400// void some_other_function() {
401// scoped_refptr<MyFoo> foo = new MyFoo();
402// ...
gab9ef4fb62016-10-28 04:06:02 +0900403// foo = nullptr; // explicitly releases |foo|
levin@chromium.org5c528682011-03-28 10:54:15 +0900404// ...
405// if (foo)
406// foo->Method(param);
407// }
408//
409// The above examples show how scoped_refptr<T> acts like a pointer to T.
410// Given two scoped_refptr<T> classes, it is also possible to exchange
411// references between the two objects, like so:
412//
413// {
414// scoped_refptr<MyFoo> a = new MyFoo();
415// scoped_refptr<MyFoo> b;
416//
417// b.swap(a);
gab9ef4fb62016-10-28 04:06:02 +0900418// // now, |b| references the MyFoo object, and |a| references nullptr.
levin@chromium.org5c528682011-03-28 10:54:15 +0900419// }
420//
421// To make both |a| and |b| in the above example reference the same MyFoo
422// object, simply use the assignment operator:
423//
424// {
425// scoped_refptr<MyFoo> a = new MyFoo();
426// scoped_refptr<MyFoo> b;
427//
428// b = a;
429// // now, |a| and |b| each own a reference to the same MyFoo object.
430// }
431//
432template <class T>
433class scoped_refptr {
434 public:
xhwang@chromium.org87cb6e32012-06-20 03:33:38 +0900435 typedef T element_type;
436
gabab545852016-11-01 02:03:20 +0900437 scoped_refptr() {}
levin@chromium.org5c528682011-03-28 10:54:15 +0900438
439 scoped_refptr(T* p) : ptr_(p) {
440 if (ptr_)
mdempsky46ffec32014-10-10 07:17:09 +0900441 AddRef(ptr_);
levin@chromium.org5c528682011-03-28 10:54:15 +0900442 }
443
danakj1a336142015-12-05 05:12:27 +0900444 // Copy constructor.
levin@chromium.org5c528682011-03-28 10:54:15 +0900445 scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
446 if (ptr_)
mdempsky46ffec32014-10-10 07:17:09 +0900447 AddRef(ptr_);
levin@chromium.org5c528682011-03-28 10:54:15 +0900448 }
449
danakj1a336142015-12-05 05:12:27 +0900450 // Copy conversion constructor.
piman5e318662016-04-20 10:04:40 +0900451 template <typename U,
452 typename = typename std::enable_if<
453 std::is_convertible<U*, T*>::value>::type>
levin@chromium.org5c528682011-03-28 10:54:15 +0900454 scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
455 if (ptr_)
mdempsky46ffec32014-10-10 07:17:09 +0900456 AddRef(ptr_);
levin@chromium.org5c528682011-03-28 10:54:15 +0900457 }
458
danakj1a336142015-12-05 05:12:27 +0900459 // Move constructor. This is required in addition to the conversion
460 // constructor below in order for clang to warn about pessimizing moves.
461 scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }
462
463 // Move conversion constructor.
piman5e318662016-04-20 10:04:40 +0900464 template <typename U,
465 typename = typename std::enable_if<
466 std::is_convertible<U*, T*>::value>::type>
kkimlabs56bcfba2015-04-14 05:49:43 +0900467 scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
468 r.ptr_ = nullptr;
469 }
470
levin@chromium.org5c528682011-03-28 10:54:15 +0900471 ~scoped_refptr() {
472 if (ptr_)
mdempsky46ffec32014-10-10 07:17:09 +0900473 Release(ptr_);
levin@chromium.org5c528682011-03-28 10:54:15 +0900474 }
475
476 T* get() const { return ptr_; }
mikhail.pozdnyakov@intel.com3d815722013-10-21 23:16:31 +0900477
dcheng8d031e12014-08-26 17:37:27 +0900478 T& operator*() const {
gab9ef4fb62016-10-28 04:06:02 +0900479 assert(ptr_ != nullptr);
dcheng8d031e12014-08-26 17:37:27 +0900480 return *ptr_;
481 }
482
akalin@chromium.orgee0b43d2012-01-31 11:16:55 +0900483 T* operator->() const {
gab9ef4fb62016-10-28 04:06:02 +0900484 assert(ptr_ != nullptr);
akalin@chromium.orgee0b43d2012-01-31 11:16:55 +0900485 return ptr_;
486 }
levin@chromium.org5c528682011-03-28 10:54:15 +0900487
levin@chromium.org5c528682011-03-28 10:54:15 +0900488 scoped_refptr<T>& operator=(T* p) {
489 // AddRef first so that self assignment should work
490 if (p)
mdempsky46ffec32014-10-10 07:17:09 +0900491 AddRef(p);
mnaganov@chromium.org08a60f52012-01-05 19:52:55 +0900492 T* old_ptr = ptr_;
levin@chromium.org5c528682011-03-28 10:54:15 +0900493 ptr_ = p;
mnaganov@chromium.org08a60f52012-01-05 19:52:55 +0900494 if (old_ptr)
mdempsky46ffec32014-10-10 07:17:09 +0900495 Release(old_ptr);
levin@chromium.org5c528682011-03-28 10:54:15 +0900496 return *this;
497 }
498
499 scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
500 return *this = r.ptr_;
501 }
502
503 template <typename U>
504 scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
505 return *this = r.get();
506 }
507
kkimlabs56bcfba2015-04-14 05:49:43 +0900508 scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
danakj800d2ea2015-11-25 14:29:58 +0900509 scoped_refptr<T>(std::move(r)).swap(*this);
kkimlabs56bcfba2015-04-14 05:49:43 +0900510 return *this;
511 }
512
513 template <typename U>
514 scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
danakj800d2ea2015-11-25 14:29:58 +0900515 scoped_refptr<T>(std::move(r)).swap(*this);
kkimlabs56bcfba2015-04-14 05:49:43 +0900516 return *this;
517 }
518
estevenson0976cc12017-03-09 00:31:29 +0900519 void swap(scoped_refptr<T>& r) {
tzika513a312017-03-14 22:27:36 +0900520 T* tmp = ptr_;
521 ptr_ = r.ptr_;
522 r.ptr_ = tmp;
estevenson0976cc12017-03-09 00:31:29 +0900523 }
levin@chromium.org5c528682011-03-28 10:54:15 +0900524
scheibd8068c42016-05-12 15:18:46 +0900525 explicit operator bool() const { return ptr_ != nullptr; }
dcheng5c3b6f32014-11-26 11:35:08 +0900526
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900527 template <typename U>
528 bool operator==(const scoped_refptr<U>& rhs) const {
529 return ptr_ == rhs.get();
530 }
531
532 template <typename U>
533 bool operator!=(const scoped_refptr<U>& rhs) const {
534 return !operator==(rhs);
535 }
536
537 template <typename U>
538 bool operator<(const scoped_refptr<U>& rhs) const {
539 return ptr_ < rhs.get();
540 }
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900541
levin@chromium.org5c528682011-03-28 10:54:15 +0900542 protected:
gabab545852016-11-01 02:03:20 +0900543 T* ptr_ = nullptr;
mdempsky46ffec32014-10-10 07:17:09 +0900544
545 private:
tzikbfc67702017-04-03 14:27:34 +0900546 template <typename U>
547 friend scoped_refptr<U> base::AdoptRef(U*);
548
549 scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {}
550
scheibd8068c42016-05-12 15:18:46 +0900551 // Friend required for move constructors that set r.ptr_ to null.
552 template <typename U>
553 friend class scoped_refptr;
554
mdempsky46ffec32014-10-10 07:17:09 +0900555 // Non-inline helpers to allow:
556 // class Opaque;
557 // extern template class scoped_refptr<Opaque>;
558 // Otherwise the compiler will complain that Opaque is an incomplete type.
559 static void AddRef(T* ptr);
560 static void Release(T* ptr);
levin@chromium.org5c528682011-03-28 10:54:15 +0900561};
562
gab351b98b2016-11-01 23:13:20 +0900563// static
mdempsky46ffec32014-10-10 07:17:09 +0900564template <typename T>
565void scoped_refptr<T>::AddRef(T* ptr) {
566 ptr->AddRef();
567}
568
gab351b98b2016-11-01 23:13:20 +0900569// static
mdempsky46ffec32014-10-10 07:17:09 +0900570template <typename T>
571void scoped_refptr<T>::Release(T* ptr) {
572 ptr->Release();
573}
574
levin@chromium.org5c528682011-03-28 10:54:15 +0900575// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without
576// having to retype all the template arguments
577template <typename T>
578scoped_refptr<T> make_scoped_refptr(T* t) {
579 return scoped_refptr<T>(t);
580}
581
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900582template <typename T, typename U>
583bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
584 return lhs.get() == rhs;
585}
586
587template <typename T, typename U>
588bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
589 return lhs == rhs.get();
590}
591
robpercivalb2444342016-05-19 09:48:51 +0900592template <typename T>
593bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
594 return !static_cast<bool>(lhs);
595}
596
597template <typename T>
598bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
599 return !static_cast<bool>(rhs);
600}
601
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900602template <typename T, typename U>
603bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
604 return !operator==(lhs, rhs);
605}
606
607template <typename T, typename U>
608bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
609 return !operator==(lhs, rhs);
610}
611
612template <typename T>
robpercivalb2444342016-05-19 09:48:51 +0900613bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
614 return !operator==(lhs, null);
615}
616
617template <typename T>
618bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
619 return !operator==(null, rhs);
620}
621
622template <typename T>
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900623std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
624 return out << p.get();
625}
Daniel Cheng8f6c3bf2014-09-05 16:16:45 +0900626
levin@chromium.org5c528682011-03-28 10:54:15 +0900627#endif // BASE_MEMORY_REF_COUNTED_H_