RefPtr.h (17965B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_RefPtr_h 8 #define mozilla_RefPtr_h 9 10 #include "mozilla/AlreadyAddRefed.h" 11 #include "mozilla/Assertions.h" 12 #include "mozilla/Attributes.h" 13 #include "mozilla/DbgMacro.h" 14 15 #include <type_traits> 16 17 /*****************************************************************************/ 18 19 // template <class T> class RefPtrGetterAddRefs; 20 21 class nsQueryReferent; 22 class nsCOMPtr_helper; 23 class nsISupports; 24 25 namespace mozilla { 26 template <class T> 27 class MovingNotNull; 28 template <class T> 29 class NotNull; 30 template <class T> 31 class OwningNonNull; 32 template <class T> 33 class StaticLocalRefPtr; 34 template <class T> 35 class StaticRefPtr; 36 37 // Traditionally, RefPtr supports automatic refcounting of any pointer type 38 // with AddRef() and Release() methods that follow the traditional semantics. 39 // 40 // This traits class can be specialized to operate on other pointer types. For 41 // example, we specialize this trait for opaque FFI types that represent 42 // refcounted objects in Rust. 43 // 44 // Given the use of ConstRemovingRefPtrTraits below, U should not be a const- 45 // qualified type. 46 template <class U> 47 struct RefPtrTraits { 48 static void AddRef(U* aPtr) { aPtr->AddRef(); } 49 static void Release(U* aPtr) { aPtr->Release(); } 50 }; 51 52 } // namespace mozilla 53 54 template <class T> 55 class MOZ_IS_REFPTR RefPtr { 56 private: 57 void assign_with_AddRef(T* aRawPtr) { 58 if (aRawPtr) { 59 ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr); 60 } 61 assign_assuming_AddRef(aRawPtr); 62 } 63 64 void assign_assuming_AddRef(T* aNewPtr) { 65 T* oldPtr = mRawPtr; 66 mRawPtr = aNewPtr; 67 if (oldPtr) { 68 ConstRemovingRefPtrTraits<T>::Release(oldPtr); 69 } 70 } 71 72 private: 73 T* MOZ_OWNING_REF mRawPtr; 74 75 public: 76 typedef T element_type; 77 78 ~RefPtr() { 79 if (mRawPtr) { 80 ConstRemovingRefPtrTraits<T>::Release(mRawPtr); 81 } 82 } 83 84 // Constructors 85 86 constexpr RefPtr() 87 : mRawPtr(nullptr) 88 // default constructor 89 {} 90 91 RefPtr(const RefPtr<T>& aSmartPtr) 92 : mRawPtr(aSmartPtr.mRawPtr) 93 // copy-constructor 94 { 95 if (mRawPtr) { 96 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr); 97 } 98 } 99 100 RefPtr(RefPtr<T>&& aRefPtr) noexcept : mRawPtr(aRefPtr.mRawPtr) { 101 aRefPtr.mRawPtr = nullptr; 102 } 103 104 // construct from a raw pointer (of the right type) 105 106 MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) { 107 if (mRawPtr) { 108 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr); 109 } 110 } 111 112 MOZ_IMPLICIT constexpr RefPtr(std::nullptr_t) : mRawPtr(nullptr) {} 113 114 template <typename I, 115 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>> 116 MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr) 117 : mRawPtr(aSmartPtr.take()) 118 // construct from |already_AddRefed| 119 {} 120 121 template <typename I, 122 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>> 123 MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr) 124 : mRawPtr(aSmartPtr.take()) 125 // construct from |otherRefPtr.forget()| 126 {} 127 128 template <typename I, 129 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>> 130 MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr) 131 : mRawPtr(aSmartPtr.get()) 132 // copy-construct from a smart pointer with a related pointer type 133 { 134 if (mRawPtr) { 135 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr); 136 } 137 } 138 139 template <typename I, 140 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>> 141 MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr) 142 : mRawPtr(aSmartPtr.forget().take()) 143 // construct from |Move(RefPtr<SomeSubclassOfT>)|. 144 {} 145 146 template <typename I, 147 typename = std::enable_if_t<!std::is_same_v<I, RefPtr<T>> && 148 std::is_convertible_v<I, RefPtr<T>>>> 149 MOZ_IMPLICIT RefPtr(const mozilla::NotNull<I>& aSmartPtr) 150 : mRawPtr(RefPtr<T>(aSmartPtr.get()).forget().take()) 151 // construct from |mozilla::NotNull|. 152 {} 153 154 template <typename I, 155 typename = std::enable_if_t<!std::is_same_v<I, RefPtr<T>> && 156 std::is_convertible_v<I, RefPtr<T>>>> 157 MOZ_IMPLICIT RefPtr(mozilla::MovingNotNull<I>&& aSmartPtr) 158 : mRawPtr(RefPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take()) 159 // construct from |mozilla::MovingNotNull|. 160 {} 161 162 MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper); 163 MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper); 164 165 // Defined in OwningNonNull.h 166 template <class U> 167 MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther); 168 169 // Defined in StaticLocalPtr.h 170 template <class U> 171 MOZ_IMPLICIT RefPtr(const mozilla::StaticLocalRefPtr<U>& aOther); 172 173 // Defined in StaticPtr.h 174 template <class U> 175 MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther); 176 177 // Assignment operators 178 179 RefPtr<T>& operator=(decltype(nullptr)) { 180 assign_assuming_AddRef(nullptr); 181 return *this; 182 } 183 184 RefPtr<T>& operator=(const RefPtr<T>& aRhs) 185 // copy assignment operator 186 { 187 assign_with_AddRef(aRhs.mRawPtr); 188 return *this; 189 } 190 191 template <typename I> 192 RefPtr<T>& operator=(const RefPtr<I>& aRhs) 193 // assign from an RefPtr of a related pointer type 194 { 195 assign_with_AddRef(aRhs.get()); 196 return *this; 197 } 198 199 RefPtr<T>& operator=(T* aRhs) 200 // assign from a raw pointer (of the right type) 201 { 202 assign_with_AddRef(aRhs); 203 return *this; 204 } 205 206 template <typename I> 207 RefPtr<T>& operator=(already_AddRefed<I>& aRhs) 208 // assign from |already_AddRefed| 209 { 210 assign_assuming_AddRef(aRhs.take()); 211 return *this; 212 } 213 214 template <typename I> 215 RefPtr<T>& operator=(already_AddRefed<I>&& aRhs) 216 // assign from |otherRefPtr.forget()| 217 { 218 assign_assuming_AddRef(aRhs.take()); 219 return *this; 220 } 221 222 RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent); 223 RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper); 224 225 template <typename I, 226 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>> 227 RefPtr<T>& operator=(RefPtr<I>&& aRefPtr) noexcept { 228 assign_assuming_AddRef(aRefPtr.forget().take()); 229 return *this; 230 } 231 232 template <typename I, 233 typename = std::enable_if_t<std::is_convertible_v<I, RefPtr<T>>>> 234 RefPtr<T>& operator=(const mozilla::NotNull<I>& aSmartPtr) 235 // assign from |mozilla::NotNull|. 236 { 237 assign_assuming_AddRef(RefPtr<T>(aSmartPtr.get()).forget().take()); 238 return *this; 239 } 240 241 template <typename I, 242 typename = std::enable_if_t<std::is_convertible_v<I, RefPtr<T>>>> 243 RefPtr<T>& operator=(mozilla::MovingNotNull<I>&& aSmartPtr) 244 // assign from |mozilla::MovingNotNull|. 245 { 246 assign_assuming_AddRef( 247 RefPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take()); 248 return *this; 249 } 250 251 // Defined in OwningNonNull.h 252 template <class U> 253 RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther); 254 255 // Defined in StaticLocalPtr.h 256 template <class U> 257 RefPtr<T>& operator=(const mozilla::StaticLocalRefPtr<U>& aOther); 258 259 // Defined in StaticPtr.h 260 template <class U> 261 RefPtr<T>& operator=(const mozilla::StaticRefPtr<U>& aOther); 262 263 // Other pointer operators 264 265 void swap(RefPtr<T>& aRhs) 266 // ...exchange ownership with |aRhs|; can save a pair of refcount operations 267 { 268 T* temp = aRhs.mRawPtr; 269 aRhs.mRawPtr = mRawPtr; 270 mRawPtr = temp; 271 } 272 273 void swap(T*& aRhs) 274 // ...exchange ownership with |aRhs|; can save a pair of refcount operations 275 { 276 T* temp = aRhs; 277 aRhs = mRawPtr; 278 mRawPtr = temp; 279 } 280 281 already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget() 282 // return the value of mRawPtr and null out mRawPtr. Useful for 283 // already_AddRefed return values. 284 { 285 T* temp = nullptr; 286 swap(temp); 287 return already_AddRefed<T>(temp); 288 } 289 290 template <typename I> 291 void forget(I** aRhs) 292 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr. 293 // Useful to avoid unnecessary AddRef/Release pairs with "out" 294 // parameters where aRhs bay be a T** or an I** where I is a base class 295 // of T. 296 { 297 MOZ_ASSERT(aRhs, "Null pointer passed to forget!"); 298 *aRhs = mRawPtr; 299 mRawPtr = nullptr; 300 } 301 302 void forget(nsISupports** aRhs) { 303 MOZ_ASSERT(aRhs, "Null pointer passed to forget!"); 304 *aRhs = ToSupports(mRawPtr); 305 mRawPtr = nullptr; 306 } 307 308 T* get() const 309 /* 310 Prefer the implicit conversion provided automatically by |operator T*() 311 const|. Use |get()| to resolve ambiguity or to get a castable pointer. 312 */ 313 { 314 return const_cast<T*>(mRawPtr); 315 } 316 317 operator T*() const& 318 /* 319 ...makes an |RefPtr| act like its underlying raw pointer type whenever it 320 is used in a context where a raw pointer is expected. It is this operator 321 that makes an |RefPtr| substitutable for a raw pointer. 322 323 Prefer the implicit use of this operator to calling |get()|, except where 324 necessary to resolve ambiguity. 325 */ 326 { 327 return get(); 328 } 329 330 // Don't allow implicit conversion of temporary RefPtr to raw pointer, 331 // because the refcount might be one and the pointer will immediately become 332 // invalid. 333 operator T*() const&& = delete; 334 335 // These are needed to avoid the deleted operator above. XXX Why is operator! 336 // needed separately? Shouldn't the compiler prefer using the non-deleted 337 // operator bool instead of the deleted operator T*? 338 explicit operator bool() const { return !!mRawPtr; } 339 bool operator!() const { return !mRawPtr; } 340 341 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { 342 MOZ_ASSERT(mRawPtr != nullptr, 343 "You can't dereference a NULL RefPtr with operator->()."); 344 return get(); 345 } 346 347 template <typename R, typename... Args> 348 class Proxy { 349 typedef R (T::*member_function)(Args...); 350 T* mRawPtr; 351 member_function mFunction; 352 353 public: 354 Proxy(T* aRawPtr, member_function aFunction) 355 : mRawPtr(aRawPtr), mFunction(aFunction) {} 356 template <typename... ActualArgs> 357 R operator()(ActualArgs&&... aArgs) { 358 return ((*mRawPtr).*mFunction)(std::forward<ActualArgs>(aArgs)...); 359 } 360 }; 361 362 template <typename R, typename... Args> 363 Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const { 364 MOZ_ASSERT(mRawPtr != nullptr, 365 "You can't dereference a NULL RefPtr with operator->*()."); 366 return Proxy<R, Args...>(get(), aFptr); 367 } 368 369 RefPtr<T>* get_address() 370 // This is not intended to be used by clients. See |address_of| 371 // below. 372 { 373 return this; 374 } 375 376 const RefPtr<T>* get_address() const 377 // This is not intended to be used by clients. See |address_of| 378 // below. 379 { 380 return this; 381 } 382 383 public: 384 T& operator*() const { 385 MOZ_ASSERT(mRawPtr != nullptr, 386 "You can't dereference a NULL RefPtr with operator*()."); 387 return *get(); 388 } 389 390 T** StartAssignment() { 391 assign_assuming_AddRef(nullptr); 392 return reinterpret_cast<T**>(&mRawPtr); 393 } 394 395 private: 396 // This helper class makes |RefPtr<const T>| possible by casting away 397 // the constness from the pointer when calling AddRef() and Release(). 398 // 399 // This is necessary because AddRef() and Release() implementations can't 400 // generally expected to be const themselves (without heavy use of |mutable| 401 // and |const_cast| in their own implementations). 402 // 403 // This should be sound because while |RefPtr<const T>| provides a 404 // const view of an object, the object itself should not be const (it 405 // would have to be allocated as |new const T| or similar to be const). 406 template <class U> 407 struct ConstRemovingRefPtrTraits { 408 static void AddRef(U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(aPtr); } 409 static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); } 410 }; 411 template <class U> 412 struct ConstRemovingRefPtrTraits<const U> { 413 static void AddRef(const U* aPtr) { 414 mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr)); 415 } 416 static void Release(const U* aPtr) { 417 mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr)); 418 } 419 }; 420 }; 421 422 class nsCycleCollectionTraversalCallback; 423 template <typename T> 424 void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback, 425 T* aChild, const char* aName, uint32_t aFlags); 426 427 template <typename T> 428 inline void ImplCycleCollectionUnlink(RefPtr<T>& aField) { 429 aField = nullptr; 430 } 431 432 template <typename T> 433 inline void ImplCycleCollectionTraverse( 434 nsCycleCollectionTraversalCallback& aCallback, const RefPtr<T>& aField, 435 const char* aName, uint32_t aFlags = 0) { 436 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags); 437 } 438 439 template <class T> 440 inline RefPtr<T>* address_of(RefPtr<T>& aPtr) { 441 return aPtr.get_address(); 442 } 443 444 template <class T> 445 inline const RefPtr<T>* address_of(const RefPtr<T>& aPtr) { 446 return aPtr.get_address(); 447 } 448 449 template <class T> 450 class RefPtrGetterAddRefs 451 /* 452 ... 453 454 This class is designed to be used for anonymous temporary objects in the 455 argument list of calls that return COM interface pointers, e.g., 456 457 RefPtr<IFoo> fooP; 458 ...->GetAddRefedPointer(getter_AddRefs(fooP)) 459 460 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. 461 462 When initialized with a |RefPtr|, as in the example above, it returns 463 a |void**|, a |T**|, or an |nsISupports**| as needed, that the 464 outer call (|GetAddRefedPointer| in this case) can fill in. 465 466 This type should be a nested class inside |RefPtr<T>|. 467 */ 468 { 469 public: 470 explicit RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr) 471 : mTargetSmartPtr(aSmartPtr) { 472 // nothing else to do 473 } 474 475 operator void**() { 476 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment()); 477 } 478 479 operator T**() { return mTargetSmartPtr.StartAssignment(); } 480 481 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } 482 483 private: 484 RefPtr<T>& mTargetSmartPtr; 485 }; 486 487 template <class T> 488 inline RefPtrGetterAddRefs<T> getter_AddRefs(RefPtr<T>& aSmartPtr) 489 /* 490 Used around a |RefPtr| when 491 ...makes the class |RefPtrGetterAddRefs<T>| invisible. 492 */ 493 { 494 return RefPtrGetterAddRefs<T>(aSmartPtr); 495 } 496 497 // Comparing two |RefPtr|s 498 499 template <class T, class U> 500 inline bool operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) { 501 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get()); 502 } 503 504 template <class T, class U> 505 inline bool operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) { 506 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get()); 507 } 508 509 // Comparing an |RefPtr| to a raw pointer 510 511 template <class T, class U> 512 inline bool operator==(const RefPtr<T>& aLhs, const U* aRhs) { 513 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs); 514 } 515 516 template <class T, class U> 517 inline bool operator==(const U* aLhs, const RefPtr<T>& aRhs) { 518 return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get()); 519 } 520 521 template <class T, class U> 522 inline bool operator!=(const RefPtr<T>& aLhs, const U* aRhs) { 523 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs); 524 } 525 526 template <class T, class U> 527 inline bool operator!=(const U* aLhs, const RefPtr<T>& aRhs) { 528 return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get()); 529 } 530 531 template <class T, class U> 532 inline bool operator==(const RefPtr<T>& aLhs, U* aRhs) { 533 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs); 534 } 535 536 template <class T, class U> 537 inline bool operator==(U* aLhs, const RefPtr<T>& aRhs) { 538 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get()); 539 } 540 541 template <class T, class U> 542 inline bool operator!=(const RefPtr<T>& aLhs, U* aRhs) { 543 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs); 544 } 545 546 template <class T, class U> 547 inline bool operator!=(U* aLhs, const RefPtr<T>& aRhs) { 548 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get()); 549 } 550 551 // Comparing an |RefPtr| to |nullptr| 552 553 template <class T> 554 inline bool operator==(const RefPtr<T>& aLhs, decltype(nullptr)) { 555 return aLhs.get() == nullptr; 556 } 557 558 template <class T> 559 inline bool operator==(decltype(nullptr), const RefPtr<T>& aRhs) { 560 return nullptr == aRhs.get(); 561 } 562 563 template <class T> 564 inline bool operator!=(const RefPtr<T>& aLhs, decltype(nullptr)) { 565 return aLhs.get() != nullptr; 566 } 567 568 template <class T> 569 inline bool operator!=(decltype(nullptr), const RefPtr<T>& aRhs) { 570 return nullptr != aRhs.get(); 571 } 572 573 // MOZ_DBG support 574 575 template <class T> 576 std::ostream& operator<<(std::ostream& aOut, const RefPtr<T>& aObj) { 577 return mozilla::DebugValue(aOut, aObj.get()); 578 } 579 580 /*****************************************************************************/ 581 582 template <class T> 583 inline already_AddRefed<T> do_AddRef(T* aObj) { 584 RefPtr<T> ref(aObj); 585 return ref.forget(); 586 } 587 588 template <class T> 589 inline already_AddRefed<T> do_AddRef(const RefPtr<T>& aObj) { 590 RefPtr<T> ref(aObj); 591 return ref.forget(); 592 } 593 594 namespace mozilla { 595 596 /** 597 * Helper function to be able to conveniently write things like: 598 * 599 * already_AddRefed<T> 600 * f(...) 601 * { 602 * return MakeAndAddRef<T>(...); 603 * } 604 */ 605 template <typename T, typename... Args> 606 already_AddRefed<T> MakeAndAddRef(Args&&... aArgs) { 607 RefPtr<T> p(new T(std::forward<Args>(aArgs)...)); 608 return p.forget(); 609 } 610 611 /** 612 * Helper function to be able to conveniently write things like: 613 * 614 * auto runnable = 615 * MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>( 616 * mOnSuccess, mOnFailure, *error, mWindowID); 617 */ 618 template <typename T, typename... Args> 619 RefPtr<T> MakeRefPtr(Args&&... aArgs) { 620 RefPtr<T> p(new T(std::forward<Args>(aArgs)...)); 621 return p; 622 } 623 624 } // namespace mozilla 625 626 /** 627 * Deduction guide to allow simple `RefPtr` definitions from an 628 * already_AddRefed<T> without repeating the type, e.g.: 629 * 630 * RefPtr ptr = MakeAndAddRef<SomeType>(...); 631 */ 632 template <typename T> 633 RefPtr(already_AddRefed<T>) -> RefPtr<T>; 634 635 #endif /* mozilla_RefPtr_h */