Bug 1610775 [wpt PR 21336] - Update urllib3 to 1.25.8, a=testonly
[gecko.git] / mfbt / RefPtr.h
blob5cb732c576e79a4f2ffc35a91a27ab9b7e0ceb43
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;
23 class nsISupports;
25 namespace mozilla {
26 template <class T>
27 class OwningNonNull;
28 template <class T>
29 class StaticLocalRefPtr;
30 template <class T>
31 class StaticRefPtr;
32 #if defined(XP_WIN)
33 namespace mscom {
34 class AgileReference;
35 } // namespace mscom
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-
46 // qualified type.
47 template <class U>
48 struct RefPtrTraits {
49 static void AddRef(U* aPtr) { aPtr->AddRef(); }
50 static void Release(U* aPtr) { aPtr->Release(); }
53 } // namespace mozilla
55 template <class T>
56 class MOZ_IS_REFPTR RefPtr {
57 private:
58 void assign_with_AddRef(T* aRawPtr) {
59 if (aRawPtr) {
60 ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
62 assign_assuming_AddRef(aRawPtr);
65 void assign_assuming_AddRef(T* aNewPtr) {
66 T* oldPtr = mRawPtr;
67 mRawPtr = aNewPtr;
68 if (oldPtr) {
69 ConstRemovingRefPtrTraits<T>::Release(oldPtr);
73 private:
74 T* MOZ_OWNING_REF mRawPtr;
76 public:
77 typedef T element_type;
79 ~RefPtr() {
80 if (mRawPtr) {
81 ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
85 // Constructors
87 RefPtr()
88 : mRawPtr(nullptr)
89 // 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) : 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) {
108 if (mRawPtr) {
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
135 if (mRawPtr) {
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);
149 #if defined(XP_WIN)
150 MOZ_IMPLICIT RefPtr(const mozilla::mscom::AgileReference& aAgileRef);
151 #endif // defined(XP_WIN)
153 // Defined in OwningNonNull.h
154 template <class U>
155 MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
157 // Defined in StaticLocalPtr.h
158 template <class U>
159 MOZ_IMPLICIT RefPtr(const mozilla::StaticLocalRefPtr<U>& aOther);
161 // Defined in StaticPtr.h
162 template <class U>
163 MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
165 // Assignment operators
167 RefPtr<T>& operator=(decltype(nullptr)) {
168 assign_assuming_AddRef(nullptr);
169 return *this;
172 RefPtr<T>& operator=(const RefPtr<T>& aRhs)
173 // copy assignment operator
175 assign_with_AddRef(aRhs.mRawPtr);
176 return *this;
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());
184 return *this;
187 RefPtr<T>& operator=(T* aRhs)
188 // assign from a raw pointer (of the right type)
190 assign_with_AddRef(aRhs);
191 return *this;
194 template <typename I>
195 RefPtr<T>& operator=(already_AddRefed<I>& aRhs)
196 // assign from |already_AddRefed|
198 assign_assuming_AddRef(aRhs.take());
199 return *this;
202 template <typename I>
203 RefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
204 // assign from |otherRefPtr.forget()|
206 assign_assuming_AddRef(aRhs.take());
207 return *this;
210 RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent);
211 RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
212 #if defined(XP_WIN)
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());
218 return *this;
221 // Defined in OwningNonNull.h
222 template <class U>
223 RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
225 // Defined in StaticLocalPtr.h
226 template <class U>
227 RefPtr<T>& operator=(const mozilla::StaticLocalRefPtr<U>& aOther);
229 // Defined in StaticPtr.h
230 template <class U>
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;
240 mRawPtr = temp;
243 void swap(T*& aRhs)
244 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
246 T* temp = aRhs;
247 aRhs = mRawPtr;
248 mRawPtr = temp;
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.
255 T* temp = nullptr;
256 swap(temp);
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
265 // of T.
267 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
268 *aRhs = mRawPtr;
269 mRawPtr = nullptr;
272 void forget(nsISupports** aRhs) {
273 MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
274 *aRhs = ToSupports(mRawPtr);
275 mRawPtr = nullptr;
278 T* get() const
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);
287 operator T*() const&
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.
297 return get();
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
302 // invalid.
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->().");
314 return get();
317 template <typename R, typename... Args>
318 class Proxy {
319 typedef R (T::*member_function)(Args...);
320 T* mRawPtr;
321 member_function mFunction;
323 public:
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|
341 // below.
343 return this;
346 const RefPtr<T>* get_address() const
347 // This is not intended to be used by clients. See |address_of|
348 // below.
350 return this;
353 public:
354 T& operator*() const {
355 MOZ_ASSERT(mRawPtr != nullptr,
356 "You can't dereference a NULL RefPtr with operator*().");
357 return *get();
360 T** StartAssignment() {
361 assign_assuming_AddRef(nullptr);
362 return reinterpret_cast<T**>(&mRawPtr);
365 private:
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).
376 template <class U>
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); }
381 template <class U>
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) {
399 aField = nullptr;
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);
409 template <class T>
410 inline RefPtr<T>* address_of(RefPtr<T>& aPtr) {
411 return aPtr.get_address();
414 template <class T>
415 inline const RefPtr<T>* address_of(const RefPtr<T>& aPtr) {
416 return aPtr.get_address();
419 template <class T>
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.,
427 RefPtr<IFoo> fooP;
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>|.
439 public:
440 explicit RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
441 : mTargetSmartPtr(aSmartPtr) {
442 // nothing else to do
445 operator void**() {
446 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
449 operator T**() { return mTargetSmartPtr.StartAssignment(); }
451 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
453 private:
454 RefPtr<T>& mTargetSmartPtr;
457 template <class T>
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|
523 template <class T>
524 inline bool operator==(const RefPtr<T>& aLhs, decltype(nullptr)) {
525 return aLhs.get() == nullptr;
528 template <class T>
529 inline bool operator==(decltype(nullptr), const RefPtr<T>& aRhs) {
530 return nullptr == aRhs.get();
533 template <class T>
534 inline bool operator!=(const RefPtr<T>& aLhs, decltype(nullptr)) {
535 return aLhs.get() != nullptr;
538 template <class T>
539 inline bool operator!=(decltype(nullptr), const RefPtr<T>& aRhs) {
540 return nullptr != aRhs.get();
543 // MOZ_DBG support
545 template <class T>
546 std::ostream& operator<<(std::ostream& aOut, const RefPtr<T>& aObj) {
547 return mozilla::DebugValue(aOut, aObj.get());
550 /*****************************************************************************/
552 template <class T>
553 inline already_AddRefed<T> do_AddRef(T* aObj) {
554 RefPtr<T> ref(aObj);
555 return ref.forget();
558 template <class T>
559 inline already_AddRefed<T> do_AddRef(const RefPtr<T>& aObj) {
560 RefPtr<T> ref(aObj);
561 return ref.forget();
564 namespace mozilla {
567 * Helper function to be able to conveniently write things like:
569 * already_AddRefed<T>
570 * f(...)
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)...));
578 return p.forget();
582 * Helper function to be able to conveniently write things like:
584 * auto runnable =
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)...));
591 return p;
594 } // namespace mozilla
596 #endif /* mozilla_RefPtr_h */