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
;
29 class StaticLocalRefPtr
;
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-
49 static void AddRef(U
* aPtr
) { aPtr
->AddRef(); }
50 static void Release(U
* aPtr
) { aPtr
->Release(); }
53 } // namespace mozilla
56 class MOZ_IS_REFPTR RefPtr
{
58 void assign_with_AddRef(T
* aRawPtr
) {
60 ConstRemovingRefPtrTraits
<T
>::AddRef(aRawPtr
);
62 assign_assuming_AddRef(aRawPtr
);
65 void assign_assuming_AddRef(T
* aNewPtr
) {
69 ConstRemovingRefPtrTraits
<T
>::Release(oldPtr
);
74 T
* MOZ_OWNING_REF mRawPtr
;
77 typedef T element_type
;
81 ConstRemovingRefPtrTraits
<T
>::Release(mRawPtr
);
89 // default constructor
92 RefPtr(const RefPtr
<T
>& aSmartPtr
)
93 : mRawPtr(aSmartPtr
.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
) {
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
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
);
150 MOZ_IMPLICIT
RefPtr(const mozilla::mscom::AgileReference
& aAgileRef
);
151 #endif // defined(XP_WIN)
153 // Defined in OwningNonNull.h
155 MOZ_IMPLICIT
RefPtr(const mozilla::OwningNonNull
<U
>& aOther
);
157 // Defined in StaticLocalPtr.h
159 MOZ_IMPLICIT
RefPtr(const mozilla::StaticLocalRefPtr
<U
>& aOther
);
161 // Defined in StaticPtr.h
163 MOZ_IMPLICIT
RefPtr(const mozilla::StaticRefPtr
<U
>& aOther
);
165 // Assignment operators
167 RefPtr
<T
>& operator=(decltype(nullptr)) {
168 assign_assuming_AddRef(nullptr);
172 RefPtr
<T
>& operator=(const RefPtr
<T
>& aRhs
)
173 // copy assignment operator
175 assign_with_AddRef(aRhs
.mRawPtr
);
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());
187 RefPtr
<T
>& operator=(T
* aRhs
)
188 // assign from a raw pointer (of the right type)
190 assign_with_AddRef(aRhs
);
194 template <typename I
>
195 RefPtr
<T
>& operator=(already_AddRefed
<I
>& aRhs
)
196 // assign from |already_AddRefed|
198 assign_assuming_AddRef(aRhs
.take());
202 template <typename I
>
203 RefPtr
<T
>& operator=(already_AddRefed
<I
>&& aRhs
)
204 // assign from |otherRefPtr.forget()|
206 assign_assuming_AddRef(aRhs
.take());
210 RefPtr
<T
>& operator=(const nsQueryReferent
& aQueryReferent
);
211 RefPtr
<T
>& operator=(const nsCOMPtr_helper
& aHelper
);
213 RefPtr
<T
>& operator=(const mozilla::mscom::AgileReference
& aAgileRef
);
214 #endif // defined(XP_WIN)
216 RefPtr
<T
>& operator=(RefPtr
<T
>&& aRefPtr
) {
217 assign_assuming_AddRef(aRefPtr
.forget().take());
221 // Defined in OwningNonNull.h
223 RefPtr
<T
>& operator=(const mozilla::OwningNonNull
<U
>& aOther
);
225 // Defined in StaticLocalPtr.h
227 RefPtr
<T
>& operator=(const mozilla::StaticLocalRefPtr
<U
>& aOther
);
229 // Defined in StaticPtr.h
231 RefPtr
<T
>& operator=(const mozilla::StaticRefPtr
<U
>& aOther
);
233 // Other pointer operators
235 void swap(RefPtr
<T
>& aRhs
)
236 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
238 T
* temp
= aRhs
.mRawPtr
;
239 aRhs
.mRawPtr
= mRawPtr
;
244 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
251 already_AddRefed
<T
> MOZ_MAY_CALL_AFTER_MUST_RETURN
forget()
252 // return the value of mRawPtr and null out mRawPtr. Useful for
253 // already_AddRefed return values.
257 return already_AddRefed
<T
>(temp
);
260 template <typename I
>
261 void forget(I
** aRhs
)
262 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
263 // Useful to avoid unnecessary AddRef/Release pairs with "out"
264 // parameters where aRhs bay be a T** or an I** where I is a base class
267 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
272 void forget(nsISupports
** aRhs
) {
273 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
274 *aRhs
= ToSupports(mRawPtr
);
280 Prefer the implicit conversion provided automatically by |operator T*()
281 const|. Use |get()| to resolve ambiguity or to get a castable pointer.
284 return const_cast<T
*>(mRawPtr
);
289 ...makes an |RefPtr| act like its underlying raw pointer type whenever it
290 is used in a context where a raw pointer is expected. It is this operator
291 that makes an |RefPtr| substitutable for a raw pointer.
293 Prefer the implicit use of this operator to calling |get()|, except where
294 necessary to resolve ambiguity.
300 // Don't allow implicit conversion of temporary RefPtr to raw pointer,
301 // because the refcount might be one and the pointer will immediately become
303 operator T
*() const&& = delete;
305 // These are needed to avoid the deleted operator above. XXX Why is operator!
306 // needed separately? Shouldn't the compiler prefer using the non-deleted
307 // operator bool instead of the deleted operator T*?
308 explicit operator bool() const { return !!mRawPtr
; }
309 bool operator!() const { return !mRawPtr
; }
311 T
* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
{
312 MOZ_ASSERT(mRawPtr
!= nullptr,
313 "You can't dereference a NULL RefPtr with operator->().");
317 template <typename R
, typename
... Args
>
319 typedef R (T::*member_function
)(Args
...);
321 member_function mFunction
;
324 Proxy(T
* aRawPtr
, member_function aFunction
)
325 : mRawPtr(aRawPtr
), mFunction(aFunction
) {}
326 template <typename
... ActualArgs
>
327 R
operator()(ActualArgs
&&... aArgs
) {
328 return ((*mRawPtr
).*mFunction
)(std::forward
<ActualArgs
>(aArgs
)...);
332 template <typename R
, typename
... Args
>
333 Proxy
<R
, Args
...> operator->*(R (T::*aFptr
)(Args
...)) const {
334 MOZ_ASSERT(mRawPtr
!= nullptr,
335 "You can't dereference a NULL RefPtr with operator->*().");
336 return Proxy
<R
, Args
...>(get(), aFptr
);
339 RefPtr
<T
>* get_address()
340 // This is not intended to be used by clients. See |address_of|
346 const RefPtr
<T
>* get_address() const
347 // This is not intended to be used by clients. See |address_of|
354 T
& operator*() const {
355 MOZ_ASSERT(mRawPtr
!= nullptr,
356 "You can't dereference a NULL RefPtr with operator*().");
360 T
** StartAssignment() {
361 assign_assuming_AddRef(nullptr);
362 return reinterpret_cast<T
**>(&mRawPtr
);
366 // This helper class makes |RefPtr<const T>| possible by casting away
367 // the constness from the pointer when calling AddRef() and Release().
369 // This is necessary because AddRef() and Release() implementations can't
370 // generally expected to be const themselves (without heavy use of |mutable|
371 // and |const_cast| in their own implementations).
373 // This should be sound because while |RefPtr<const T>| provides a
374 // const view of an object, the object itself should not be const (it
375 // would have to be allocated as |new const T| or similar to be const).
377 struct ConstRemovingRefPtrTraits
{
378 static void AddRef(U
* aPtr
) { mozilla::RefPtrTraits
<U
>::AddRef(aPtr
); }
379 static void Release(U
* aPtr
) { mozilla::RefPtrTraits
<U
>::Release(aPtr
); }
382 struct ConstRemovingRefPtrTraits
<const U
> {
383 static void AddRef(const U
* aPtr
) {
384 mozilla::RefPtrTraits
<U
>::AddRef(const_cast<U
*>(aPtr
));
386 static void Release(const U
* aPtr
) {
387 mozilla::RefPtrTraits
<U
>::Release(const_cast<U
*>(aPtr
));
392 class nsCycleCollectionTraversalCallback
;
393 template <typename T
>
394 void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback
& aCallback
,
395 T
* aChild
, const char* aName
, uint32_t aFlags
);
397 template <typename T
>
398 inline void ImplCycleCollectionUnlink(RefPtr
<T
>& aField
) {
402 template <typename T
>
403 inline void ImplCycleCollectionTraverse(
404 nsCycleCollectionTraversalCallback
& aCallback
, RefPtr
<T
>& aField
,
405 const char* aName
, uint32_t aFlags
= 0) {
406 CycleCollectionNoteChild(aCallback
, aField
.get(), aName
, aFlags
);
410 inline RefPtr
<T
>* address_of(RefPtr
<T
>& aPtr
) {
411 return aPtr
.get_address();
415 inline const RefPtr
<T
>* address_of(const RefPtr
<T
>& aPtr
) {
416 return aPtr
.get_address();
420 class RefPtrGetterAddRefs
424 This class is designed to be used for anonymous temporary objects in the
425 argument list of calls that return COM interface pointers, e.g.,
428 ...->GetAddRefedPointer(getter_AddRefs(fooP))
430 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
432 When initialized with a |RefPtr|, as in the example above, it returns
433 a |void**|, a |T**|, or an |nsISupports**| as needed, that the
434 outer call (|GetAddRefedPointer| in this case) can fill in.
436 This type should be a nested class inside |RefPtr<T>|.
440 explicit RefPtrGetterAddRefs(RefPtr
<T
>& aSmartPtr
)
441 : mTargetSmartPtr(aSmartPtr
) {
442 // nothing else to do
446 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
449 operator T
**() { return mTargetSmartPtr
.StartAssignment(); }
451 T
*& operator*() { return *(mTargetSmartPtr
.StartAssignment()); }
454 RefPtr
<T
>& mTargetSmartPtr
;
458 inline RefPtrGetterAddRefs
<T
> getter_AddRefs(RefPtr
<T
>& aSmartPtr
)
460 Used around a |RefPtr| when
461 ...makes the class |RefPtrGetterAddRefs<T>| invisible.
464 return RefPtrGetterAddRefs
<T
>(aSmartPtr
);
467 // Comparing two |RefPtr|s
469 template <class T
, class U
>
470 inline bool operator==(const RefPtr
<T
>& aLhs
, const RefPtr
<U
>& aRhs
) {
471 return static_cast<const T
*>(aLhs
.get()) == static_cast<const U
*>(aRhs
.get());
474 template <class T
, class U
>
475 inline bool operator!=(const RefPtr
<T
>& aLhs
, const RefPtr
<U
>& aRhs
) {
476 return static_cast<const T
*>(aLhs
.get()) != static_cast<const U
*>(aRhs
.get());
479 // Comparing an |RefPtr| to a raw pointer
481 template <class T
, class U
>
482 inline bool operator==(const RefPtr
<T
>& aLhs
, const U
* aRhs
) {
483 return static_cast<const T
*>(aLhs
.get()) == static_cast<const U
*>(aRhs
);
486 template <class T
, class U
>
487 inline bool operator==(const U
* aLhs
, const RefPtr
<T
>& aRhs
) {
488 return static_cast<const U
*>(aLhs
) == static_cast<const T
*>(aRhs
.get());
491 template <class T
, class U
>
492 inline bool operator!=(const RefPtr
<T
>& aLhs
, const U
* aRhs
) {
493 return static_cast<const T
*>(aLhs
.get()) != static_cast<const U
*>(aRhs
);
496 template <class T
, class U
>
497 inline bool operator!=(const U
* aLhs
, const RefPtr
<T
>& aRhs
) {
498 return static_cast<const U
*>(aLhs
) != static_cast<const T
*>(aRhs
.get());
501 template <class T
, class U
>
502 inline bool operator==(const RefPtr
<T
>& aLhs
, U
* aRhs
) {
503 return static_cast<const T
*>(aLhs
.get()) == const_cast<const U
*>(aRhs
);
506 template <class T
, class U
>
507 inline bool operator==(U
* aLhs
, const RefPtr
<T
>& aRhs
) {
508 return const_cast<const U
*>(aLhs
) == static_cast<const T
*>(aRhs
.get());
511 template <class T
, class U
>
512 inline bool operator!=(const RefPtr
<T
>& aLhs
, U
* aRhs
) {
513 return static_cast<const T
*>(aLhs
.get()) != const_cast<const U
*>(aRhs
);
516 template <class T
, class U
>
517 inline bool operator!=(U
* aLhs
, const RefPtr
<T
>& aRhs
) {
518 return const_cast<const U
*>(aLhs
) != static_cast<const T
*>(aRhs
.get());
521 // Comparing an |RefPtr| to |nullptr|
524 inline bool operator==(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
525 return aLhs
.get() == nullptr;
529 inline bool operator==(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
530 return nullptr == aRhs
.get();
534 inline bool operator!=(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
535 return aLhs
.get() != nullptr;
539 inline bool operator!=(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
540 return nullptr != aRhs
.get();
546 std::ostream
& operator<<(std::ostream
& aOut
, const RefPtr
<T
>& aObj
) {
547 return mozilla::DebugValue(aOut
, aObj
.get());
550 /*****************************************************************************/
553 inline already_AddRefed
<T
> do_AddRef(T
* aObj
) {
559 inline already_AddRefed
<T
> do_AddRef(const RefPtr
<T
>& aObj
) {
567 * Helper function to be able to conveniently write things like:
569 * already_AddRefed<T>
572 * return MakeAndAddRef<T>(...);
575 template <typename T
, typename
... Args
>
576 already_AddRefed
<T
> MakeAndAddRef(Args
&&... aArgs
) {
577 RefPtr
<T
> p(new T(std::forward
<Args
>(aArgs
)...));
582 * Helper function to be able to conveniently write things like:
585 * MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
586 * mOnSuccess, mOnFailure, *error, mWindowID);
588 template <typename T
, typename
... Args
>
589 RefPtr
<T
> MakeRefPtr(Args
&&... aArgs
) {
590 RefPtr
<T
> p(new T(std::forward
<Args
>(aArgs
)...));
594 } // namespace mozilla
596 #endif /* mozilla_RefPtr_h */