Bug 1719035 [wpt PR 29572] - Address flakiness in import-css-module-basic.html, a...
[gecko.git] / mfbt / RefPtr.h
blobb251b4b8f6fabb9955042a2d94920fc10fc25d68
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 OwningNonNull;
28 template <class T>
29 class StaticLocalRefPtr;
30 template <class T>
31 class StaticRefPtr;
32 #if defined(XP_WIN)
33 namespace mscom {
34 class AgileReference;
35 } // namespace mscom
36 #endif // defined(XP_WIN)
38 // Traditionally, RefPtr supports automatic refcounting of any pointer type
39 // with AddRef() and Release() methods that follow the traditional semantics.
41 // This traits class can be specialized to operate on other pointer types. For
42 // example, we specialize this trait for opaque FFI types that represent
43 // refcounted objects in Rust.
45 // Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
46 // qualified type.
47 template <class U>
48 struct RefPtrTraits {
49 static void AddRef(U* aPtr) { aPtr->AddRef(); }
50 static void Release(U* aPtr) { aPtr->Release(); }
53 } // namespace mozilla
55 template <class T>
56 class MOZ_IS_REFPTR RefPtr {
57 private:
58 void assign_with_AddRef(T* aRawPtr) {
59 if (aRawPtr) {
60 ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
62 assign_assuming_AddRef(aRawPtr);
65 void assign_assuming_AddRef(T* aNewPtr) {
66 T* oldPtr = mRawPtr;
67 mRawPtr = aNewPtr;
68 if (oldPtr) {
69 ConstRemovingRefPtrTraits<T>::Release(oldPtr);
73 private:
74 T* MOZ_OWNING_REF mRawPtr;
76 public:
77 typedef T element_type;
79 ~RefPtr() {
80 if (mRawPtr) {
81 ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
85 // Constructors
87 RefPtr()
88 : mRawPtr(nullptr)
89 // default constructor
92 RefPtr(const RefPtr<T>& aSmartPtr)
93 : mRawPtr(aSmartPtr.mRawPtr)
94 // copy-constructor
96 if (mRawPtr) {
97 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
101 RefPtr(RefPtr<T>&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) {
102 aRefPtr.mRawPtr = nullptr;
105 // construct from a raw pointer (of the right type)
107 MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) {
108 if (mRawPtr) {
109 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
113 MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {}
115 template <typename I,
116 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
117 MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
118 : mRawPtr(aSmartPtr.take())
119 // construct from |already_AddRefed|
122 template <typename I,
123 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
124 MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr)
125 : mRawPtr(aSmartPtr.take())
126 // construct from |otherRefPtr.forget()|
129 template <typename I,
130 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
131 MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr)
132 : mRawPtr(aSmartPtr.get())
133 // copy-construct from a smart pointer with a related pointer type
135 if (mRawPtr) {
136 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
140 template <typename I,
141 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
142 MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
143 : mRawPtr(aSmartPtr.forget().take())
144 // construct from |Move(RefPtr<SomeSubclassOfT>)|.
147 MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper);
148 MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
149 #if defined(XP_WIN)
150 MOZ_IMPLICIT RefPtr(const mozilla::mscom::AgileReference& aAgileRef);
151 #endif // defined(XP_WIN)
153 // Defined in OwningNonNull.h
154 template <class U>
155 MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
157 // Defined in StaticLocalPtr.h
158 template <class U>
159 MOZ_IMPLICIT RefPtr(const mozilla::StaticLocalRefPtr<U>& aOther);
161 // Defined in StaticPtr.h
162 template <class U>
163 MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
165 // Assignment operators
167 RefPtr<T>& operator=(decltype(nullptr)) {
168 assign_assuming_AddRef(nullptr);
169 return *this;
172 RefPtr<T>& operator=(const RefPtr<T>& aRhs)
173 // copy assignment operator
175 assign_with_AddRef(aRhs.mRawPtr);
176 return *this;
179 template <typename I>
180 RefPtr<T>& operator=(const RefPtr<I>& aRhs)
181 // assign from an RefPtr of a related pointer type
183 assign_with_AddRef(aRhs.get());
184 return *this;
187 RefPtr<T>& operator=(T* aRhs)
188 // assign from a raw pointer (of the right type)
190 assign_with_AddRef(aRhs);
191 return *this;
194 template <typename I>
195 RefPtr<T>& operator=(already_AddRefed<I>& aRhs)
196 // assign from |already_AddRefed|
198 assign_assuming_AddRef(aRhs.take());
199 return *this;
202 template <typename I>
203 RefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
204 // assign from |otherRefPtr.forget()|
206 assign_assuming_AddRef(aRhs.take());
207 return *this;
210 RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent);
211 RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
212 #if defined(XP_WIN)
213 RefPtr<T>& operator=(const mozilla::mscom::AgileReference& aAgileRef);
214 #endif // defined(XP_WIN)
216 template <typename I,
217 typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
218 RefPtr<T>& operator=(RefPtr<I>&& aRefPtr) {
219 assign_assuming_AddRef(aRefPtr.forget().take());
220 return *this;
223 // Defined in OwningNonNull.h
224 template <class U>
225 RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
227 // Defined in StaticLocalPtr.h
228 template <class U>
229 RefPtr<T>& operator=(const mozilla::StaticLocalRefPtr<U>& aOther);
231 // Defined in StaticPtr.h
232 template <class U>
233 RefPtr<T>& operator=(const mozilla::StaticRefPtr<U>& aOther);
235 // Other pointer operators
237 void swap(RefPtr<T>& aRhs)
238 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
240 T* temp = aRhs.mRawPtr;
241 aRhs.mRawPtr = mRawPtr;
242 mRawPtr = temp;
245 void swap(T*& aRhs)
246 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
248 T* temp = aRhs;
249 aRhs = mRawPtr;
250 mRawPtr = temp;
253 already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget()
254 // return the value of mRawPtr and null out mRawPtr. Useful for
255 // already_AddRefed return values.
257 T* temp = nullptr;
258 swap(temp);
259 return already_AddRefed<T>(temp);
262 template <typename I>
263 void forget(I** aRhs)
264 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
265 // Useful to avoid unnecessary AddRef/Release pairs with "out"
266 // parameters where aRhs bay be a T** or an I** where I is a base class
267 // of T.
269 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
270 *aRhs = mRawPtr;
271 mRawPtr = nullptr;
274 void forget(nsISupports** aRhs) {
275 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
276 *aRhs = ToSupports(mRawPtr);
277 mRawPtr = nullptr;
280 T* get() const
282 Prefer the implicit conversion provided automatically by |operator T*()
283 const|. Use |get()| to resolve ambiguity or to get a castable pointer.
286 return const_cast<T*>(mRawPtr);
289 operator T*() const&
291 ...makes an |RefPtr| act like its underlying raw pointer type whenever it
292 is used in a context where a raw pointer is expected. It is this operator
293 that makes an |RefPtr| substitutable for a raw pointer.
295 Prefer the implicit use of this operator to calling |get()|, except where
296 necessary to resolve ambiguity.
299 return get();
302 // Don't allow implicit conversion of temporary RefPtr to raw pointer,
303 // because the refcount might be one and the pointer will immediately become
304 // invalid.
305 operator T*() const&& = delete;
307 // These are needed to avoid the deleted operator above. XXX Why is operator!
308 // needed separately? Shouldn't the compiler prefer using the non-deleted
309 // operator bool instead of the deleted operator T*?
310 explicit operator bool() const { return !!mRawPtr; }
311 bool operator!() const { return !mRawPtr; }
313 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
314 MOZ_ASSERT(mRawPtr != nullptr,
315 "You can't dereference a NULL RefPtr with operator->().");
316 return get();
319 template <typename R, typename... Args>
320 class Proxy {
321 typedef R (T::*member_function)(Args...);
322 T* mRawPtr;
323 member_function mFunction;
325 public:
326 Proxy(T* aRawPtr, member_function aFunction)
327 : mRawPtr(aRawPtr), mFunction(aFunction) {}
328 template <typename... ActualArgs>
329 R operator()(ActualArgs&&... aArgs) {
330 return ((*mRawPtr).*mFunction)(std::forward<ActualArgs>(aArgs)...);
334 template <typename R, typename... Args>
335 Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const {
336 MOZ_ASSERT(mRawPtr != nullptr,
337 "You can't dereference a NULL RefPtr with operator->*().");
338 return Proxy<R, Args...>(get(), aFptr);
341 RefPtr<T>* get_address()
342 // This is not intended to be used by clients. See |address_of|
343 // below.
345 return this;
348 const RefPtr<T>* get_address() const
349 // This is not intended to be used by clients. See |address_of|
350 // below.
352 return this;
355 public:
356 T& operator*() const {
357 MOZ_ASSERT(mRawPtr != nullptr,
358 "You can't dereference a NULL RefPtr with operator*().");
359 return *get();
362 T** StartAssignment() {
363 assign_assuming_AddRef(nullptr);
364 return reinterpret_cast<T**>(&mRawPtr);
367 private:
368 // This helper class makes |RefPtr<const T>| possible by casting away
369 // the constness from the pointer when calling AddRef() and Release().
371 // This is necessary because AddRef() and Release() implementations can't
372 // generally expected to be const themselves (without heavy use of |mutable|
373 // and |const_cast| in their own implementations).
375 // This should be sound because while |RefPtr<const T>| provides a
376 // const view of an object, the object itself should not be const (it
377 // would have to be allocated as |new const T| or similar to be const).
378 template <class U>
379 struct ConstRemovingRefPtrTraits {
380 static void AddRef(U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(aPtr); }
381 static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); }
383 template <class U>
384 struct ConstRemovingRefPtrTraits<const U> {
385 static void AddRef(const U* aPtr) {
386 mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
388 static void Release(const U* aPtr) {
389 mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
394 class nsCycleCollectionTraversalCallback;
395 template <typename T>
396 void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback,
397 T* aChild, const char* aName, uint32_t aFlags);
399 template <typename T>
400 inline void ImplCycleCollectionUnlink(RefPtr<T>& aField) {
401 aField = nullptr;
404 template <typename T>
405 inline void ImplCycleCollectionTraverse(
406 nsCycleCollectionTraversalCallback& aCallback, RefPtr<T>& aField,
407 const char* aName, uint32_t aFlags = 0) {
408 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
411 template <class T>
412 inline RefPtr<T>* address_of(RefPtr<T>& aPtr) {
413 return aPtr.get_address();
416 template <class T>
417 inline const RefPtr<T>* address_of(const RefPtr<T>& aPtr) {
418 return aPtr.get_address();
421 template <class T>
422 class RefPtrGetterAddRefs
426 This class is designed to be used for anonymous temporary objects in the
427 argument list of calls that return COM interface pointers, e.g.,
429 RefPtr<IFoo> fooP;
430 ...->GetAddRefedPointer(getter_AddRefs(fooP))
432 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
434 When initialized with a |RefPtr|, as in the example above, it returns
435 a |void**|, a |T**|, or an |nsISupports**| as needed, that the
436 outer call (|GetAddRefedPointer| in this case) can fill in.
438 This type should be a nested class inside |RefPtr<T>|.
441 public:
442 explicit RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
443 : mTargetSmartPtr(aSmartPtr) {
444 // nothing else to do
447 operator void**() {
448 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
451 operator T**() { return mTargetSmartPtr.StartAssignment(); }
453 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
455 private:
456 RefPtr<T>& mTargetSmartPtr;
459 template <class T>
460 inline RefPtrGetterAddRefs<T> getter_AddRefs(RefPtr<T>& aSmartPtr)
462 Used around a |RefPtr| when
463 ...makes the class |RefPtrGetterAddRefs<T>| invisible.
466 return RefPtrGetterAddRefs<T>(aSmartPtr);
469 // Comparing two |RefPtr|s
471 template <class T, class U>
472 inline bool operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
473 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
476 template <class T, class U>
477 inline bool operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
478 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
481 // Comparing an |RefPtr| to a raw pointer
483 template <class T, class U>
484 inline bool operator==(const RefPtr<T>& aLhs, const U* aRhs) {
485 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs);
488 template <class T, class U>
489 inline bool operator==(const U* aLhs, const RefPtr<T>& aRhs) {
490 return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
493 template <class T, class U>
494 inline bool operator!=(const RefPtr<T>& aLhs, const U* aRhs) {
495 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs);
498 template <class T, class U>
499 inline bool operator!=(const U* aLhs, const RefPtr<T>& aRhs) {
500 return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
503 template <class T, class U>
504 inline bool operator==(const RefPtr<T>& aLhs, U* aRhs) {
505 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
508 template <class T, class U>
509 inline bool operator==(U* aLhs, const RefPtr<T>& aRhs) {
510 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
513 template <class T, class U>
514 inline bool operator!=(const RefPtr<T>& aLhs, U* aRhs) {
515 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
518 template <class T, class U>
519 inline bool operator!=(U* aLhs, const RefPtr<T>& aRhs) {
520 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
523 // Comparing an |RefPtr| to |nullptr|
525 template <class T>
526 inline bool operator==(const RefPtr<T>& aLhs, decltype(nullptr)) {
527 return aLhs.get() == nullptr;
530 template <class T>
531 inline bool operator==(decltype(nullptr), const RefPtr<T>& aRhs) {
532 return nullptr == aRhs.get();
535 template <class T>
536 inline bool operator!=(const RefPtr<T>& aLhs, decltype(nullptr)) {
537 return aLhs.get() != nullptr;
540 template <class T>
541 inline bool operator!=(decltype(nullptr), const RefPtr<T>& aRhs) {
542 return nullptr != aRhs.get();
545 // MOZ_DBG support
547 template <class T>
548 std::ostream& operator<<(std::ostream& aOut, const RefPtr<T>& aObj) {
549 return mozilla::DebugValue(aOut, aObj.get());
552 /*****************************************************************************/
554 template <class T>
555 inline already_AddRefed<T> do_AddRef(T* aObj) {
556 RefPtr<T> ref(aObj);
557 return ref.forget();
560 template <class T>
561 inline already_AddRefed<T> do_AddRef(const RefPtr<T>& aObj) {
562 RefPtr<T> ref(aObj);
563 return ref.forget();
566 namespace mozilla {
568 template <typename T>
569 class AlignmentFinder;
571 // Provide a specialization of AlignmentFinder to allow MOZ_ALIGNOF(RefPtr<T>)
572 // with an incomplete T.
573 template <typename T>
574 class AlignmentFinder<RefPtr<T>> {
575 public:
576 static const size_t alignment = alignof(T*);
580 * Helper function to be able to conveniently write things like:
582 * already_AddRefed<T>
583 * f(...)
585 * return MakeAndAddRef<T>(...);
588 template <typename T, typename... Args>
589 already_AddRefed<T> MakeAndAddRef(Args&&... aArgs) {
590 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
591 return p.forget();
595 * Helper function to be able to conveniently write things like:
597 * auto runnable =
598 * MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
599 * mOnSuccess, mOnFailure, *error, mWindowID);
601 template <typename T, typename... Args>
602 RefPtr<T> MakeRefPtr(Args&&... aArgs) {
603 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
604 return p;
607 } // namespace mozilla
610 * Deduction guide to allow simple `RefPtr` definitions from an
611 * already_AddRefed<T> without repeating the type, e.g.:
613 * RefPtr ptr = MakeAndAddRef<SomeType>(...);
615 template <typename T>
616 RefPtr(already_AddRefed<T>) -> RefPtr<T>;
618 #endif /* mozilla_RefPtr_h */