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> |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 // | 262 // |
263 // b = a; | 263 // b = a; |
264 // // now, |a| and |b| each own a reference to the same MyFoo object. | 264 // // now, |a| and |b| each own a reference to the same MyFoo object. |
265 // } | 265 // } |
266 // | 266 // |
267 template <class T> | 267 template <class T> |
268 class scoped_refptr { | 268 class scoped_refptr { |
269 public: | 269 public: |
270 typedef T element_type; | 270 typedef T element_type; |
271 | 271 |
| 272 // RefCounted<T> or RefCountedThreadSafe<T> depending on the type implemented |
| 273 // by T (or T itself for RefCountedThreadSafe<T, CustomTraits> and the rare |
| 274 // use case of classes providing their own AddRef/Release methods and being |
| 275 // stored in a scoped_refptr). |
| 276 using RefCountedType = typename std::conditional< |
| 277 std::is_convertible<T*, base::RefCounted<T>*>::value, |
| 278 base::RefCounted<T>, |
| 279 typename std::conditional< |
| 280 std::is_convertible<T*, base::RefCountedThreadSafe<T>*>::value, |
| 281 base::RefCountedThreadSafe<T>, |
| 282 T>::type>::type; |
| 283 |
272 scoped_refptr() = default; | 284 scoped_refptr() = default; |
273 | 285 |
274 scoped_refptr(T* p) : ptr_(p) { | 286 scoped_refptr(T* p) : ptr_(p) { |
275 if (ptr_) | 287 if (ref_) |
276 AddRef(ptr_); | 288 AddRef(ref_); |
277 } | 289 } |
278 | 290 |
279 // Copy constructor. | 291 // Copy constructor. |
280 scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { | 292 scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { |
281 if (ptr_) | 293 if (ref_) |
282 AddRef(ptr_); | 294 AddRef(ref_); |
283 } | 295 } |
284 | 296 |
285 // Copy conversion constructor. | 297 // Copy conversion constructor. |
286 template <typename U, | 298 template <typename U, |
287 typename = typename std::enable_if< | 299 typename = typename std::enable_if< |
288 std::is_convertible<U*, T*>::value>::type> | 300 std::is_convertible<U*, T*>::value>::type> |
289 scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { | 301 scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { |
290 if (ptr_) | 302 if (ref_) |
291 AddRef(ptr_); | 303 AddRef(ref_); |
292 } | 304 } |
293 | 305 |
294 // Move constructor. This is required in addition to the conversion | 306 // Move constructor. This is required in addition to the conversion |
295 // constructor below in order for clang to warn about pessimizing moves. | 307 // constructor below in order for clang to warn about pessimizing moves. |
296 scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; } | 308 scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; } |
297 | 309 |
298 // Move conversion constructor. | 310 // Move conversion constructor. |
299 template <typename U, | 311 template <typename U, |
300 typename = typename std::enable_if< | 312 typename = typename std::enable_if< |
301 std::is_convertible<U*, T*>::value>::type> | 313 std::is_convertible<U*, T*>::value>::type> |
302 scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) { | 314 scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) { |
303 r.ptr_ = nullptr; | 315 r.ptr_ = nullptr; |
304 } | 316 } |
305 | 317 |
306 ~scoped_refptr() { | 318 ~scoped_refptr() { |
307 if (ptr_) | 319 if (ref_) |
308 Release(ptr_); | 320 Release(ref_); |
309 } | 321 } |
310 | 322 |
311 T* get() const { return ptr_; } | 323 T* get() const { return ptr_; } |
312 | 324 |
313 T& operator*() const { | 325 T& operator*() const { |
314 assert(ptr_ != nullptr); | 326 assert(ptr_ != nullptr); |
315 return *ptr_; | 327 return *ptr_; |
316 } | 328 } |
317 | 329 |
318 T* operator->() const { | 330 T* operator->() const { |
319 assert(ptr_ != nullptr); | 331 assert(ptr_ != nullptr); |
320 return ptr_; | 332 return ptr_; |
321 } | 333 } |
322 | 334 |
323 scoped_refptr<T>& operator=(T* p) { | 335 scoped_refptr<T>& operator=(T* p) { |
324 // AddRef first so that self assignment should work | 336 // AddRef first so that self assignment should work |
| 337 // Note: This AddRef() can't use the |ref_| trick, so assigning from a naked |
| 338 // pointer requires the assignor to have the full definition of |T|. |
325 if (p) | 339 if (p) |
326 AddRef(p); | 340 AddRef(p); |
327 T* old_ptr = ptr_; | 341 const RefCountedType* old_ref = ref_; |
328 ptr_ = p; | 342 ptr_ = p; |
329 if (old_ptr) | 343 if (old_ref) |
330 Release(old_ptr); | 344 Release(old_ref); |
331 return *this; | 345 return *this; |
332 } | 346 } |
333 | 347 |
334 scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { | 348 scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { |
335 return *this = r.ptr_; | 349 return *this = r.ptr_; |
336 } | 350 } |
337 | 351 |
338 template <typename U> | 352 template <typename U> |
339 scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { | 353 scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { |
340 return *this = r.get(); | 354 return *this = r.get(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 bool operator!=(const scoped_refptr<U>& rhs) const { | 386 bool operator!=(const scoped_refptr<U>& rhs) const { |
373 return !operator==(rhs); | 387 return !operator==(rhs); |
374 } | 388 } |
375 | 389 |
376 template <typename U> | 390 template <typename U> |
377 bool operator<(const scoped_refptr<U>& rhs) const { | 391 bool operator<(const scoped_refptr<U>& rhs) const { |
378 return ptr_ < rhs.get(); | 392 return ptr_ < rhs.get(); |
379 } | 393 } |
380 | 394 |
381 protected: | 395 protected: |
| 396 //FIXME need to update |ref_| when updating |ptr_|. |
382 T* ptr_ = nullptr; | 397 T* ptr_ = nullptr; |
383 | 398 |
| 399 // |ref_| merely points to |ptr_| but the type checking is done when |
| 400 // scoped_refptr is constructed instead of when it's used, this allows |
| 401 // callsites that merely do: |
| 402 // void PassRefToFoo(Foo* foo, scoped_refptr<T> t) { |
| 403 // foo->TakeRef(std::move(t)); |
| 404 // } |
| 405 // to compile without the full definition of |T| as they can perform |
| 406 // AddRef/Release operations on it without having to know that it implements |
| 407 // RefCountedInterface. |
| 408 //FIXME: This still doesn't work because template instantiations still need to |
| 409 //know the full type to derive |RefCountedType|... |
| 410 const RefCountedType* ref_ = ptr_; |
| 411 |
384 private: | 412 private: |
385 // Friend required for move constructors that set r.ptr_ to null. | 413 // Friend required for move constructors that set r.ptr_ to null. |
386 template <typename U> | 414 template <typename U> |
387 friend class scoped_refptr; | 415 friend class scoped_refptr; |
388 | 416 |
389 // Non-inline helpers to allow: | 417 // Non-inline helpers to allow: |
390 // class Opaque; | 418 // class Opaque; |
391 // extern template class scoped_refptr<Opaque>; | 419 // extern template class scoped_refptr<Opaque>; |
392 // Otherwise the compiler will complain that Opaque is an incomplete type. | 420 // Otherwise the compiler will complain that Opaque is an incomplete type. |
393 static void AddRef(T* ptr); | 421 static void AddRef(const RefCountedType* ref_type); |
394 static void Release(T* ptr); | 422 static void Release(const RefCountedType* ref_type); |
395 }; | 423 }; |
396 | 424 |
| 425 // static |
397 template <typename T> | 426 template <typename T> |
398 void scoped_refptr<T>::AddRef(T* ptr) { | 427 void scoped_refptr<T>::AddRef( |
399 ptr->AddRef(); | 428 const scoped_refptr<T>::RefCountedType* ref_type) { |
| 429 ref_type->AddRef(); |
400 } | 430 } |
401 | 431 |
| 432 // static |
402 template <typename T> | 433 template <typename T> |
403 void scoped_refptr<T>::Release(T* ptr) { | 434 void scoped_refptr<T>::Release( |
404 ptr->Release(); | 435 const scoped_refptr<T>::RefCountedType* ref_type) { |
| 436 ref_type->Release(); |
405 } | 437 } |
406 | 438 |
407 // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without | 439 // Handy utility for creating a scoped_refptr<T> out of a T* explicitly without |
408 // having to retype all the template arguments | 440 // having to retype all the template arguments |
409 template <typename T> | 441 template <typename T> |
410 scoped_refptr<T> make_scoped_refptr(T* t) { | 442 scoped_refptr<T> make_scoped_refptr(T* t) { |
411 return scoped_refptr<T>(t); | 443 return scoped_refptr<T>(t); |
412 } | 444 } |
413 | 445 |
414 template <typename T, typename U> | 446 template <typename T, typename U> |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { | 482 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
451 return !operator==(null, rhs); | 483 return !operator==(null, rhs); |
452 } | 484 } |
453 | 485 |
454 template <typename T> | 486 template <typename T> |
455 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { | 487 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
456 return out << p.get(); | 488 return out << p.get(); |
457 } | 489 } |
458 | 490 |
459 #endif // BASE_MEMORY_REF_COUNTED_H_ | 491 #endif // BASE_MEMORY_REF_COUNTED_H_ |
OLD | NEW |