summaryrefslogtreecommitdiffstats
path: root/mfbt/RefPtr.h
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/RefPtr.h')
-rw-r--r--mfbt/RefPtr.h646
1 files changed, 646 insertions, 0 deletions
diff --git a/mfbt/RefPtr.h b/mfbt/RefPtr.h
new file mode 100644
index 0000000000..343e78d61e
--- /dev/null
+++ b/mfbt/RefPtr.h
@@ -0,0 +1,646 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_RefPtr_h
+#define mozilla_RefPtr_h
+
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/DbgMacro.h"
+
+#include <type_traits>
+
+/*****************************************************************************/
+
+// template <class T> class RefPtrGetterAddRefs;
+
+class nsQueryReferent;
+class nsCOMPtr_helper;
+class nsISupports;
+
+namespace mozilla {
+template <class T>
+class MovingNotNull;
+template <class T>
+class NotNull;
+template <class T>
+class OwningNonNull;
+template <class T>
+class StaticLocalRefPtr;
+template <class T>
+class StaticRefPtr;
+
+// Traditionally, RefPtr supports automatic refcounting of any pointer type
+// with AddRef() and Release() methods that follow the traditional semantics.
+//
+// This traits class can be specialized to operate on other pointer types. For
+// example, we specialize this trait for opaque FFI types that represent
+// refcounted objects in Rust.
+//
+// Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
+// qualified type.
+template <class U>
+struct RefPtrTraits {
+ static void AddRef(U* aPtr) { aPtr->AddRef(); }
+ static void Release(U* aPtr) { aPtr->Release(); }
+};
+
+} // namespace mozilla
+
+template <class T>
+class MOZ_IS_REFPTR RefPtr {
+ private:
+ void assign_with_AddRef(T* aRawPtr) {
+ if (aRawPtr) {
+ ConstRemovingRefPtrTraits<T>::AddRef(aRawPtr);
+ }
+ assign_assuming_AddRef(aRawPtr);
+ }
+
+ void assign_assuming_AddRef(T* aNewPtr) {
+ T* oldPtr = mRawPtr;
+ mRawPtr = aNewPtr;
+ if (oldPtr) {
+ ConstRemovingRefPtrTraits<T>::Release(oldPtr);
+ }
+ }
+
+ private:
+ T* MOZ_OWNING_REF mRawPtr;
+
+ public:
+ typedef T element_type;
+
+ ~RefPtr() {
+ if (mRawPtr) {
+ ConstRemovingRefPtrTraits<T>::Release(mRawPtr);
+ }
+ }
+
+ // Constructors
+
+ RefPtr()
+ : mRawPtr(nullptr)
+ // default constructor
+ {}
+
+ RefPtr(const RefPtr<T>& aSmartPtr)
+ : mRawPtr(aSmartPtr.mRawPtr)
+ // copy-constructor
+ {
+ if (mRawPtr) {
+ ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
+ }
+ }
+
+ RefPtr(RefPtr<T>&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) {
+ aRefPtr.mRawPtr = nullptr;
+ }
+
+ // construct from a raw pointer (of the right type)
+
+ MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) {
+ if (mRawPtr) {
+ ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
+ }
+ }
+
+ MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {}
+
+ template <typename I,
+ typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
+ MOZ_IMPLICIT RefPtr(already_AddRefed<I>& aSmartPtr)
+ : mRawPtr(aSmartPtr.take())
+ // construct from |already_AddRefed|
+ {}
+
+ template <typename I,
+ typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
+ MOZ_IMPLICIT RefPtr(already_AddRefed<I>&& aSmartPtr)
+ : mRawPtr(aSmartPtr.take())
+ // construct from |otherRefPtr.forget()|
+ {}
+
+ template <typename I,
+ typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
+ MOZ_IMPLICIT RefPtr(const RefPtr<I>& aSmartPtr)
+ : mRawPtr(aSmartPtr.get())
+ // copy-construct from a smart pointer with a related pointer type
+ {
+ if (mRawPtr) {
+ ConstRemovingRefPtrTraits<T>::AddRef(mRawPtr);
+ }
+ }
+
+ template <typename I,
+ typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
+ MOZ_IMPLICIT RefPtr(RefPtr<I>&& aSmartPtr)
+ : mRawPtr(aSmartPtr.forget().take())
+ // construct from |Move(RefPtr<SomeSubclassOfT>)|.
+ {}
+
+ template <typename I,
+ typename = std::enable_if_t<!std::is_same_v<I, RefPtr<T>> &&
+ std::is_convertible_v<I, RefPtr<T>>>>
+ MOZ_IMPLICIT RefPtr(const mozilla::NotNull<I>& aSmartPtr)
+ : mRawPtr(RefPtr<T>(aSmartPtr.get()).forget().take())
+ // construct from |mozilla::NotNull|.
+ {}
+
+ template <typename I,
+ typename = std::enable_if_t<!std::is_same_v<I, RefPtr<T>> &&
+ std::is_convertible_v<I, RefPtr<T>>>>
+ MOZ_IMPLICIT RefPtr(mozilla::MovingNotNull<I>&& aSmartPtr)
+ : mRawPtr(RefPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take())
+ // construct from |mozilla::MovingNotNull|.
+ {}
+
+ MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper);
+ MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper);
+
+ // Defined in OwningNonNull.h
+ template <class U>
+ MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
+
+ // Defined in StaticLocalPtr.h
+ template <class U>
+ MOZ_IMPLICIT RefPtr(const mozilla::StaticLocalRefPtr<U>& aOther);
+
+ // Defined in StaticPtr.h
+ template <class U>
+ MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
+
+ // Assignment operators
+
+ RefPtr<T>& operator=(decltype(nullptr)) {
+ assign_assuming_AddRef(nullptr);
+ return *this;
+ }
+
+ RefPtr<T>& operator=(const RefPtr<T>& aRhs)
+ // copy assignment operator
+ {
+ assign_with_AddRef(aRhs.mRawPtr);
+ return *this;
+ }
+
+ template <typename I>
+ RefPtr<T>& operator=(const RefPtr<I>& aRhs)
+ // assign from an RefPtr of a related pointer type
+ {
+ assign_with_AddRef(aRhs.get());
+ return *this;
+ }
+
+ RefPtr<T>& operator=(T* aRhs)
+ // assign from a raw pointer (of the right type)
+ {
+ assign_with_AddRef(aRhs);
+ return *this;
+ }
+
+ template <typename I>
+ RefPtr<T>& operator=(already_AddRefed<I>& aRhs)
+ // assign from |already_AddRefed|
+ {
+ assign_assuming_AddRef(aRhs.take());
+ return *this;
+ }
+
+ template <typename I>
+ RefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
+ // assign from |otherRefPtr.forget()|
+ {
+ assign_assuming_AddRef(aRhs.take());
+ return *this;
+ }
+
+ RefPtr<T>& operator=(const nsQueryReferent& aQueryReferent);
+ RefPtr<T>& operator=(const nsCOMPtr_helper& aHelper);
+
+ template <typename I,
+ typename = std::enable_if_t<std::is_convertible_v<I*, T*>>>
+ RefPtr<T>& operator=(RefPtr<I>&& aRefPtr) {
+ assign_assuming_AddRef(aRefPtr.forget().take());
+ return *this;
+ }
+
+ template <typename I,
+ typename = std::enable_if_t<std::is_convertible_v<I, RefPtr<T>>>>
+ RefPtr<T>& operator=(const mozilla::NotNull<I>& aSmartPtr)
+ // assign from |mozilla::NotNull|.
+ {
+ assign_assuming_AddRef(RefPtr<T>(aSmartPtr.get()).forget().take());
+ return *this;
+ }
+
+ template <typename I,
+ typename = std::enable_if_t<std::is_convertible_v<I, RefPtr<T>>>>
+ RefPtr<T>& operator=(mozilla::MovingNotNull<I>&& aSmartPtr)
+ // assign from |mozilla::MovingNotNull|.
+ {
+ assign_assuming_AddRef(
+ RefPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take());
+ return *this;
+ }
+
+ // Defined in OwningNonNull.h
+ template <class U>
+ RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
+
+ // Defined in StaticLocalPtr.h
+ template <class U>
+ RefPtr<T>& operator=(const mozilla::StaticLocalRefPtr<U>& aOther);
+
+ // Defined in StaticPtr.h
+ template <class U>
+ RefPtr<T>& operator=(const mozilla::StaticRefPtr<U>& aOther);
+
+ // Other pointer operators
+
+ void swap(RefPtr<T>& aRhs)
+ // ...exchange ownership with |aRhs|; can save a pair of refcount operations
+ {
+ T* temp = aRhs.mRawPtr;
+ aRhs.mRawPtr = mRawPtr;
+ mRawPtr = temp;
+ }
+
+ void swap(T*& aRhs)
+ // ...exchange ownership with |aRhs|; can save a pair of refcount operations
+ {
+ T* temp = aRhs;
+ aRhs = mRawPtr;
+ mRawPtr = temp;
+ }
+
+ already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget()
+ // return the value of mRawPtr and null out mRawPtr. Useful for
+ // already_AddRefed return values.
+ {
+ T* temp = nullptr;
+ swap(temp);
+ return already_AddRefed<T>(temp);
+ }
+
+ template <typename I>
+ void forget(I** aRhs)
+ // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
+ // Useful to avoid unnecessary AddRef/Release pairs with "out"
+ // parameters where aRhs bay be a T** or an I** where I is a base class
+ // of T.
+ {
+ MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
+ *aRhs = mRawPtr;
+ mRawPtr = nullptr;
+ }
+
+ void forget(nsISupports** aRhs) {
+ MOZ_ASSERT(aRhs, "Null pointer passed to forget!");
+ *aRhs = ToSupports(mRawPtr);
+ mRawPtr = nullptr;
+ }
+
+ T* get() const
+ /*
+ Prefer the implicit conversion provided automatically by |operator T*()
+ const|. Use |get()| to resolve ambiguity or to get a castable pointer.
+ */
+ {
+ return const_cast<T*>(mRawPtr);
+ }
+
+ operator T*() const&
+ /*
+ ...makes an |RefPtr| act like its underlying raw pointer type whenever it
+ is used in a context where a raw pointer is expected. It is this operator
+ that makes an |RefPtr| substitutable for a raw pointer.
+
+ Prefer the implicit use of this operator to calling |get()|, except where
+ necessary to resolve ambiguity.
+ */
+ {
+ return get();
+ }
+
+ // Don't allow implicit conversion of temporary RefPtr to raw pointer,
+ // because the refcount might be one and the pointer will immediately become
+ // invalid.
+ operator T*() const&& = delete;
+
+ // These are needed to avoid the deleted operator above. XXX Why is operator!
+ // needed separately? Shouldn't the compiler prefer using the non-deleted
+ // operator bool instead of the deleted operator T*?
+ explicit operator bool() const { return !!mRawPtr; }
+ bool operator!() const { return !mRawPtr; }
+
+ T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
+ MOZ_ASSERT(mRawPtr != nullptr,
+ "You can't dereference a NULL RefPtr with operator->().");
+ return get();
+ }
+
+ template <typename R, typename... Args>
+ class Proxy {
+ typedef R (T::*member_function)(Args...);
+ T* mRawPtr;
+ member_function mFunction;
+
+ public:
+ Proxy(T* aRawPtr, member_function aFunction)
+ : mRawPtr(aRawPtr), mFunction(aFunction) {}
+ template <typename... ActualArgs>
+ R operator()(ActualArgs&&... aArgs) {
+ return ((*mRawPtr).*mFunction)(std::forward<ActualArgs>(aArgs)...);
+ }
+ };
+
+ template <typename R, typename... Args>
+ Proxy<R, Args...> operator->*(R (T::*aFptr)(Args...)) const {
+ MOZ_ASSERT(mRawPtr != nullptr,
+ "You can't dereference a NULL RefPtr with operator->*().");
+ return Proxy<R, Args...>(get(), aFptr);
+ }
+
+ RefPtr<T>* get_address()
+ // This is not intended to be used by clients. See |address_of|
+ // below.
+ {
+ return this;
+ }
+
+ const RefPtr<T>* get_address() const
+ // This is not intended to be used by clients. See |address_of|
+ // below.
+ {
+ return this;
+ }
+
+ public:
+ T& operator*() const {
+ MOZ_ASSERT(mRawPtr != nullptr,
+ "You can't dereference a NULL RefPtr with operator*().");
+ return *get();
+ }
+
+ T** StartAssignment() {
+ assign_assuming_AddRef(nullptr);
+ return reinterpret_cast<T**>(&mRawPtr);
+ }
+
+ private:
+ // This helper class makes |RefPtr<const T>| possible by casting away
+ // the constness from the pointer when calling AddRef() and Release().
+ //
+ // This is necessary because AddRef() and Release() implementations can't
+ // generally expected to be const themselves (without heavy use of |mutable|
+ // and |const_cast| in their own implementations).
+ //
+ // This should be sound because while |RefPtr<const T>| provides a
+ // const view of an object, the object itself should not be const (it
+ // would have to be allocated as |new const T| or similar to be const).
+ template <class U>
+ struct ConstRemovingRefPtrTraits {
+ static void AddRef(U* aPtr) { mozilla::RefPtrTraits<U>::AddRef(aPtr); }
+ static void Release(U* aPtr) { mozilla::RefPtrTraits<U>::Release(aPtr); }
+ };
+ template <class U>
+ struct ConstRemovingRefPtrTraits<const U> {
+ static void AddRef(const U* aPtr) {
+ mozilla::RefPtrTraits<U>::AddRef(const_cast<U*>(aPtr));
+ }
+ static void Release(const U* aPtr) {
+ mozilla::RefPtrTraits<U>::Release(const_cast<U*>(aPtr));
+ }
+ };
+};
+
+class nsCycleCollectionTraversalCallback;
+template <typename T>
+void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback,
+ T* aChild, const char* aName, uint32_t aFlags);
+
+template <typename T>
+inline void ImplCycleCollectionUnlink(RefPtr<T>& aField) {
+ aField = nullptr;
+}
+
+template <typename T>
+inline void ImplCycleCollectionTraverse(
+ nsCycleCollectionTraversalCallback& aCallback, RefPtr<T>& aField,
+ const char* aName, uint32_t aFlags = 0) {
+ CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
+}
+
+template <class T>
+inline RefPtr<T>* address_of(RefPtr<T>& aPtr) {
+ return aPtr.get_address();
+}
+
+template <class T>
+inline const RefPtr<T>* address_of(const RefPtr<T>& aPtr) {
+ return aPtr.get_address();
+}
+
+template <class T>
+class RefPtrGetterAddRefs
+/*
+ ...
+
+ This class is designed to be used for anonymous temporary objects in the
+ argument list of calls that return COM interface pointers, e.g.,
+
+ RefPtr<IFoo> fooP;
+ ...->GetAddRefedPointer(getter_AddRefs(fooP))
+
+ DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
+
+ When initialized with a |RefPtr|, as in the example above, it returns
+ a |void**|, a |T**|, or an |nsISupports**| as needed, that the
+ outer call (|GetAddRefedPointer| in this case) can fill in.
+
+ This type should be a nested class inside |RefPtr<T>|.
+*/
+{
+ public:
+ explicit RefPtrGetterAddRefs(RefPtr<T>& aSmartPtr)
+ : mTargetSmartPtr(aSmartPtr) {
+ // nothing else to do
+ }
+
+ operator void**() {
+ return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
+ }
+
+ operator T**() { return mTargetSmartPtr.StartAssignment(); }
+
+ T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
+
+ private:
+ RefPtr<T>& mTargetSmartPtr;
+};
+
+template <class T>
+inline RefPtrGetterAddRefs<T> getter_AddRefs(RefPtr<T>& aSmartPtr)
+/*
+ Used around a |RefPtr| when
+ ...makes the class |RefPtrGetterAddRefs<T>| invisible.
+*/
+{
+ return RefPtrGetterAddRefs<T>(aSmartPtr);
+}
+
+// Comparing two |RefPtr|s
+
+template <class T, class U>
+inline bool operator==(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
+ return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
+}
+
+template <class T, class U>
+inline bool operator!=(const RefPtr<T>& aLhs, const RefPtr<U>& aRhs) {
+ return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
+}
+
+// Comparing an |RefPtr| to a raw pointer
+
+template <class T, class U>
+inline bool operator==(const RefPtr<T>& aLhs, const U* aRhs) {
+ return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs);
+}
+
+template <class T, class U>
+inline bool operator==(const U* aLhs, const RefPtr<T>& aRhs) {
+ return static_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
+}
+
+template <class T, class U>
+inline bool operator!=(const RefPtr<T>& aLhs, const U* aRhs) {
+ return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs);
+}
+
+template <class T, class U>
+inline bool operator!=(const U* aLhs, const RefPtr<T>& aRhs) {
+ return static_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
+}
+
+template <class T, class U>
+inline bool operator==(const RefPtr<T>& aLhs, U* aRhs) {
+ return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
+}
+
+template <class T, class U>
+inline bool operator==(U* aLhs, const RefPtr<T>& aRhs) {
+ return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
+}
+
+template <class T, class U>
+inline bool operator!=(const RefPtr<T>& aLhs, U* aRhs) {
+ return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
+}
+
+template <class T, class U>
+inline bool operator!=(U* aLhs, const RefPtr<T>& aRhs) {
+ return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
+}
+
+// Comparing an |RefPtr| to |nullptr|
+
+template <class T>
+inline bool operator==(const RefPtr<T>& aLhs, decltype(nullptr)) {
+ return aLhs.get() == nullptr;
+}
+
+template <class T>
+inline bool operator==(decltype(nullptr), const RefPtr<T>& aRhs) {
+ return nullptr == aRhs.get();
+}
+
+template <class T>
+inline bool operator!=(const RefPtr<T>& aLhs, decltype(nullptr)) {
+ return aLhs.get() != nullptr;
+}
+
+template <class T>
+inline bool operator!=(decltype(nullptr), const RefPtr<T>& aRhs) {
+ return nullptr != aRhs.get();
+}
+
+// MOZ_DBG support
+
+template <class T>
+std::ostream& operator<<(std::ostream& aOut, const RefPtr<T>& aObj) {
+ return mozilla::DebugValue(aOut, aObj.get());
+}
+
+/*****************************************************************************/
+
+template <class T>
+inline already_AddRefed<T> do_AddRef(T* aObj) {
+ RefPtr<T> ref(aObj);
+ return ref.forget();
+}
+
+template <class T>
+inline already_AddRefed<T> do_AddRef(const RefPtr<T>& aObj) {
+ RefPtr<T> ref(aObj);
+ return ref.forget();
+}
+
+namespace mozilla {
+
+template <typename T>
+class AlignmentFinder;
+
+// Provide a specialization of AlignmentFinder to allow MOZ_ALIGNOF(RefPtr<T>)
+// with an incomplete T.
+template <typename T>
+class AlignmentFinder<RefPtr<T>> {
+ public:
+ static const size_t alignment = alignof(T*);
+};
+
+/**
+ * Helper function to be able to conveniently write things like:
+ *
+ * already_AddRefed<T>
+ * f(...)
+ * {
+ * return MakeAndAddRef<T>(...);
+ * }
+ */
+template <typename T, typename... Args>
+already_AddRefed<T> MakeAndAddRef(Args&&... aArgs) {
+ RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
+ return p.forget();
+}
+
+/**
+ * Helper function to be able to conveniently write things like:
+ *
+ * auto runnable =
+ * MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
+ * mOnSuccess, mOnFailure, *error, mWindowID);
+ */
+template <typename T, typename... Args>
+RefPtr<T> MakeRefPtr(Args&&... aArgs) {
+ RefPtr<T> p(new T(std::forward<Args>(aArgs)...));
+ return p;
+}
+
+} // namespace mozilla
+
+/**
+ * Deduction guide to allow simple `RefPtr` definitions from an
+ * already_AddRefed<T> without repeating the type, e.g.:
+ *
+ * RefPtr ptr = MakeAndAddRef<SomeType>(...);
+ */
+template <typename T>
+RefPtr(already_AddRefed<T>) -> RefPtr<T>;
+
+#endif /* mozilla_RefPtr_h */