no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / mfbt / RefPtr.h
blobb36491f49b63ab504e24ce7a80653054a653bca4
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/. */
7 #ifndef mozilla_RefPtr_h
8 #define mozilla_RefPtr_h
10 #include "mozilla/AlreadyAddRefed.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/DbgMacro.h"
15 #include <type_traits>
17 /*****************************************************************************/
19 // template <class T> class RefPtrGetterAddRefs;
21 class nsQueryReferent;
22 class nsCOMPtr_helper;
23 class nsISupports;
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 #if defined(XP_WIN)
37 namespace mscom {
38 class AgileReference;
39 } // namespace mscom
40 #endif // defined(XP_WIN)
42 // Traditionally, RefPtr supports automatic refcounting of any pointer type
43 // with AddRef() and Release() methods that follow the traditional semantics.
45 // This traits class can be specialized to operate on other pointer types. For
46 // example, we specialize this trait for opaque FFI types that represent
47 // refcounted objects in Rust.
49 // Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
50 // qualified type.
51 template <class U>
52 struct RefPtrTraits {
53 static void AddRef(U* aPtr) { aPtr->AddRef(); }
54 static void Release(U* aPtr) { aPtr->Release(); }
57 } // namespace mozilla
59 template <class T>
60 class MOZ_IS_REFPTR RefPtr {
61 private:
62 void assign_with_AddRef(T* aRawPtr) {
63 if (aRawPtr) {
64 ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
66 assign_assuming_AddRef(aRawPtr);
69 void assign_assuming_AddRef(T* aNewPtr) {
70 T* oldPtr = mRawPtr;
71 mRawPtr = aNewPtr;
72 if (oldPtr) {
73 ConstRemovingRefPtrTraits<T>::Release(oldPtr);
77 private:
78 T* MOZ_OWNING_REF mRawPtr;
80 public:
81 typedef T element_type;
83 ~RefPtr() {
84 if (mRawPtr) {
85 ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
89 // Constructors
91 RefPtr()
92 : mRawPtr(nullptr)
93 // default constructor
96 RefPtr(const RefPtr<T>& aSmartPtr)
97 : mRawPtr(aSmartPtr.mRawPtr)
98 // copy-constructor
100 if (mRawPtr) {
101 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
105 RefPtr(RefPtr<T>&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) {
106 aRefPtr.mRawPtr = nullptr;
109 // construct from a raw pointer (of the right type)
111 MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) {
112 if (mRawPtr) {
113 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
117 MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {}
119 template <typename I,
120 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
121 MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
122 : mRawPtr(aSmartPtr.take())
123 // construct from |already_AddRefed|
126 template <typename I,
127 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
128 MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr)
129 : mRawPtr(aSmartPtr.take())
130 // construct from |otherRefPtr.forget()|
133 template <typename I,
134 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
135 MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr)
136 : mRawPtr(aSmartPtr.get())
137 // copy-construct from a smart pointer with a related pointer type
139 if (mRawPtr) {
140 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
144 template <typename I,
145 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
146 MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
147 : mRawPtr(aSmartPtr.forget().take())
148 // construct from |Move(RefPtr<SomeSubclassOfT>)|.
151 template <typename I,
152 typename = std::enable_if_t<!std::is_same_v<I, RefPtr<T>> &&
153 std::is_convertible_v<I, RefPtr<T>>>>
154 MOZ_IMPLICIT RefPtr(const mozilla::NotNull<I>& aSmartPtr)
155 : mRawPtr(RefPtr<T>(aSmartPtr.get()).forget().take())
156 // construct from |mozilla::NotNull|.
159 template <typename I,
160 typename = std::enable_if_t<!std::is_same_v<I, RefPtr<T>> &&
161 std::is_convertible_v<I, RefPtr<T>>>>
162 MOZ_IMPLICIT RefPtr(mozilla::MovingNotNull<I>&& aSmartPtr)
163 : mRawPtr(RefPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take())
164 // construct from |mozilla::MovingNotNull|.
167 MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper);
168 MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
169 #if defined(XP_WIN)
170 MOZ_IMPLICIT RefPtr(const mozilla::mscom::AgileReference& aAgileRef);
171 #endif // defined(XP_WIN)
173 // Defined in OwningNonNull.h
174 template <class U>
175 MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
177 // Defined in StaticLocalPtr.h
178 template <class U>
179 MOZ_IMPLICIT RefPtr(const mozilla::StaticLocalRefPtr<U>& aOther);
181 // Defined in StaticPtr.h
182 template <class U>
183 MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
185 // Assignment operators
187 RefPtr<T>& operator=(decltype(nullptr)) {
188 assign_assuming_AddRef(nullptr);
189 return *this;
192 RefPtr<T>& operator=(const RefPtr<T>& aRhs)
193 // copy assignment operator
195 assign_with_AddRef(aRhs.mRawPtr);
196 return *this;
199 template <typename I>
200 RefPtr<T>& operator=(const RefPtr<I>& aRhs)
201 // assign from an RefPtr of a related pointer type
203 assign_with_AddRef(aRhs.get());
204 return *this;
207 RefPtr<T>& operator=(T* aRhs)
208 // assign from a raw pointer (of the right type)
210 assign_with_AddRef(aRhs);
211 return *this;
214 template <typename I>
215 RefPtr<T>& operator=(already_AddRefed<I>& aRhs)
216 // assign from |already_AddRefed|
218 assign_assuming_AddRef(aRhs.take());
219 return *this;
222 template <typename I>
223 RefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
224 // assign from |otherRefPtr.forget()|
226 assign_assuming_AddRef(aRhs.take());
227 return *this;
230 RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent);
231 RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
232 #if defined(XP_WIN)
233 RefPtr<T>& operator=(const mozilla::mscom::AgileReference& aAgileRef);
234 #endif // defined(XP_WIN)
236 template <typename I,
237 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
238 RefPtr<T>& operator=(RefPtr<I>&& aRefPtr) {
239 assign_assuming_AddRef(aRefPtr.forget().take());
240 return *this;
243 template <typename I,
244 typename = std::enable_if_t<std::is_convertible_v<I, RefPtr<T>>>>
245 RefPtr<T>& operator=(const mozilla::NotNull<I>& aSmartPtr)
246 // assign from |mozilla::NotNull|.
248 assign_assuming_AddRef(RefPtr<T>(aSmartPtr.get()).forget().take());
249 return *this;
252 template <typename I,
253 typename = std::enable_if_t<std::is_convertible_v<I, RefPtr<T>>>>
254 RefPtr<T>& operator=(mozilla::MovingNotNull<I>&& aSmartPtr)
255 // assign from |mozilla::MovingNotNull|.
257 assign_assuming_AddRef(
258 RefPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take());
259 return *this;
262 // Defined in OwningNonNull.h
263 template <class U>
264 RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
266 // Defined in StaticLocalPtr.h
267 template <class U>
268 RefPtr<T>& operator=(const mozilla::StaticLocalRefPtr<U>& aOther);
270 // Defined in StaticPtr.h
271 template <class U>
272 RefPtr<T>& operator=(const mozilla::StaticRefPtr<U>& aOther);
274 // Other pointer operators
276 void swap(RefPtr<T>& aRhs)
277 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
279 T* temp = aRhs.mRawPtr;
280 aRhs.mRawPtr = mRawPtr;
281 mRawPtr = temp;
284 void swap(T*& aRhs)
285 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
287 T* temp = aRhs;
288 aRhs = mRawPtr;
289 mRawPtr = temp;
292 already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget()
293 // return the value of mRawPtr and null out mRawPtr. Useful for
294 // already_AddRefed return values.
296 T* temp = nullptr;
297 swap(temp);
298 return already_AddRefed<T>(temp);
301 template <typename I>
302 void forget(I** aRhs)
303 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
304 // Useful to avoid unnecessary AddRef/Release pairs with "out"
305 // parameters where aRhs bay be a T** or an I** where I is a base class
306 // of T.
308 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
309 *aRhs = mRawPtr;
310 mRawPtr = nullptr;
313 void forget(nsISupports** aRhs) {
314 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
315 *aRhs = ToSupports(mRawPtr);
316 mRawPtr = nullptr;
319 T* get() const
321 Prefer the implicit conversion provided automatically by |operator T*()
322 const|. Use |get()| to resolve ambiguity or to get a castable pointer.
325 return const_cast<T*>(mRawPtr);
328 operator T*() const&
330 ...makes an |RefPtr| act like its underlying raw pointer type whenever it
331 is used in a context where a raw pointer is expected. It is this operator
332 that makes an |RefPtr| substitutable for a raw pointer.
334 Prefer the implicit use of this operator to calling |get()|, except where
335 necessary to resolve ambiguity.
338 return get();
341 // Don't allow implicit conversion of temporary RefPtr to raw pointer,
342 // because the refcount might be one and the pointer will immediately become
343 // invalid.
344 operator T*() const&& = delete;
346 // These are needed to avoid the deleted operator above. XXX Why is operator!
347 // needed separately? Shouldn't the compiler prefer using the non-deleted
348 // operator bool instead of the deleted operator T*?
349 explicit operator bool() const { return !!mRawPtr; }
350 bool operator!() const { return !mRawPtr; }
352 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
353 MOZ_ASSERT(mRawPtr != nullptr,
354 "You can't dereference a NULL RefPtr with operator->().");
355 return get();
358 template <typename R, typename... Args>
359 class Proxy {
360 typedef R (T::*member_function)(Args...);
361 T* mRawPtr;
362 member_function mFunction;
364 public:
365 Proxy(T* aRawPtr, member_function aFunction)
366 : mRawPtr(aRawPtr), mFunction(aFunction) {}
367 template <typename... ActualArgs>
368 R operator()(ActualArgs&&... aArgs) {
369 return ((*mRawPtr).*mFunction)(std::forward<ActualArgs>(aArgs)...);
373 template <typename R, typename... Args>
374 Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const {
375 MOZ_ASSERT(mRawPtr != nullptr,
376 "You can't dereference a NULL RefPtr with operator->*().");
377 return Proxy<R, Args...>(get(), aFptr);
380 RefPtr<T>* get_address()
381 // This is not intended to be used by clients. See |address_of|
382 // below.
384 return this;
387 const RefPtr<T>* get_address() const
388 // This is not intended to be used by clients. See |address_of|
389 // below.
391 return this;
394 public:
395 T& operator*() const {
396 MOZ_ASSERT(mRawPtr != nullptr,
397 "You can't dereference a NULL RefPtr with operator*().");
398 return *get();
401 T** StartAssignment() {
402 assign_assuming_AddRef(nullptr);
403 return reinterpret_cast<T**>(&mRawPtr);
406 private:
407 // This helper class makes |RefPtr<const T>| possible by casting away
408 // the constness from the pointer when calling AddRef() and Release().
410 // This is necessary because AddRef() and Release() implementations can't
411 // generally expected to be const themselves (without heavy use of |mutable|
412 // and |const_cast| in their own implementations).
414 // This should be sound because while |RefPtr<const T>| provides a
415 // const view of an object, the object itself should not be const (it
416 // would have to be allocated as |new const T| or similar to be const).
417 template <class U>
418 struct ConstRemovingRefPtrTraits {
419 static void AddRef(U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(aPtr); }
420 static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); }
422 template <class U>
423 struct ConstRemovingRefPtrTraits<const U> {
424 static void AddRef(const U* aPtr) {
425 mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
427 static void Release(const U* aPtr) {
428 mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
433 class nsCycleCollectionTraversalCallback;
434 template <typename T>
435 void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback,
436 T* aChild, const char* aName, uint32_t aFlags);
438 template <typename T>
439 inline void ImplCycleCollectionUnlink(RefPtr<T>& aField) {
440 aField = nullptr;
443 template <typename T>
444 inline void ImplCycleCollectionTraverse(
445 nsCycleCollectionTraversalCallback& aCallback, RefPtr<T>& aField,
446 const char* aName, uint32_t aFlags = 0) {
447 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
450 template <class T>
451 inline RefPtr<T>* address_of(RefPtr<T>& aPtr) {
452 return aPtr.get_address();
455 template <class T>
456 inline const RefPtr<T>* address_of(const RefPtr<T>& aPtr) {
457 return aPtr.get_address();
460 template <class T>
461 class RefPtrGetterAddRefs
465 This class is designed to be used for anonymous temporary objects in the
466 argument list of calls that return COM interface pointers, e.g.,
468 RefPtr<IFoo> fooP;
469 ...->GetAddRefedPointer(getter_AddRefs(fooP))
471 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
473 When initialized with a |RefPtr|, as in the example above, it returns
474 a |void**|, a |T**|, or an |nsISupports**| as needed, that the
475 outer call (|GetAddRefedPointer| in this case) can fill in.
477 This type should be a nested class inside |RefPtr<T>|.
480 public:
481 explicit RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
482 : mTargetSmartPtr(aSmartPtr) {
483 // nothing else to do
486 operator void**() {
487 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
490 operator T**() { return mTargetSmartPtr.StartAssignment(); }
492 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
494 private:
495 RefPtr<T>& mTargetSmartPtr;
498 template <class T>
499 inline RefPtrGetterAddRefs<T> getter_AddRefs(RefPtr<T>& aSmartPtr)
501 Used around a |RefPtr| when
502 ...makes the class |RefPtrGetterAddRefs<T>| invisible.
505 return RefPtrGetterAddRefs<T>(aSmartPtr);
508 // Comparing two |RefPtr|s
510 template <class T, class U>
511 inline bool operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
512 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
515 template <class T, class U>
516 inline bool operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
517 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
520 // Comparing an |RefPtr| to a raw pointer
522 template <class T, class U>
523 inline bool operator==(const RefPtr<T>& aLhs, const U* aRhs) {
524 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs);
527 template <class T, class U>
528 inline bool operator==(const U* aLhs, const RefPtr<T>& aRhs) {
529 return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
532 template <class T, class U>
533 inline bool operator!=(const RefPtr<T>& aLhs, const U* aRhs) {
534 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs);
537 template <class T, class U>
538 inline bool operator!=(const U* aLhs, const RefPtr<T>& aRhs) {
539 return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
542 template <class T, class U>
543 inline bool operator==(const RefPtr<T>& aLhs, U* aRhs) {
544 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
547 template <class T, class U>
548 inline bool operator==(U* aLhs, const RefPtr<T>& aRhs) {
549 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
552 template <class T, class U>
553 inline bool operator!=(const RefPtr<T>& aLhs, U* aRhs) {
554 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
557 template <class T, class U>
558 inline bool operator!=(U* aLhs, const RefPtr<T>& aRhs) {
559 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
562 // Comparing an |RefPtr| to |nullptr|
564 template <class T>
565 inline bool operator==(const RefPtr<T>& aLhs, decltype(nullptr)) {
566 return aLhs.get() == nullptr;
569 template <class T>
570 inline bool operator==(decltype(nullptr), const RefPtr<T>& aRhs) {
571 return nullptr == aRhs.get();
574 template <class T>
575 inline bool operator!=(const RefPtr<T>& aLhs, decltype(nullptr)) {
576 return aLhs.get() != nullptr;
579 template <class T>
580 inline bool operator!=(decltype(nullptr), const RefPtr<T>& aRhs) {
581 return nullptr != aRhs.get();
584 // MOZ_DBG support
586 template <class T>
587 std::ostream& operator<<(std::ostream& aOut, const RefPtr<T>& aObj) {
588 return mozilla::DebugValue(aOut, aObj.get());
591 /*****************************************************************************/
593 template <class T>
594 inline already_AddRefed<T> do_AddRef(T* aObj) {
595 RefPtr<T> ref(aObj);
596 return ref.forget();
599 template <class T>
600 inline already_AddRefed<T> do_AddRef(const RefPtr<T>& aObj) {
601 RefPtr<T> ref(aObj);
602 return ref.forget();
605 namespace mozilla {
607 template <typename T>
608 class AlignmentFinder;
610 // Provide a specialization of AlignmentFinder to allow MOZ_ALIGNOF(RefPtr<T>)
611 // with an incomplete T.
612 template <typename T>
613 class AlignmentFinder<RefPtr<T>> {
614 public:
615 static const size_t alignment = alignof(T*);
619 * Helper function to be able to conveniently write things like:
621 * already_AddRefed<T>
622 * f(...)
624 * return MakeAndAddRef<T>(...);
627 template <typename T, typename... Args>
628 already_AddRefed<T> MakeAndAddRef(Args&&... aArgs) {
629 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
630 return p.forget();
634 * Helper function to be able to conveniently write things like:
636 * auto runnable =
637 * MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
638 * mOnSuccess, mOnFailure, *error, mWindowID);
640 template <typename T, typename... Args>
641 RefPtr<T> MakeRefPtr(Args&&... aArgs) {
642 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
643 return p;
646 } // namespace mozilla
649 * Deduction guide to allow simple `RefPtr` definitions from an
650 * already_AddRefed<T> without repeating the type, e.g.:
652 * RefPtr ptr = MakeAndAddRef<SomeType>(...);
654 template <typename T>
655 RefPtr(already_AddRefed<T>) -> RefPtr<T>;
657 #endif /* mozilla_RefPtr_h */