From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- mfbt/RefPtr.h | 646 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 646 insertions(+) create mode 100644 mfbt/RefPtr.h (limited to 'mfbt/RefPtr.h') 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 + +/*****************************************************************************/ + +// template class RefPtrGetterAddRefs; + +class nsQueryReferent; +class nsCOMPtr_helper; +class nsISupports; + +namespace mozilla { +template +class MovingNotNull; +template +class NotNull; +template +class OwningNonNull; +template +class StaticLocalRefPtr; +template +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 +struct RefPtrTraits { + static void AddRef(U* aPtr) { aPtr->AddRef(); } + static void Release(U* aPtr) { aPtr->Release(); } +}; + +} // namespace mozilla + +template +class MOZ_IS_REFPTR RefPtr { + private: + void assign_with_AddRef(T* aRawPtr) { + if (aRawPtr) { + ConstRemovingRefPtrTraits::AddRef(aRawPtr); + } + assign_assuming_AddRef(aRawPtr); + } + + void assign_assuming_AddRef(T* aNewPtr) { + T* oldPtr = mRawPtr; + mRawPtr = aNewPtr; + if (oldPtr) { + ConstRemovingRefPtrTraits::Release(oldPtr); + } + } + + private: + T* MOZ_OWNING_REF mRawPtr; + + public: + typedef T element_type; + + ~RefPtr() { + if (mRawPtr) { + ConstRemovingRefPtrTraits::Release(mRawPtr); + } + } + + // Constructors + + RefPtr() + : mRawPtr(nullptr) + // default constructor + {} + + RefPtr(const RefPtr& aSmartPtr) + : mRawPtr(aSmartPtr.mRawPtr) + // copy-constructor + { + if (mRawPtr) { + ConstRemovingRefPtrTraits::AddRef(mRawPtr); + } + } + + RefPtr(RefPtr&& 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::AddRef(mRawPtr); + } + } + + MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {} + + template >> + MOZ_IMPLICIT RefPtr(already_AddRefed& aSmartPtr) + : mRawPtr(aSmartPtr.take()) + // construct from |already_AddRefed| + {} + + template >> + MOZ_IMPLICIT RefPtr(already_AddRefed&& aSmartPtr) + : mRawPtr(aSmartPtr.take()) + // construct from |otherRefPtr.forget()| + {} + + template >> + MOZ_IMPLICIT RefPtr(const RefPtr& aSmartPtr) + : mRawPtr(aSmartPtr.get()) + // copy-construct from a smart pointer with a related pointer type + { + if (mRawPtr) { + ConstRemovingRefPtrTraits::AddRef(mRawPtr); + } + } + + template >> + MOZ_IMPLICIT RefPtr(RefPtr&& aSmartPtr) + : mRawPtr(aSmartPtr.forget().take()) + // construct from |Move(RefPtr)|. + {} + + template > && + std::is_convertible_v>>> + MOZ_IMPLICIT RefPtr(const mozilla::NotNull& aSmartPtr) + : mRawPtr(RefPtr(aSmartPtr.get()).forget().take()) + // construct from |mozilla::NotNull|. + {} + + template > && + std::is_convertible_v>>> + MOZ_IMPLICIT RefPtr(mozilla::MovingNotNull&& aSmartPtr) + : mRawPtr(RefPtr(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 + MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull& aOther); + + // Defined in StaticLocalPtr.h + template + MOZ_IMPLICIT RefPtr(const mozilla::StaticLocalRefPtr& aOther); + + // Defined in StaticPtr.h + template + MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr& aOther); + + // Assignment operators + + RefPtr& operator=(decltype(nullptr)) { + assign_assuming_AddRef(nullptr); + return *this; + } + + RefPtr& operator=(const RefPtr& aRhs) + // copy assignment operator + { + assign_with_AddRef(aRhs.mRawPtr); + return *this; + } + + template + RefPtr& operator=(const RefPtr& aRhs) + // assign from an RefPtr of a related pointer type + { + assign_with_AddRef(aRhs.get()); + return *this; + } + + RefPtr& operator=(T* aRhs) + // assign from a raw pointer (of the right type) + { + assign_with_AddRef(aRhs); + return *this; + } + + template + RefPtr& operator=(already_AddRefed& aRhs) + // assign from |already_AddRefed| + { + assign_assuming_AddRef(aRhs.take()); + return *this; + } + + template + RefPtr& operator=(already_AddRefed&& aRhs) + // assign from |otherRefPtr.forget()| + { + assign_assuming_AddRef(aRhs.take()); + return *this; + } + + RefPtr& operator=(const nsQueryReferent& aQueryReferent); + RefPtr& operator=(const nsCOMPtr_helper& aHelper); + + template >> + RefPtr& operator=(RefPtr&& aRefPtr) { + assign_assuming_AddRef(aRefPtr.forget().take()); + return *this; + } + + template >>> + RefPtr& operator=(const mozilla::NotNull& aSmartPtr) + // assign from |mozilla::NotNull|. + { + assign_assuming_AddRef(RefPtr(aSmartPtr.get()).forget().take()); + return *this; + } + + template >>> + RefPtr& operator=(mozilla::MovingNotNull&& aSmartPtr) + // assign from |mozilla::MovingNotNull|. + { + assign_assuming_AddRef( + RefPtr(std::move(aSmartPtr).unwrapBasePtr()).forget().take()); + return *this; + } + + // Defined in OwningNonNull.h + template + RefPtr& operator=(const mozilla::OwningNonNull& aOther); + + // Defined in StaticLocalPtr.h + template + RefPtr& operator=(const mozilla::StaticLocalRefPtr& aOther); + + // Defined in StaticPtr.h + template + RefPtr& operator=(const mozilla::StaticRefPtr& aOther); + + // Other pointer operators + + void swap(RefPtr& 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 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(temp); + } + + template + 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(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 + 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 + R operator()(ActualArgs&&... aArgs) { + return ((*mRawPtr).*mFunction)(std::forward(aArgs)...); + } + }; + + template + Proxy operator->*(R (T::*aFptr)(Args...)) const { + MOZ_ASSERT(mRawPtr != nullptr, + "You can't dereference a NULL RefPtr with operator->*()."); + return Proxy(get(), aFptr); + } + + RefPtr* get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const RefPtr* 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(&mRawPtr); + } + + private: + // This helper class makes |RefPtr| 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| 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 + struct ConstRemovingRefPtrTraits { + static void AddRef(U* aPtr) { mozilla::RefPtrTraits::AddRef(aPtr); } + static void Release(U* aPtr) { mozilla::RefPtrTraits::Release(aPtr); } + }; + template + struct ConstRemovingRefPtrTraits { + static void AddRef(const U* aPtr) { + mozilla::RefPtrTraits::AddRef(const_cast(aPtr)); + } + static void Release(const U* aPtr) { + mozilla::RefPtrTraits::Release(const_cast(aPtr)); + } + }; +}; + +class nsCycleCollectionTraversalCallback; +template +void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback, + T* aChild, const char* aName, uint32_t aFlags); + +template +inline void ImplCycleCollectionUnlink(RefPtr& aField) { + aField = nullptr; +} + +template +inline void ImplCycleCollectionTraverse( + nsCycleCollectionTraversalCallback& aCallback, RefPtr& aField, + const char* aName, uint32_t aFlags = 0) { + CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags); +} + +template +inline RefPtr* address_of(RefPtr& aPtr) { + return aPtr.get_address(); +} + +template +inline const RefPtr* address_of(const RefPtr& aPtr) { + return aPtr.get_address(); +} + +template +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 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|. +*/ +{ + public: + explicit RefPtrGetterAddRefs(RefPtr& aSmartPtr) + : mTargetSmartPtr(aSmartPtr) { + // nothing else to do + } + + operator void**() { + return reinterpret_cast(mTargetSmartPtr.StartAssignment()); + } + + operator T**() { return mTargetSmartPtr.StartAssignment(); } + + T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } + + private: + RefPtr& mTargetSmartPtr; +}; + +template +inline RefPtrGetterAddRefs getter_AddRefs(RefPtr& aSmartPtr) +/* + Used around a |RefPtr| when + ...makes the class |RefPtrGetterAddRefs| invisible. +*/ +{ + return RefPtrGetterAddRefs(aSmartPtr); +} + +// Comparing two |RefPtr|s + +template +inline bool operator==(const RefPtr& aLhs, const RefPtr& aRhs) { + return static_cast(aLhs.get()) == static_cast(aRhs.get()); +} + +template +inline bool operator!=(const RefPtr& aLhs, const RefPtr& aRhs) { + return static_cast(aLhs.get()) != static_cast(aRhs.get()); +} + +// Comparing an |RefPtr| to a raw pointer + +template +inline bool operator==(const RefPtr& aLhs, const U* aRhs) { + return static_cast(aLhs.get()) == static_cast(aRhs); +} + +template +inline bool operator==(const U* aLhs, const RefPtr& aRhs) { + return static_cast(aLhs) == static_cast(aRhs.get()); +} + +template +inline bool operator!=(const RefPtr& aLhs, const U* aRhs) { + return static_cast(aLhs.get()) != static_cast(aRhs); +} + +template +inline bool operator!=(const U* aLhs, const RefPtr& aRhs) { + return static_cast(aLhs) != static_cast(aRhs.get()); +} + +template +inline bool operator==(const RefPtr& aLhs, U* aRhs) { + return static_cast(aLhs.get()) == const_cast(aRhs); +} + +template +inline bool operator==(U* aLhs, const RefPtr& aRhs) { + return const_cast(aLhs) == static_cast(aRhs.get()); +} + +template +inline bool operator!=(const RefPtr& aLhs, U* aRhs) { + return static_cast(aLhs.get()) != const_cast(aRhs); +} + +template +inline bool operator!=(U* aLhs, const RefPtr& aRhs) { + return const_cast(aLhs) != static_cast(aRhs.get()); +} + +// Comparing an |RefPtr| to |nullptr| + +template +inline bool operator==(const RefPtr& aLhs, decltype(nullptr)) { + return aLhs.get() == nullptr; +} + +template +inline bool operator==(decltype(nullptr), const RefPtr& aRhs) { + return nullptr == aRhs.get(); +} + +template +inline bool operator!=(const RefPtr& aLhs, decltype(nullptr)) { + return aLhs.get() != nullptr; +} + +template +inline bool operator!=(decltype(nullptr), const RefPtr& aRhs) { + return nullptr != aRhs.get(); +} + +// MOZ_DBG support + +template +std::ostream& operator<<(std::ostream& aOut, const RefPtr& aObj) { + return mozilla::DebugValue(aOut, aObj.get()); +} + +/*****************************************************************************/ + +template +inline already_AddRefed do_AddRef(T* aObj) { + RefPtr ref(aObj); + return ref.forget(); +} + +template +inline already_AddRefed do_AddRef(const RefPtr& aObj) { + RefPtr ref(aObj); + return ref.forget(); +} + +namespace mozilla { + +template +class AlignmentFinder; + +// Provide a specialization of AlignmentFinder to allow MOZ_ALIGNOF(RefPtr) +// with an incomplete T. +template +class AlignmentFinder> { + public: + static const size_t alignment = alignof(T*); +}; + +/** + * Helper function to be able to conveniently write things like: + * + * already_AddRefed + * f(...) + * { + * return MakeAndAddRef(...); + * } + */ +template +already_AddRefed MakeAndAddRef(Args&&... aArgs) { + RefPtr p(new T(std::forward(aArgs)...)); + return p.forget(); +} + +/** + * Helper function to be able to conveniently write things like: + * + * auto runnable = + * MakeRefPtr>( + * mOnSuccess, mOnFailure, *error, mWindowID); + */ +template +RefPtr MakeRefPtr(Args&&... aArgs) { + RefPtr p(new T(std::forward(aArgs)...)); + return p; +} + +} // namespace mozilla + +/** + * Deduction guide to allow simple `RefPtr` definitions from an + * already_AddRefed without repeating the type, e.g.: + * + * RefPtr ptr = MakeAndAddRef(...); + */ +template +RefPtr(already_AddRefed) -> RefPtr; + +#endif /* mozilla_RefPtr_h */ -- cgit v1.2.3