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
;
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-
53 static void AddRef(U
* aPtr
) { aPtr
->AddRef(); }
54 static void Release(U
* aPtr
) { aPtr
->Release(); }
57 } // namespace mozilla
60 class MOZ_IS_REFPTR RefPtr
{
62 void assign_with_AddRef(T
* aRawPtr
) {
64 ConstRemovingRefPtrTraits
<T
>::AddRef(aRawPtr
);
66 assign_assuming_AddRef(aRawPtr
);
69 void assign_assuming_AddRef(T
* aNewPtr
) {
73 ConstRemovingRefPtrTraits
<T
>::Release(oldPtr
);
78 T
* MOZ_OWNING_REF mRawPtr
;
81 typedef T element_type
;
85 ConstRemovingRefPtrTraits
<T
>::Release(mRawPtr
);
93 // default constructor
96 RefPtr(const RefPtr
<T
>& aSmartPtr
)
97 : mRawPtr(aSmartPtr
.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
) {
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
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
);
170 MOZ_IMPLICIT
RefPtr(const mozilla::mscom::AgileReference
& aAgileRef
);
171 #endif // defined(XP_WIN)
173 // Defined in OwningNonNull.h
175 MOZ_IMPLICIT
RefPtr(const mozilla::OwningNonNull
<U
>& aOther
);
177 // Defined in StaticLocalPtr.h
179 MOZ_IMPLICIT
RefPtr(const mozilla::StaticLocalRefPtr
<U
>& aOther
);
181 // Defined in StaticPtr.h
183 MOZ_IMPLICIT
RefPtr(const mozilla::StaticRefPtr
<U
>& aOther
);
185 // Assignment operators
187 RefPtr
<T
>& operator=(decltype(nullptr)) {
188 assign_assuming_AddRef(nullptr);
192 RefPtr
<T
>& operator=(const RefPtr
<T
>& aRhs
)
193 // copy assignment operator
195 assign_with_AddRef(aRhs
.mRawPtr
);
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());
207 RefPtr
<T
>& operator=(T
* aRhs
)
208 // assign from a raw pointer (of the right type)
210 assign_with_AddRef(aRhs
);
214 template <typename I
>
215 RefPtr
<T
>& operator=(already_AddRefed
<I
>& aRhs
)
216 // assign from |already_AddRefed|
218 assign_assuming_AddRef(aRhs
.take());
222 template <typename I
>
223 RefPtr
<T
>& operator=(already_AddRefed
<I
>&& aRhs
)
224 // assign from |otherRefPtr.forget()|
226 assign_assuming_AddRef(aRhs
.take());
230 RefPtr
<T
>& operator=(const nsQueryReferent
& aQueryReferent
);
231 RefPtr
<T
>& operator=(const nsCOMPtr_helper
& aHelper
);
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());
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());
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());
262 // Defined in OwningNonNull.h
264 RefPtr
<T
>& operator=(const mozilla::OwningNonNull
<U
>& aOther
);
266 // Defined in StaticLocalPtr.h
268 RefPtr
<T
>& operator=(const mozilla::StaticLocalRefPtr
<U
>& aOther
);
270 // Defined in StaticPtr.h
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
;
285 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
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.
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
308 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
313 void forget(nsISupports
** aRhs
) {
314 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
315 *aRhs
= ToSupports(mRawPtr
);
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
);
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.
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
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->().");
358 template <typename R
, typename
... Args
>
360 typedef R (T::*member_function
)(Args
...);
362 member_function mFunction
;
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|
387 const RefPtr
<T
>* get_address() const
388 // This is not intended to be used by clients. See |address_of|
395 T
& operator*() const {
396 MOZ_ASSERT(mRawPtr
!= nullptr,
397 "You can't dereference a NULL RefPtr with operator*().");
401 T
** StartAssignment() {
402 assign_assuming_AddRef(nullptr);
403 return reinterpret_cast<T
**>(&mRawPtr
);
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).
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
); }
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
) {
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
);
451 inline RefPtr
<T
>* address_of(RefPtr
<T
>& aPtr
) {
452 return aPtr
.get_address();
456 inline const RefPtr
<T
>* address_of(const RefPtr
<T
>& aPtr
) {
457 return aPtr
.get_address();
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.,
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>|.
481 explicit RefPtrGetterAddRefs(RefPtr
<T
>& aSmartPtr
)
482 : mTargetSmartPtr(aSmartPtr
) {
483 // nothing else to do
487 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
490 operator T
**() { return mTargetSmartPtr
.StartAssignment(); }
492 T
*& operator*() { return *(mTargetSmartPtr
.StartAssignment()); }
495 RefPtr
<T
>& mTargetSmartPtr
;
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|
565 inline bool operator==(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
566 return aLhs
.get() == nullptr;
570 inline bool operator==(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
571 return nullptr == aRhs
.get();
575 inline bool operator!=(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
576 return aLhs
.get() != nullptr;
580 inline bool operator!=(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
581 return nullptr != aRhs
.get();
587 std::ostream
& operator<<(std::ostream
& aOut
, const RefPtr
<T
>& aObj
) {
588 return mozilla::DebugValue(aOut
, aObj
.get());
591 /*****************************************************************************/
594 inline already_AddRefed
<T
> do_AddRef(T
* aObj
) {
600 inline already_AddRefed
<T
> do_AddRef(const RefPtr
<T
>& aObj
) {
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
>> {
615 static const size_t alignment
= alignof(T
*);
619 * Helper function to be able to conveniently write things like:
621 * already_AddRefed<T>
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
)...));
634 * Helper function to be able to conveniently write things like:
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
)...));
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 */