Bug 1485328 [wpt PR 12617] - HTML: test that floating legends do not disappear, a...
[gecko.git] / mfbt / RefPtr.h
blob4ba2854f1487335a5dae608c2bd4b613225a7add
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"
14 /*****************************************************************************/
16 // template <class T> class RefPtrGetterAddRefs;
18 class nsQueryReferent;
19 class nsCOMPtr_helper;
20 class nsISupports;
22 namespace mozilla {
23 template<class T> class OwningNonNull;
24 template<class T> class StaticRefPtr;
26 // Traditionally, RefPtr supports automatic refcounting of any pointer type
27 // with AddRef() and Release() methods that follow the traditional semantics.
29 // This traits class can be specialized to operate on other pointer types. For
30 // example, we specialize this trait for opaque FFI types that represent
31 // refcounted objects in Rust.
33 // Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
34 // qualified type.
35 template<class U>
36 struct RefPtrTraits
38 static void AddRef(U* aPtr) {
39 aPtr->AddRef();
41 static void Release(U* aPtr) {
42 aPtr->Release();
46 } // namespace mozilla
48 template <class T>
49 class MOZ_IS_REFPTR RefPtr
51 private:
52 void
53 assign_with_AddRef(T* aRawPtr)
55 if (aRawPtr) {
56 ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
58 assign_assuming_AddRef(aRawPtr);
61 void
62 assign_assuming_AddRef(T* aNewPtr)
64 T* oldPtr = mRawPtr;
65 mRawPtr = aNewPtr;
66 if (oldPtr) {
67 ConstRemovingRefPtrTraits<T>::Release(oldPtr);
71 private:
72 T* MOZ_OWNING_REF mRawPtr;
74 public:
75 typedef T element_type;
77 ~RefPtr()
79 if (mRawPtr) {
80 ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
84 // Constructors
86 RefPtr()
87 : mRawPtr(nullptr)
88 // 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)
102 : mRawPtr(aRefPtr.mRawPtr)
104 aRefPtr.mRawPtr = nullptr;
107 // construct from a raw pointer (of the right type)
109 MOZ_IMPLICIT RefPtr(T* aRawPtr)
110 : mRawPtr(aRawPtr)
112 if (mRawPtr) {
113 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
117 MOZ_IMPLICIT RefPtr(decltype(nullptr))
118 : mRawPtr(nullptr)
122 template <typename I>
123 MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
124 : mRawPtr(aSmartPtr.take())
125 // construct from |already_AddRefed|
129 template <typename I>
130 MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr)
131 : mRawPtr(aSmartPtr.take())
132 // construct from |otherRefPtr.forget()|
136 template <typename I>
137 MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr)
138 : mRawPtr(aSmartPtr.get())
139 // copy-construct from a smart pointer with a related pointer type
141 if (mRawPtr) {
142 ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
146 template <typename I>
147 MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
148 : mRawPtr(aSmartPtr.forget().take())
149 // construct from |Move(RefPtr<SomeSubclassOfT>)|.
153 MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper);
154 MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
156 // Defined in OwningNonNull.h
157 template<class U>
158 MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
160 // Defined in StaticPtr.h
161 template<class U>
162 MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
164 // Assignment operators
166 RefPtr<T>&
167 operator=(decltype(nullptr))
169 assign_assuming_AddRef(nullptr);
170 return *this;
173 RefPtr<T>&
174 operator=(const RefPtr<T>& aRhs)
175 // copy assignment operator
177 assign_with_AddRef(aRhs.mRawPtr);
178 return *this;
181 template <typename I>
182 RefPtr<T>&
183 operator=(const RefPtr<I>& aRhs)
184 // assign from an RefPtr of a related pointer type
186 assign_with_AddRef(aRhs.get());
187 return *this;
190 RefPtr<T>&
191 operator=(T* aRhs)
192 // assign from a raw pointer (of the right type)
194 assign_with_AddRef(aRhs);
195 return *this;
198 template <typename I>
199 RefPtr<T>&
200 operator=(already_AddRefed<I>& aRhs)
201 // assign from |already_AddRefed|
203 assign_assuming_AddRef(aRhs.take());
204 return *this;
207 template <typename I>
208 RefPtr<T>&
209 operator=(already_AddRefed<I> && aRhs)
210 // assign from |otherRefPtr.forget()|
212 assign_assuming_AddRef(aRhs.take());
213 return *this;
216 RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent);
217 RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
219 RefPtr<T>&
220 operator=(RefPtr<T> && aRefPtr)
222 assign_assuming_AddRef(aRefPtr.mRawPtr);
223 aRefPtr.mRawPtr = nullptr;
224 return *this;
227 // Defined in OwningNonNull.h
228 template<class U>
229 RefPtr<T>&
230 operator=(const mozilla::OwningNonNull<U>& aOther);
232 // Defined in StaticPtr.h
233 template<class U>
234 RefPtr<T>&
235 operator=(const mozilla::StaticRefPtr<U>& aOther);
237 // Other pointer operators
239 void
240 swap(RefPtr<T>& aRhs)
241 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
243 T* temp = aRhs.mRawPtr;
244 aRhs.mRawPtr = mRawPtr;
245 mRawPtr = temp;
248 void
249 swap(T*& aRhs)
250 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
252 T* temp = aRhs;
253 aRhs = mRawPtr;
254 mRawPtr = temp;
257 already_AddRefed<T>
258 MOZ_MAY_CALL_AFTER_MUST_RETURN
259 forget()
260 // return the value of mRawPtr and null out mRawPtr. Useful for
261 // already_AddRefed return values.
263 T* temp = nullptr;
264 swap(temp);
265 return already_AddRefed<T>(temp);
268 template <typename I>
269 void
270 forget(I** aRhs)
271 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
272 // Useful to avoid unnecessary AddRef/Release pairs with "out"
273 // parameters where aRhs bay be a T** or an I** where I is a base class
274 // of T.
276 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
277 *aRhs = mRawPtr;
278 mRawPtr = nullptr;
281 void
282 forget(nsISupports** aRhs)
284 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
285 *aRhs = ToSupports(mRawPtr);
286 mRawPtr = nullptr;
290 get() const
292 Prefer the implicit conversion provided automatically by |operator T*() const|.
293 Use |get()| to resolve ambiguity or to get a castable pointer.
296 return const_cast<T*>(mRawPtr);
299 operator T*() const &
301 ...makes an |RefPtr| act like its underlying raw pointer type whenever it
302 is used in a context where a raw pointer is expected. It is this operator
303 that makes an |RefPtr| substitutable for a raw pointer.
305 Prefer the implicit use of this operator to calling |get()|, except where
306 necessary to resolve ambiguity.
309 return get();
312 // Don't allow implicit conversion of temporary RefPtr to raw pointer,
313 // because the refcount might be one and the pointer will immediately become
314 // invalid.
315 operator T*() const && = delete;
317 // These are needed to avoid the deleted operator above. XXX Why is operator!
318 // needed separately? Shouldn't the compiler prefer using the non-deleted
319 // operator bool instead of the deleted operator T*?
320 explicit operator bool() const { return !!mRawPtr; }
321 bool operator!() const { return !mRawPtr; }
324 operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
326 MOZ_ASSERT(mRawPtr != nullptr,
327 "You can't dereference a NULL RefPtr with operator->().");
328 return get();
331 template <typename R, typename... Args>
332 class Proxy
334 typedef R (T::*member_function)(Args...);
335 T* mRawPtr;
336 member_function mFunction;
337 public:
338 Proxy(T* aRawPtr, member_function aFunction)
339 : mRawPtr(aRawPtr),
340 mFunction(aFunction)
343 template<typename... ActualArgs>
344 R operator()(ActualArgs&&... aArgs)
346 return ((*mRawPtr).*mFunction)(std::forward<ActualArgs>(aArgs)...);
350 template <typename R, typename... Args>
351 Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const
353 MOZ_ASSERT(mRawPtr != nullptr,
354 "You can't dereference a NULL RefPtr with operator->*().");
355 return Proxy<R, Args...>(get(), aFptr);
358 RefPtr<T>*
359 get_address()
360 // This is not intended to be used by clients. See |address_of|
361 // below.
363 return this;
366 const RefPtr<T>*
367 get_address() const
368 // This is not intended to be used by clients. See |address_of|
369 // below.
371 return this;
374 public:
376 operator*() const
378 MOZ_ASSERT(mRawPtr != nullptr,
379 "You can't dereference a NULL RefPtr with operator*().");
380 return *get();
384 StartAssignment()
386 assign_assuming_AddRef(nullptr);
387 return reinterpret_cast<T**>(&mRawPtr);
389 private:
390 // This helper class makes |RefPtr<const T>| possible by casting away
391 // the constness from the pointer when calling AddRef() and Release().
393 // This is necessary because AddRef() and Release() implementations can't
394 // generally expected to be const themselves (without heavy use of |mutable|
395 // and |const_cast| in their own implementations).
397 // This should be sound because while |RefPtr<const T>| provides a
398 // const view of an object, the object itself should not be const (it
399 // would have to be allocated as |new const T| or similar to be const).
400 template<class U>
401 struct ConstRemovingRefPtrTraits
403 static void AddRef(U* aPtr) {
404 mozilla::RefPtrTraits<U>::AddRef(aPtr);
406 static void Release(U* aPtr) {
407 mozilla::RefPtrTraits<U>::Release(aPtr);
410 template<class U>
411 struct ConstRemovingRefPtrTraits<const U>
413 static void AddRef(const U* aPtr) {
414 mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
416 static void Release(const U* aPtr) {
417 mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
422 class nsCycleCollectionTraversalCallback;
423 template <typename T>
424 void
425 CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback,
426 T* aChild, const char* aName, uint32_t aFlags);
428 template <typename T>
429 inline void
430 ImplCycleCollectionUnlink(RefPtr<T>& aField)
432 aField = nullptr;
435 template <typename T>
436 inline void
437 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
438 RefPtr<T>& aField,
439 const char* aName,
440 uint32_t aFlags = 0)
442 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
445 template <class T>
446 inline RefPtr<T>*
447 address_of(RefPtr<T>& aPtr)
449 return aPtr.get_address();
452 template <class T>
453 inline const RefPtr<T>*
454 address_of(const RefPtr<T>& aPtr)
456 return aPtr.get_address();
459 template <class T>
460 class RefPtrGetterAddRefs
464 This class is designed to be used for anonymous temporary objects in the
465 argument list of calls that return COM interface pointers, e.g.,
467 RefPtr<IFoo> fooP;
468 ...->GetAddRefedPointer(getter_AddRefs(fooP))
470 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
472 When initialized with a |RefPtr|, as in the example above, it returns
473 a |void**|, a |T**|, or an |nsISupports**| as needed, that the
474 outer call (|GetAddRefedPointer| in this case) can fill in.
476 This type should be a nested class inside |RefPtr<T>|.
479 public:
480 explicit
481 RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
482 : mTargetSmartPtr(aSmartPtr)
484 // nothing else to do
487 operator void**()
489 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
492 operator T**()
494 return mTargetSmartPtr.StartAssignment();
498 operator*()
500 return *(mTargetSmartPtr.StartAssignment());
503 private:
504 RefPtr<T>& mTargetSmartPtr;
507 template <class T>
508 inline RefPtrGetterAddRefs<T>
509 getter_AddRefs(RefPtr<T>& aSmartPtr)
511 Used around a |RefPtr| when
512 ...makes the class |RefPtrGetterAddRefs<T>| invisible.
515 return RefPtrGetterAddRefs<T>(aSmartPtr);
519 // Comparing two |RefPtr|s
521 template <class T, class U>
522 inline bool
523 operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs)
525 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
529 template <class T, class U>
530 inline bool
531 operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs)
533 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
537 // Comparing an |RefPtr| to a raw pointer
539 template <class T, class U>
540 inline bool
541 operator==(const RefPtr<T>& aLhs, const U* aRhs)
543 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs);
546 template <class T, class U>
547 inline bool
548 operator==(const U* aLhs, const RefPtr<T>& aRhs)
550 return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
553 template <class T, class U>
554 inline bool
555 operator!=(const RefPtr<T>& aLhs, const U* aRhs)
557 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs);
560 template <class T, class U>
561 inline bool
562 operator!=(const U* aLhs, const RefPtr<T>& aRhs)
564 return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
567 template <class T, class U>
568 inline bool
569 operator==(const RefPtr<T>& aLhs, U* aRhs)
571 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
574 template <class T, class U>
575 inline bool
576 operator==(U* aLhs, const RefPtr<T>& aRhs)
578 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
581 template <class T, class U>
582 inline bool
583 operator!=(const RefPtr<T>& aLhs, U* aRhs)
585 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
588 template <class T, class U>
589 inline bool
590 operator!=(U* aLhs, const RefPtr<T>& aRhs)
592 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
595 // Comparing an |RefPtr| to |nullptr|
597 template <class T>
598 inline bool
599 operator==(const RefPtr<T>& aLhs, decltype(nullptr))
601 return aLhs.get() == nullptr;
604 template <class T>
605 inline bool
606 operator==(decltype(nullptr), const RefPtr<T>& aRhs)
608 return nullptr == aRhs.get();
611 template <class T>
612 inline bool
613 operator!=(const RefPtr<T>& aLhs, decltype(nullptr))
615 return aLhs.get() != nullptr;
618 template <class T>
619 inline bool
620 operator!=(decltype(nullptr), const RefPtr<T>& aRhs)
622 return nullptr != aRhs.get();
625 /*****************************************************************************/
627 template <class T>
628 inline already_AddRefed<T>
629 do_AddRef(T* aObj)
631 RefPtr<T> ref(aObj);
632 return ref.forget();
635 template <class T>
636 inline already_AddRefed<T>
637 do_AddRef(const RefPtr<T>& aObj)
639 RefPtr<T> ref(aObj);
640 return ref.forget();
643 namespace mozilla {
646 * Helper function to be able to conveniently write things like:
648 * already_AddRefed<T>
649 * f(...)
651 * return MakeAndAddRef<T>(...);
654 template<typename T, typename... Args>
655 already_AddRefed<T>
656 MakeAndAddRef(Args&&... aArgs)
658 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
659 return p.forget();
663 * Helper function to be able to conveniently write things like:
665 * auto runnable = MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
666 * mOnSuccess, mOnFailure, *error, mWindowID);
668 template<typename T, typename... Args>
669 RefPtr<T>
670 MakeRefPtr(Args&&... aArgs)
672 RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
673 return p;
676 } // namespace mozilla
678 #endif /* mozilla_RefPtr_h */