| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef BASE_MEMORY_REF_COUNTED_H_ | 5 #ifndef BASE_MEMORY_REF_COUNTED_H_ |
| 6 #define BASE_MEMORY_REF_COUNTED_H_ | 6 #define BASE_MEMORY_REF_COUNTED_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <cassert> | 10 #include <cassert> |
| 11 #include <iosfwd> | 11 #include <iosfwd> |
| 12 #include <type_traits> | 12 #include <type_traits> |
| 13 | 13 |
| 14 #include "base/atomic_ref_count.h" | 14 #include "base/atomic_ref_count.h" |
| 15 #include "base/base_export.h" | 15 #include "base/base_export.h" |
| 16 #include "base/compiler_specific.h" | 16 #include "base/compiler_specific.h" |
| 17 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/macros.h" | 18 #include "base/macros.h" |
| 19 #include "base/threading/thread_collision_warner.h" | 19 #include "base/threading/thread_collision_warner.h" |
| 20 #include "build/build_config.h" | 20 #include "build/build_config.h" |
| 21 | 21 |
| 22 template <class T> |
| 23 class scoped_refptr; |
| 24 |
| 22 namespace base { | 25 namespace base { |
| 23 | 26 |
| 27 template <typename T> |
| 28 scoped_refptr<T> AdoptRef(T* t); |
| 29 |
| 24 namespace subtle { | 30 namespace subtle { |
| 25 | 31 |
| 32 enum AdoptRefTag { kAdoptRefTag }; |
| 33 enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag }; |
| 34 enum StartRefCountFromOneTag { kStartRefCountFromOneTag }; |
| 35 |
| 26 class BASE_EXPORT RefCountedBase { | 36 class BASE_EXPORT RefCountedBase { |
| 27 public: | 37 public: |
| 28 bool HasOneRef() const { return ref_count_ == 1; } | 38 bool HasOneRef() const { return ref_count_ == 1; } |
| 29 | 39 |
| 30 protected: | 40 protected: |
| 31 RefCountedBase() {} | 41 explicit RefCountedBase(StartRefCountFromZeroTag) {} |
| 42 explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) { |
| 43 #if DCHECK_IS_ON() |
| 44 needs_adopt_ref_ = true; |
| 45 #endif |
| 46 } |
| 32 | 47 |
| 33 ~RefCountedBase() { | 48 ~RefCountedBase() { |
| 34 #if DCHECK_IS_ON() | 49 #if DCHECK_IS_ON() |
| 35 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; | 50 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; |
| 36 #endif | 51 #endif |
| 37 } | 52 } |
| 38 | 53 |
| 39 void AddRef() const { | 54 void AddRef() const { |
| 40 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 55 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
| 41 // Current thread books the critical section "AddRelease" | 56 // Current thread books the critical section "AddRelease" |
| 42 // without release it. | 57 // without release it. |
| 43 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 58 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
| 44 #if DCHECK_IS_ON() | 59 #if DCHECK_IS_ON() |
| 45 DCHECK(!in_dtor_); | 60 DCHECK(!in_dtor_); |
| 61 DCHECK(!needs_adopt_ref_) |
| 62 << "This RefCounted object is created with non-zero reference count." |
| 63 << " The first reference to such a object has to be made by AdoptRef or" |
| 64 << " MakeShared."; |
| 46 #endif | 65 #endif |
| 47 | 66 |
| 48 ++ref_count_; | 67 ++ref_count_; |
| 49 } | 68 } |
| 50 | 69 |
| 51 // Returns true if the object should self-delete. | 70 // Returns true if the object should self-delete. |
| 52 bool Release() const { | 71 bool Release() const { |
| 53 --ref_count_; | 72 --ref_count_; |
| 54 | 73 |
| 55 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 74 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
| 56 // Current thread books the critical section "AddRelease" | 75 // Current thread books the critical section "AddRelease" |
| 57 // without release it. | 76 // without release it. |
| 58 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 77 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
| 59 | 78 |
| 60 #if DCHECK_IS_ON() | 79 #if DCHECK_IS_ON() |
| 61 DCHECK(!in_dtor_); | 80 DCHECK(!in_dtor_); |
| 62 if (ref_count_ == 0) | 81 if (ref_count_ == 0) |
| 63 in_dtor_ = true; | 82 in_dtor_ = true; |
| 64 #endif | 83 #endif |
| 65 | 84 |
| 66 return ref_count_ == 0; | 85 return ref_count_ == 0; |
| 67 } | 86 } |
| 68 | 87 |
| 69 private: | 88 private: |
| 89 template <typename U> |
| 90 friend scoped_refptr<U> base::AdoptRef(U*); |
| 91 |
| 92 void Adopted() const { |
| 93 #if DCHECK_IS_ON() |
| 94 DCHECK(needs_adopt_ref_); |
| 95 needs_adopt_ref_ = false; |
| 96 #endif |
| 97 } |
| 98 |
| 70 mutable size_t ref_count_ = 0; | 99 mutable size_t ref_count_ = 0; |
| 100 |
| 71 #if DCHECK_IS_ON() | 101 #if DCHECK_IS_ON() |
| 102 mutable bool needs_adopt_ref_ = false; |
| 72 mutable bool in_dtor_ = false; | 103 mutable bool in_dtor_ = false; |
| 73 #endif | 104 #endif |
| 74 | 105 |
| 75 DFAKE_MUTEX(add_release_); | 106 DFAKE_MUTEX(add_release_); |
| 76 | 107 |
| 77 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); | 108 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
| 78 }; | 109 }; |
| 79 | 110 |
| 80 class BASE_EXPORT RefCountedThreadSafeBase { | 111 class BASE_EXPORT RefCountedThreadSafeBase { |
| 81 public: | 112 public: |
| 82 bool HasOneRef() const; | 113 bool HasOneRef() const; |
| 83 | 114 |
| 84 protected: | 115 protected: |
| 85 RefCountedThreadSafeBase(); | 116 explicit RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} |
| 117 explicit RefCountedThreadSafeBase(StartRefCountFromOneTag) : ref_count_(1) { |
| 118 #if DCHECK_IS_ON() |
| 119 needs_adopt_ref_ = true; |
| 120 #endif |
| 121 } |
| 122 |
| 86 ~RefCountedThreadSafeBase(); | 123 ~RefCountedThreadSafeBase(); |
| 87 | 124 |
| 88 void AddRef() const; | 125 void AddRef() const; |
| 89 | 126 |
| 90 // Returns true if the object should self-delete. | 127 // Returns true if the object should self-delete. |
| 91 bool Release() const; | 128 bool Release() const; |
| 92 | 129 |
| 93 private: | 130 private: |
| 131 template <typename U> |
| 132 friend scoped_refptr<U> base::AdoptRef(U*); |
| 133 |
| 134 void Adopted() const { |
| 135 #if DCHECK_IS_ON() |
| 136 DCHECK(needs_adopt_ref_); |
| 137 needs_adopt_ref_ = false; |
| 138 #endif |
| 139 } |
| 140 |
| 94 mutable AtomicRefCount ref_count_ = 0; | 141 mutable AtomicRefCount ref_count_ = 0; |
| 95 #if DCHECK_IS_ON() | 142 #if DCHECK_IS_ON() |
| 143 mutable bool needs_adopt_ref_ = false; |
| 96 mutable bool in_dtor_ = false; | 144 mutable bool in_dtor_ = false; |
| 97 #endif | 145 #endif |
| 98 | 146 |
| 99 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); | 147 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
| 100 }; | 148 }; |
| 101 | 149 |
| 102 } // namespace subtle | 150 } // namespace subtle |
| 103 | 151 |
| 104 // | 152 // |
| 105 // A base class for reference counted classes. Otherwise, known as a cheap | 153 // A base class for reference counted classes. Otherwise, known as a cheap |
| 106 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your | 154 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your |
| 107 // class from it like so: | 155 // class from it like so: |
| 108 // | 156 // |
| 109 // class MyFoo : public base::RefCounted<MyFoo> { | 157 // class MyFoo : public base::RefCounted<MyFoo> { |
| 110 // ... | 158 // ... |
| 111 // private: | 159 // private: |
| 112 // friend class base::RefCounted<MyFoo>; | 160 // friend class base::RefCounted<MyFoo>; |
| 113 // ~MyFoo(); | 161 // ~MyFoo(); |
| 114 // }; | 162 // }; |
| 115 // | 163 // |
| 116 // You should always make your destructor non-public, to avoid any code deleting | 164 // You should always make your destructor non-public, to avoid any code deleting |
| 117 // the object accidently while there are references to it. | 165 // the object accidently while there are references to it. |
| 118 template <class T> | 166 template <class T> |
| 119 class RefCounted : public subtle::RefCountedBase { | 167 class RefCounted : public subtle::RefCountedBase { |
| 120 public: | 168 public: |
| 121 RefCounted() = default; | 169 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
| 170 subtle::kStartRefCountFromZeroTag; |
| 171 |
| 172 RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {} |
| 122 | 173 |
| 123 void AddRef() const { | 174 void AddRef() const { |
| 124 subtle::RefCountedBase::AddRef(); | 175 subtle::RefCountedBase::AddRef(); |
| 125 } | 176 } |
| 126 | 177 |
| 127 void Release() const { | 178 void Release() const { |
| 128 if (subtle::RefCountedBase::Release()) { | 179 if (subtle::RefCountedBase::Release()) { |
| 129 delete static_cast<const T*>(this); | 180 delete static_cast<const T*>(this); |
| 130 } | 181 } |
| 131 } | 182 } |
| 132 | 183 |
| 133 protected: | 184 protected: |
| 134 ~RefCounted() = default; | 185 ~RefCounted() = default; |
| 135 | 186 |
| 136 private: | 187 private: |
| 137 DISALLOW_COPY_AND_ASSIGN(RefCounted<T>); | 188 DISALLOW_COPY_AND_ASSIGN(RefCounted); |
| 138 }; | 189 }; |
| 139 | 190 |
| 140 // Forward declaration. | 191 // Forward declaration. |
| 141 template <class T, typename Traits> class RefCountedThreadSafe; | 192 template <class T, typename Traits> class RefCountedThreadSafe; |
| 142 | 193 |
| 143 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref | 194 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref |
| 144 // count reaches 0. Overload to delete it on a different thread etc. | 195 // count reaches 0. Overload to delete it on a different thread etc. |
| 145 template<typename T> | 196 template<typename T> |
| 146 struct DefaultRefCountedThreadSafeTraits { | 197 struct DefaultRefCountedThreadSafeTraits { |
| 147 static void Destruct(const T* x) { | 198 static void Destruct(const T* x) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 161 // }; | 212 // }; |
| 162 // | 213 // |
| 163 // If you're using the default trait, then you should add compile time | 214 // If you're using the default trait, then you should add compile time |
| 164 // asserts that no one else is deleting your object. i.e. | 215 // asserts that no one else is deleting your object. i.e. |
| 165 // private: | 216 // private: |
| 166 // friend class base::RefCountedThreadSafe<MyFoo>; | 217 // friend class base::RefCountedThreadSafe<MyFoo>; |
| 167 // ~MyFoo(); | 218 // ~MyFoo(); |
| 168 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > | 219 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
| 169 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { | 220 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
| 170 public: | 221 public: |
| 171 RefCountedThreadSafe() = default; | 222 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
| 223 subtle::kStartRefCountFromZeroTag; |
| 224 |
| 225 explicit RefCountedThreadSafe() |
| 226 : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} |
| 172 | 227 |
| 173 void AddRef() const { | 228 void AddRef() const { |
| 174 subtle::RefCountedThreadSafeBase::AddRef(); | 229 subtle::RefCountedThreadSafeBase::AddRef(); |
| 175 } | 230 } |
| 176 | 231 |
| 177 void Release() const { | 232 void Release() const { |
| 178 if (subtle::RefCountedThreadSafeBase::Release()) { | 233 if (subtle::RefCountedThreadSafeBase::Release()) { |
| 179 Traits::Destruct(static_cast<const T*>(this)); | 234 Traits::Destruct(static_cast<const T*>(this)); |
| 180 } | 235 } |
| 181 } | 236 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 201 RefCountedData() : data() {} | 256 RefCountedData() : data() {} |
| 202 RefCountedData(const T& in_value) : data(in_value) {} | 257 RefCountedData(const T& in_value) : data(in_value) {} |
| 203 | 258 |
| 204 T data; | 259 T data; |
| 205 | 260 |
| 206 private: | 261 private: |
| 207 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; | 262 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; |
| 208 ~RefCountedData() = default; | 263 ~RefCountedData() = default; |
| 209 }; | 264 }; |
| 210 | 265 |
| 266 // Creates a scoped_refptr from a raw pointer without incrementing the reference |
| 267 // count. Use this only for a newly created object whose reference count starts |
| 268 // from 1 instead of 0. |
| 269 template <typename T> |
| 270 scoped_refptr<T> AdoptRef(T* obj) { |
| 271 using Tag = typename std::decay<decltype(T::kRefCountPreference)>::type; |
| 272 static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value, |
| 273 "Use AdoptRef only for the reference count starts from one."); |
| 274 |
| 275 DCHECK(obj); |
| 276 DCHECK(obj->HasOneRef()); |
| 277 obj->Adopted(); |
| 278 return scoped_refptr<T>(obj, subtle::kAdoptRefTag); |
| 279 } |
| 280 |
| 281 namespace subtle { |
| 282 |
| 283 template <typename T> |
| 284 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) { |
| 285 return scoped_refptr<T>(obj); |
| 286 } |
| 287 |
| 288 template <typename T> |
| 289 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) { |
| 290 return AdoptRef(obj); |
| 291 } |
| 292 |
| 293 } // namespace subtle |
| 294 |
| 295 // Constructs an instance of T, which is a ref counted type, and wraps the |
| 296 // object into a scoped_refptr. |
| 297 template <typename T, typename... Args> |
| 298 scoped_refptr<T> MakeShared(Args&&... args) { |
| 299 T* obj = new T(std::forward<Args>(args)...); |
| 300 return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference); |
| 301 } |
| 302 |
| 211 } // namespace base | 303 } // namespace base |
| 212 | 304 |
| 213 // | 305 // |
| 214 // A smart pointer class for reference counted objects. Use this class instead | 306 // A smart pointer class for reference counted objects. Use this class instead |
| 215 // of calling AddRef and Release manually on a reference counted object to | 307 // of calling AddRef and Release manually on a reference counted object to |
| 216 // avoid common memory leaks caused by forgetting to Release an object | 308 // avoid common memory leaks caused by forgetting to Release an object |
| 217 // reference. Sample usage: | 309 // reference. Sample usage: |
| 218 // | 310 // |
| 219 // class MyFoo : public RefCounted<MyFoo> { | 311 // class MyFoo : public RefCounted<MyFoo> { |
| 220 // ... | 312 // ... |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 | 460 |
| 369 template <typename U> | 461 template <typename U> |
| 370 bool operator<(const scoped_refptr<U>& rhs) const { | 462 bool operator<(const scoped_refptr<U>& rhs) const { |
| 371 return ptr_ < rhs.get(); | 463 return ptr_ < rhs.get(); |
| 372 } | 464 } |
| 373 | 465 |
| 374 protected: | 466 protected: |
| 375 T* ptr_ = nullptr; | 467 T* ptr_ = nullptr; |
| 376 | 468 |
| 377 private: | 469 private: |
| 470 template <typename U> |
| 471 friend scoped_refptr<U> base::AdoptRef(U*); |
| 472 |
| 473 scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {} |
| 474 |
| 378 // Friend required for move constructors that set r.ptr_ to null. | 475 // Friend required for move constructors that set r.ptr_ to null. |
| 379 template <typename U> | 476 template <typename U> |
| 380 friend class scoped_refptr; | 477 friend class scoped_refptr; |
| 381 | 478 |
| 382 // Non-inline helpers to allow: | 479 // Non-inline helpers to allow: |
| 383 // class Opaque; | 480 // class Opaque; |
| 384 // extern template class scoped_refptr<Opaque>; | 481 // extern template class scoped_refptr<Opaque>; |
| 385 // Otherwise the compiler will complain that Opaque is an incomplete type. | 482 // Otherwise the compiler will complain that Opaque is an incomplete type. |
| 386 static void AddRef(T* ptr); | 483 static void AddRef(T* ptr); |
| 387 static void Release(T* ptr); | 484 static void Release(T* ptr); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { | 542 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
| 446 return !operator==(null, rhs); | 543 return !operator==(null, rhs); |
| 447 } | 544 } |
| 448 | 545 |
| 449 template <typename T> | 546 template <typename T> |
| 450 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { | 547 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
| 451 return out << p.get(); | 548 return out << p.get(); |
| 452 } | 549 } |
| 453 | 550 |
| 454 #endif // BASE_MEMORY_REF_COUNTED_H_ | 551 #endif // BASE_MEMORY_REF_COUNTED_H_ |
| OLD | NEW |