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
;
33 class StaticLocalRefPtr
;
37 // Traditionally, RefPtr supports automatic refcounting of any pointer type
38 // with AddRef() and Release() methods that follow the traditional semantics.
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.
44 // Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
48 static void AddRef(U
* aPtr
) { aPtr
->AddRef(); }
49 static void Release(U
* aPtr
) { aPtr
->Release(); }
52 } // namespace mozilla
55 class MOZ_IS_REFPTR RefPtr
{
57 void assign_with_AddRef(T
* aRawPtr
) {
59 ConstRemovingRefPtrTraits
<T
>::AddRef(aRawPtr
);
61 assign_assuming_AddRef(aRawPtr
);
64 void assign_assuming_AddRef(T
* aNewPtr
) {
68 ConstRemovingRefPtrTraits
<T
>::Release(oldPtr
);
73 T
* MOZ_OWNING_REF mRawPtr
;
76 typedef T element_type
;
80 ConstRemovingRefPtrTraits
<T
>::Release(mRawPtr
);
88 // default constructor
91 RefPtr(const RefPtr
<T
>& aSmartPtr
)
92 : mRawPtr(aSmartPtr
.mRawPtr
)
96 ConstRemovingRefPtrTraits
<T
>::AddRef(mRawPtr
);
100 RefPtr(RefPtr
<T
>&& aRefPtr
) noexcept
: mRawPtr(aRefPtr
.mRawPtr
) {
101 aRefPtr
.mRawPtr
= nullptr;
104 // construct from a raw pointer (of the right type)
106 MOZ_IMPLICIT
RefPtr(T
* aRawPtr
) : mRawPtr(aRawPtr
) {
108 ConstRemovingRefPtrTraits
<T
>::AddRef(mRawPtr
);
112 MOZ_IMPLICIT
RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {}
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|
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()|
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
135 ConstRemovingRefPtrTraits
<T
>::AddRef(mRawPtr
);
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>)|.
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|.
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|.
162 MOZ_IMPLICIT
RefPtr(const nsQueryReferent
& aHelper
);
163 MOZ_IMPLICIT
RefPtr(const nsCOMPtr_helper
& aHelper
);
165 // Defined in OwningNonNull.h
167 MOZ_IMPLICIT
RefPtr(const mozilla::OwningNonNull
<U
>& aOther
);
169 // Defined in StaticLocalPtr.h
171 MOZ_IMPLICIT
RefPtr(const mozilla::StaticLocalRefPtr
<U
>& aOther
);
173 // Defined in StaticPtr.h
175 MOZ_IMPLICIT
RefPtr(const mozilla::StaticRefPtr
<U
>& aOther
);
177 // Assignment operators
179 RefPtr
<T
>& operator=(decltype(nullptr)) {
180 assign_assuming_AddRef(nullptr);
184 RefPtr
<T
>& operator=(const RefPtr
<T
>& aRhs
)
185 // copy assignment operator
187 assign_with_AddRef(aRhs
.mRawPtr
);
191 template <typename I
>
192 RefPtr
<T
>& operator=(const RefPtr
<I
>& aRhs
)
193 // assign from an RefPtr of a related pointer type
195 assign_with_AddRef(aRhs
.get());
199 RefPtr
<T
>& operator=(T
* aRhs
)
200 // assign from a raw pointer (of the right type)
202 assign_with_AddRef(aRhs
);
206 template <typename I
>
207 RefPtr
<T
>& operator=(already_AddRefed
<I
>& aRhs
)
208 // assign from |already_AddRefed|
210 assign_assuming_AddRef(aRhs
.take());
214 template <typename I
>
215 RefPtr
<T
>& operator=(already_AddRefed
<I
>&& aRhs
)
216 // assign from |otherRefPtr.forget()|
218 assign_assuming_AddRef(aRhs
.take());
222 RefPtr
<T
>& operator=(const nsQueryReferent
& aQueryReferent
);
223 RefPtr
<T
>& operator=(const nsCOMPtr_helper
& aHelper
);
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());
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|.
237 assign_assuming_AddRef(RefPtr
<T
>(aSmartPtr
.get()).forget().take());
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|.
246 assign_assuming_AddRef(
247 RefPtr
<T
>(std::move(aSmartPtr
).unwrapBasePtr()).forget().take());
251 // Defined in OwningNonNull.h
253 RefPtr
<T
>& operator=(const mozilla::OwningNonNull
<U
>& aOther
);
255 // Defined in StaticLocalPtr.h
257 RefPtr
<T
>& operator=(const mozilla::StaticLocalRefPtr
<U
>& aOther
);
259 // Defined in StaticPtr.h
261 RefPtr
<T
>& operator=(const mozilla::StaticRefPtr
<U
>& aOther
);
263 // Other pointer operators
265 void swap(RefPtr
<T
>& aRhs
)
266 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
268 T
* temp
= aRhs
.mRawPtr
;
269 aRhs
.mRawPtr
= mRawPtr
;
274 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
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.
287 return already_AddRefed
<T
>(temp
);
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
297 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
302 void forget(nsISupports
** aRhs
) {
303 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
304 *aRhs
= ToSupports(mRawPtr
);
310 Prefer the implicit conversion provided automatically by |operator T*()
311 const|. Use |get()| to resolve ambiguity or to get a castable pointer.
314 return const_cast<T
*>(mRawPtr
);
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.
323 Prefer the implicit use of this operator to calling |get()|, except where
324 necessary to resolve ambiguity.
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
333 operator T
*() const&& = delete;
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
; }
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->().");
347 template <typename R
, typename
... Args
>
349 typedef R (T::*member_function
)(Args
...);
351 member_function mFunction
;
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
)...);
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
);
369 RefPtr
<T
>* get_address()
370 // This is not intended to be used by clients. See |address_of|
376 const RefPtr
<T
>* get_address() const
377 // This is not intended to be used by clients. See |address_of|
384 T
& operator*() const {
385 MOZ_ASSERT(mRawPtr
!= nullptr,
386 "You can't dereference a NULL RefPtr with operator*().");
390 T
** StartAssignment() {
391 assign_assuming_AddRef(nullptr);
392 return reinterpret_cast<T
**>(&mRawPtr
);
396 // This helper class makes |RefPtr<const T>| possible by casting away
397 // the constness from the pointer when calling AddRef() and Release().
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).
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).
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
); }
412 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 CycleCollectionNoteChild(nsCycleCollectionTraversalCallback
& aCallback
,
425 T
* aChild
, const char* aName
, uint32_t aFlags
);
427 template <typename T
>
428 inline void ImplCycleCollectionUnlink(RefPtr
<T
>& aField
) {
432 template <typename T
>
433 inline void ImplCycleCollectionTraverse(
434 nsCycleCollectionTraversalCallback
& aCallback
, RefPtr
<T
>& aField
,
435 const char* aName
, uint32_t aFlags
= 0) {
436 CycleCollectionNoteChild(aCallback
, aField
.get(), aName
, aFlags
);
440 inline RefPtr
<T
>* address_of(RefPtr
<T
>& aPtr
) {
441 return aPtr
.get_address();
445 inline const RefPtr
<T
>* address_of(const RefPtr
<T
>& aPtr
) {
446 return aPtr
.get_address();
450 class RefPtrGetterAddRefs
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.,
458 ...->GetAddRefedPointer(getter_AddRefs(fooP))
460 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
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.
466 This type should be a nested class inside |RefPtr<T>|.
470 explicit RefPtrGetterAddRefs(RefPtr
<T
>& aSmartPtr
)
471 : mTargetSmartPtr(aSmartPtr
) {
472 // nothing else to do
476 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
479 operator T
**() { return mTargetSmartPtr
.StartAssignment(); }
481 T
*& operator*() { return *(mTargetSmartPtr
.StartAssignment()); }
484 RefPtr
<T
>& mTargetSmartPtr
;
488 inline RefPtrGetterAddRefs
<T
> getter_AddRefs(RefPtr
<T
>& aSmartPtr
)
490 Used around a |RefPtr| when
491 ...makes the class |RefPtrGetterAddRefs<T>| invisible.
494 return RefPtrGetterAddRefs
<T
>(aSmartPtr
);
497 // Comparing two |RefPtr|s
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());
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());
509 // Comparing an |RefPtr| to a raw pointer
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
);
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());
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
);
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());
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
);
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());
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
);
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());
551 // Comparing an |RefPtr| to |nullptr|
554 inline bool operator==(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
555 return aLhs
.get() == nullptr;
559 inline bool operator==(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
560 return nullptr == aRhs
.get();
564 inline bool operator!=(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
565 return aLhs
.get() != nullptr;
569 inline bool operator!=(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
570 return nullptr != aRhs
.get();
576 std::ostream
& operator<<(std::ostream
& aOut
, const RefPtr
<T
>& aObj
) {
577 return mozilla::DebugValue(aOut
, aObj
.get());
580 /*****************************************************************************/
583 inline already_AddRefed
<T
> do_AddRef(T
* aObj
) {
589 inline already_AddRefed
<T
> do_AddRef(const RefPtr
<T
>& aObj
) {
596 template <typename T
>
597 class AlignmentFinder
;
599 // Provide a specialization of AlignmentFinder to allow MOZ_ALIGNOF(RefPtr<T>)
600 // with an incomplete T.
601 template <typename T
>
602 class AlignmentFinder
<RefPtr
<T
>> {
604 static const size_t alignment
= alignof(T
*);
608 * Helper function to be able to conveniently write things like:
610 * already_AddRefed<T>
613 * return MakeAndAddRef<T>(...);
616 template <typename T
, typename
... Args
>
617 already_AddRefed
<T
> MakeAndAddRef(Args
&&... aArgs
) {
618 RefPtr
<T
> p(new T(std::forward
<Args
>(aArgs
)...));
623 * Helper function to be able to conveniently write things like:
626 * MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
627 * mOnSuccess, mOnFailure, *error, mWindowID);
629 template <typename T
, typename
... Args
>
630 RefPtr
<T
> MakeRefPtr(Args
&&... aArgs
) {
631 RefPtr
<T
> p(new T(std::forward
<Args
>(aArgs
)...));
635 } // namespace mozilla
638 * Deduction guide to allow simple `RefPtr` definitions from an
639 * already_AddRefed<T> without repeating the type, e.g.:
641 * RefPtr ptr = MakeAndAddRef<SomeType>(...);
643 template <typename T
>
644 RefPtr(already_AddRefed
<T
>) -> RefPtr
<T
>;
646 #endif /* mozilla_RefPtr_h */