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
;
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-
45 static void AddRef(U
* aPtr
) { aPtr
->AddRef(); }
46 static void Release(U
* aPtr
) { aPtr
->Release(); }
49 } // namespace mozilla
52 class MOZ_IS_REFPTR RefPtr
{
54 void assign_with_AddRef(T
* aRawPtr
) {
56 ConstRemovingRefPtrTraits
<T
>::AddRef(aRawPtr
);
58 assign_assuming_AddRef(aRawPtr
);
61 void assign_assuming_AddRef(T
* aNewPtr
) {
65 ConstRemovingRefPtrTraits
<T
>::Release(oldPtr
);
70 T
* MOZ_OWNING_REF mRawPtr
;
73 typedef T element_type
;
77 ConstRemovingRefPtrTraits
<T
>::Release(mRawPtr
);
85 // default constructor
88 RefPtr(const RefPtr
<T
>& aSmartPtr
)
89 : mRawPtr(aSmartPtr
.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
) {
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
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
);
142 MOZ_IMPLICIT
RefPtr(const mozilla::mscom::AgileReference
& aAgileRef
);
143 #endif // defined(XP_WIN)
145 // Defined in OwningNonNull.h
147 MOZ_IMPLICIT
RefPtr(const mozilla::OwningNonNull
<U
>& aOther
);
149 // Defined in StaticPtr.h
151 MOZ_IMPLICIT
RefPtr(const mozilla::StaticRefPtr
<U
>& aOther
);
153 // Assignment operators
155 RefPtr
<T
>& operator=(decltype(nullptr)) {
156 assign_assuming_AddRef(nullptr);
160 RefPtr
<T
>& operator=(const RefPtr
<T
>& aRhs
)
161 // copy assignment operator
163 assign_with_AddRef(aRhs
.mRawPtr
);
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());
175 RefPtr
<T
>& operator=(T
* aRhs
)
176 // assign from a raw pointer (of the right type)
178 assign_with_AddRef(aRhs
);
182 template <typename I
>
183 RefPtr
<T
>& operator=(already_AddRefed
<I
>& aRhs
)
184 // assign from |already_AddRefed|
186 assign_assuming_AddRef(aRhs
.take());
190 template <typename I
>
191 RefPtr
<T
>& operator=(already_AddRefed
<I
>&& aRhs
)
192 // assign from |otherRefPtr.forget()|
194 assign_assuming_AddRef(aRhs
.take());
198 RefPtr
<T
>& operator=(const nsQueryReferent
& aQueryReferent
);
199 RefPtr
<T
>& operator=(const nsCOMPtr_helper
& aHelper
);
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());
209 // Defined in OwningNonNull.h
211 RefPtr
<T
>& operator=(const mozilla::OwningNonNull
<U
>& aOther
);
213 // Defined in StaticPtr.h
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
;
228 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
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.
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
251 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
256 void forget(nsISupports
** aRhs
) {
257 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
258 *aRhs
= ToSupports(mRawPtr
);
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
);
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.
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
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->().");
301 template <typename R
, typename
... Args
>
303 typedef R (T::*member_function
)(Args
...);
305 member_function mFunction
;
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|
330 const RefPtr
<T
>* get_address() const
331 // This is not intended to be used by clients. See |address_of|
338 T
& operator*() const {
339 MOZ_ASSERT(mRawPtr
!= nullptr,
340 "You can't dereference a NULL RefPtr with operator*().");
344 T
** StartAssignment() {
345 assign_assuming_AddRef(nullptr);
346 return reinterpret_cast<T
**>(&mRawPtr
);
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).
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
); }
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
) {
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
);
394 inline RefPtr
<T
>* address_of(RefPtr
<T
>& aPtr
) {
395 return aPtr
.get_address();
399 inline const RefPtr
<T
>* address_of(const RefPtr
<T
>& aPtr
) {
400 return aPtr
.get_address();
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.,
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>|.
424 explicit RefPtrGetterAddRefs(RefPtr
<T
>& aSmartPtr
)
425 : mTargetSmartPtr(aSmartPtr
) {
426 // nothing else to do
430 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
433 operator T
**() { return mTargetSmartPtr
.StartAssignment(); }
435 T
*& operator*() { return *(mTargetSmartPtr
.StartAssignment()); }
438 RefPtr
<T
>& mTargetSmartPtr
;
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|
508 inline bool operator==(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
509 return aLhs
.get() == nullptr;
513 inline bool operator==(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
514 return nullptr == aRhs
.get();
518 inline bool operator!=(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
519 return aLhs
.get() != nullptr;
523 inline bool operator!=(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
524 return nullptr != aRhs
.get();
530 std::ostream
& operator<<(std::ostream
& aOut
, const RefPtr
<T
>& aObj
) {
531 return mozilla::DebugValue(aOut
, aObj
.get());
534 /*****************************************************************************/
537 inline already_AddRefed
<T
> do_AddRef(T
* aObj
) {
543 inline already_AddRefed
<T
> do_AddRef(const RefPtr
<T
>& aObj
) {
551 * Helper function to be able to conveniently write things like:
553 * already_AddRefed<T>
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
)...));
566 * Helper function to be able to conveniently write things like:
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
)...));
578 } // namespace mozilla
580 #endif /* mozilla_RefPtr_h */