Bug 1531915 [wpt PR 15578] - Fix flakiness of external/wpt/css/css-position/z-index...
[gecko.git] / mfbt / RefPtr.h
blob1736d99f91433241a6eaee8a2dab584668121e25
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 /*****************************************************************************/
17 // template <class T> class RefPtrGetterAddRefs;
19 class nsQueryReferent;
20 class nsCOMPtr_helper;
21 class nsISupports;
23 namespace mozilla {
24 template <class T>
25 class OwningNonNull;
26 template <class T>
27 class StaticRefPtr;
28 #if defined(XP_WIN)
29 namespace mscom {
30 class AgileReference;
31 } // namespace mscom
32 #endif // defined(XP_WIN)
34 // Traditionally, RefPtr supports automatic refcounting of any pointer type
35 // with AddRef() and Release() methods that follow the traditional semantics.
37 // This traits class can be specialized to operate on other pointer types. For
38 // example, we specialize this trait for opaque FFI types that represent
39 // refcounted objects in Rust.
41 // Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
42 // qualified type.
43 template <class U>
44 struct RefPtrTraits {
45 static void AddRef(U* aPtr) { aPtr->AddRef(); }
46 static void Release(U* aPtr) { aPtr->Release(); }
49 } // namespace mozilla
51 template <class T>
52 class MOZ_IS_REFPTR RefPtr {
53 private:
54 void assign_with_AddRef(T* aRawPtr) {
55 if (aRawPtr) {
56 ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
58 assign_assuming_AddRef(aRawPtr);
61 void assign_assuming_AddRef(T* aNewPtr) {
62 T* oldPtr = mRawPtr;
63 mRawPtr = aNewPtr;
64 if (oldPtr) {
65 ConstRemovingRefPtrTraits<T>::Release(oldPtr);
69 private:
70 T* MOZ_OWNING_REF mRawPtr;
72 public:
73 typedef T element_type;
75 ~RefPtr() {
76 if (mRawPtr) {
77 ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
81 // Constructors
83 RefPtr()
84 : mRawPtr(nullptr)
85 // default constructor
88 RefPtr(const RefPtr<T>& aSmartPtr)
89 : mRawPtr(aSmartPtr.mRawPtr)
90 // copy-constructor
92 if (mRawPtr) {
93 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
97 RefPtr(RefPtr<T>&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) {
98 aRefPtr.mRawPtr = nullptr;
101 // construct from a raw pointer (of the right type)
103 MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) {
104 if (mRawPtr) {
105 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
109 MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {}
111 template <typename I>
112 MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
113 : mRawPtr(aSmartPtr.take())
114 // construct from |already_AddRefed|
117 template <typename I>
118 MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr)
119 : mRawPtr(aSmartPtr.take())
120 // construct from |otherRefPtr.forget()|
123 template <typename I>
124 MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr)
125 : mRawPtr(aSmartPtr.get())
126 // copy-construct from a smart pointer with a related pointer type
128 if (mRawPtr) {
129 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
133 template <typename I>
134 MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
135 : mRawPtr(aSmartPtr.forget().take())
136 // construct from |Move(RefPtr<SomeSubclassOfT>)|.
139 MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper);
140 MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
141 #if defined(XP_WIN)
142 MOZ_IMPLICIT RefPtr(const mozilla::mscom::AgileReference& aAgileRef);
143 #endif // defined(XP_WIN)
145 // Defined in OwningNonNull.h
146 template <class U>
147 MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
149 // Defined in StaticPtr.h
150 template <class U>
151 MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
153 // Assignment operators
155 RefPtr<T>& operator=(decltype(nullptr)) {
156 assign_assuming_AddRef(nullptr);
157 return *this;
160 RefPtr<T>& operator=(const RefPtr<T>& aRhs)
161 // copy assignment operator
163 assign_with_AddRef(aRhs.mRawPtr);
164 return *this;
167 template <typename I>
168 RefPtr<T>& operator=(const RefPtr<I>& aRhs)
169 // assign from an RefPtr of a related pointer type
171 assign_with_AddRef(aRhs.get());
172 return *this;
175 RefPtr<T>& operator=(T* aRhs)
176 // assign from a raw pointer (of the right type)
178 assign_with_AddRef(aRhs);
179 return *this;
182 template <typename I>
183 RefPtr<T>& operator=(already_AddRefed<I>& aRhs)
184 // assign from |already_AddRefed|
186 assign_assuming_AddRef(aRhs.take());
187 return *this;
190 template <typename I>
191 RefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
192 // assign from |otherRefPtr.forget()|
194 assign_assuming_AddRef(aRhs.take());
195 return *this;
198 RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent);
199 RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
200 #if defined(XP_WIN)
201 RefPtr<T>& operator=(const mozilla::mscom::AgileReference& aAgileRef);
202 #endif // defined(XP_WIN)
204 RefPtr<T>& operator=(RefPtr<T>&& aRefPtr) {
205 assign_assuming_AddRef(aRefPtr.forget().take());
206 return *this;
209 // Defined in OwningNonNull.h
210 template <class U>
211 RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
213 // Defined in StaticPtr.h
214 template <class U>
215 RefPtr<T>& operator=(const mozilla::StaticRefPtr<U>& aOther);
217 // Other pointer operators
219 void swap(RefPtr<T>& aRhs)
220 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
222 T* temp = aRhs.mRawPtr;
223 aRhs.mRawPtr = mRawPtr;
224 mRawPtr = temp;
227 void swap(T*& aRhs)
228 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
230 T* temp = aRhs;
231 aRhs = mRawPtr;
232 mRawPtr = temp;
235 already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget()
236 // return the value of mRawPtr and null out mRawPtr. Useful for
237 // already_AddRefed return values.
239 T* temp = nullptr;
240 swap(temp);
241 return already_AddRefed<T>(temp);
244 template <typename I>
245 void forget(I** aRhs)
246 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
247 // Useful to avoid unnecessary AddRef/Release pairs with "out"
248 // parameters where aRhs bay be a T** or an I** where I is a base class
249 // of T.
251 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
252 *aRhs = mRawPtr;
253 mRawPtr = nullptr;
256 void forget(nsISupports** aRhs) {
257 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
258 *aRhs = ToSupports(mRawPtr);
259 mRawPtr = nullptr;
262 T* get() const
264 Prefer the implicit conversion provided automatically by |operator T*()
265 const|. Use |get()| to resolve ambiguity or to get a castable pointer.
268 return const_cast<T*>(mRawPtr);
271 operator T*() const&
273 ...makes an |RefPtr| act like its underlying raw pointer type whenever it
274 is used in a context where a raw pointer is expected. It is this operator
275 that makes an |RefPtr| substitutable for a raw pointer.
277 Prefer the implicit use of this operator to calling |get()|, except where
278 necessary to resolve ambiguity.
281 return get();
284 // Don't allow implicit conversion of temporary RefPtr to raw pointer,
285 // because the refcount might be one and the pointer will immediately become
286 // invalid.
287 operator T*() const&& = delete;
289 // These are needed to avoid the deleted operator above. XXX Why is operator!
290 // needed separately? Shouldn't the compiler prefer using the non-deleted
291 // operator bool instead of the deleted operator T*?
292 explicit operator bool() const { return !!mRawPtr; }
293 bool operator!() const { return !mRawPtr; }
295 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
296 MOZ_ASSERT(mRawPtr != nullptr,
297 "You can't dereference a NULL RefPtr with operator->().");
298 return get();
301 template <typename R, typename... Args>
302 class Proxy {
303 typedef R (T::*member_function)(Args...);
304 T* mRawPtr;
305 member_function mFunction;
307 public:
308 Proxy(T* aRawPtr, member_function aFunction)
309 : mRawPtr(aRawPtr), mFunction(aFunction) {}
310 template <typename... ActualArgs>
311 R operator()(ActualArgs&&... aArgs) {
312 return ((*mRawPtr).*mFunction)(std::forward<ActualArgs>(aArgs)...);
316 template <typename R, typename... Args>
317 Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const {
318 MOZ_ASSERT(mRawPtr != nullptr,
319 "You can't dereference a NULL RefPtr with operator->*().");
320 return Proxy<R, Args...>(get(), aFptr);
323 RefPtr<T>* get_address()
324 // This is not intended to be used by clients. See |address_of|
325 // below.
327 return this;
330 const RefPtr<T>* get_address() const
331 // This is not intended to be used by clients. See |address_of|
332 // below.
334 return this;
337 public:
338 T& operator*() const {
339 MOZ_ASSERT(mRawPtr != nullptr,
340 "You can't dereference a NULL RefPtr with operator*().");
341 return *get();
344 T** StartAssignment() {
345 assign_assuming_AddRef(nullptr);
346 return reinterpret_cast<T**>(&mRawPtr);
349 private:
350 // This helper class makes |RefPtr<const T>| possible by casting away
351 // the constness from the pointer when calling AddRef() and Release().
353 // This is necessary because AddRef() and Release() implementations can't
354 // generally expected to be const themselves (without heavy use of |mutable|
355 // and |const_cast| in their own implementations).
357 // This should be sound because while |RefPtr<const T>| provides a
358 // const view of an object, the object itself should not be const (it
359 // would have to be allocated as |new const T| or similar to be const).
360 template <class U>
361 struct ConstRemovingRefPtrTraits {
362 static void AddRef(U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(aPtr); }
363 static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); }
365 template <class U>
366 struct ConstRemovingRefPtrTraits<const U> {
367 static void AddRef(const U* aPtr) {
368 mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
370 static void Release(const U* aPtr) {
371 mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
376 class nsCycleCollectionTraversalCallback;
377 template <typename T>
378 void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback,
379 T* aChild, const char* aName, uint32_t aFlags);
381 template <typename T>
382 inline void ImplCycleCollectionUnlink(RefPtr<T>& aField) {
383 aField = nullptr;
386 template <typename T>
387 inline void ImplCycleCollectionTraverse(
388 nsCycleCollectionTraversalCallback& aCallback, RefPtr<T>& aField,
389 const char* aName, uint32_t aFlags = 0) {
390 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
393 template <class T>
394 inline RefPtr<T>* address_of(RefPtr<T>& aPtr) {
395 return aPtr.get_address();
398 template <class T>
399 inline const RefPtr<T>* address_of(const RefPtr<T>& aPtr) {
400 return aPtr.get_address();
403 template <class T>
404 class RefPtrGetterAddRefs
408 This class is designed to be used for anonymous temporary objects in the
409 argument list of calls that return COM interface pointers, e.g.,
411 RefPtr<IFoo> fooP;
412 ...->GetAddRefedPointer(getter_AddRefs(fooP))
414 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
416 When initialized with a |RefPtr|, as in the example above, it returns
417 a |void**|, a |T**|, or an |nsISupports**| as needed, that the
418 outer call (|GetAddRefedPointer| in this case) can fill in.
420 This type should be a nested class inside |RefPtr<T>|.
423 public:
424 explicit RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
425 : mTargetSmartPtr(aSmartPtr) {
426 // nothing else to do
429 operator void**() {
430 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
433 operator T**() { return mTargetSmartPtr.StartAssignment(); }
435 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
437 private:
438 RefPtr<T>& mTargetSmartPtr;
441 template <class T>
442 inline RefPtrGetterAddRefs<T> getter_AddRefs(RefPtr<T>& aSmartPtr)
444 Used around a |RefPtr| when
445 ...makes the class |RefPtrGetterAddRefs<T>| invisible.
448 return RefPtrGetterAddRefs<T>(aSmartPtr);
451 // Comparing two |RefPtr|s
453 template <class T, class U>
454 inline bool operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
455 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
458 template <class T, class U>
459 inline bool operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
460 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
463 // Comparing an |RefPtr| to a raw pointer
465 template <class T, class U>
466 inline bool operator==(const RefPtr<T>& aLhs, const U* aRhs) {
467 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs);
470 template <class T, class U>
471 inline bool operator==(const U* aLhs, const RefPtr<T>& aRhs) {
472 return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
475 template <class T, class U>
476 inline bool operator!=(const RefPtr<T>& aLhs, const U* aRhs) {
477 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs);
480 template <class T, class U>
481 inline bool operator!=(const U* aLhs, const RefPtr<T>& aRhs) {
482 return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
485 template <class T, class U>
486 inline bool operator==(const RefPtr<T>& aLhs, U* aRhs) {
487 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
490 template <class T, class U>
491 inline bool operator==(U* aLhs, const RefPtr<T>& aRhs) {
492 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
495 template <class T, class U>
496 inline bool operator!=(const RefPtr<T>& aLhs, U* aRhs) {
497 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
500 template <class T, class U>
501 inline bool operator!=(U* aLhs, const RefPtr<T>& aRhs) {
502 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
505 // Comparing an |RefPtr| to |nullptr|
507 template <class T>
508 inline bool operator==(const RefPtr<T>& aLhs, decltype(nullptr)) {
509 return aLhs.get() == nullptr;
512 template <class T>
513 inline bool operator==(decltype(nullptr), const RefPtr<T>& aRhs) {
514 return nullptr == aRhs.get();
517 template <class T>
518 inline bool operator!=(const RefPtr<T>& aLhs, decltype(nullptr)) {
519 return aLhs.get() != nullptr;
522 template <class T>
523 inline bool operator!=(decltype(nullptr), const RefPtr<T>& aRhs) {
524 return nullptr != aRhs.get();
527 // MOZ_DBG support
529 template <class T>
530 std::ostream& operator<<(std::ostream& aOut, const RefPtr<T>& aObj) {
531 return mozilla::DebugValue(aOut, aObj.get());
534 /*****************************************************************************/
536 template <class T>
537 inline already_AddRefed<T> do_AddRef(T* aObj) {
538 RefPtr<T> ref(aObj);
539 return ref.forget();
542 template <class T>
543 inline already_AddRefed<T> do_AddRef(const RefPtr<T>& aObj) {
544 RefPtr<T> ref(aObj);
545 return ref.forget();
548 namespace mozilla {
551 * Helper function to be able to conveniently write things like:
553 * already_AddRefed<T>
554 * f(...)
556 * return MakeAndAddRef<T>(...);
559 template <typename T, typename... Args>
560 already_AddRefed<T> MakeAndAddRef(Args&&... aArgs) {
561 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
562 return p.forget();
566 * Helper function to be able to conveniently write things like:
568 * auto runnable =
569 * MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
570 * mOnSuccess, mOnFailure, *error, mWindowID);
572 template <typename T, typename... Args>
573 RefPtr<T> MakeRefPtr(Args&&... aArgs) {
574 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
575 return p;
578 } // namespace mozilla
580 #endif /* mozilla_RefPtr_h */