From 43a97878ce14b72f0981164f87f2e35e14151312 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:22:09 +0200 Subject: Adding upstream version 110.0.1. Signed-off-by: Daniel Baumann --- mfbt/UniquePtrExtensions.h | 310 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 mfbt/UniquePtrExtensions.h (limited to 'mfbt/UniquePtrExtensions.h') diff --git a/mfbt/UniquePtrExtensions.h b/mfbt/UniquePtrExtensions.h new file mode 100644 index 0000000000..7a7b97a94e --- /dev/null +++ b/mfbt/UniquePtrExtensions.h @@ -0,0 +1,310 @@ +/* -*- 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/. */ + +/* Useful extensions to UniquePtr. */ + +#ifndef mozilla_UniquePtrExtensions_h +#define mozilla_UniquePtrExtensions_h + +#include + +#include "mozilla/Attributes.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/fallible.h" +#include "mozilla/UniquePtr.h" + +#ifdef XP_WIN +# include +#endif +#if defined(XP_MACOSX) && !defined(RUST_BINDGEN) +# include +#endif + +namespace mozilla { + +/** + * MakeUniqueFallible works exactly like MakeUnique, except that the memory + * allocation performed is done fallibly, i.e. it can return nullptr. + */ +template +typename detail::UniqueSelector::SingleObject MakeUniqueFallible( + Args&&... aArgs) { + return UniquePtr(new (fallible) T(std::forward(aArgs)...)); +} + +template +typename detail::UniqueSelector::UnknownBound MakeUniqueFallible( + decltype(sizeof(int)) aN) { + using ArrayType = std::remove_extent_t; + return UniquePtr(new (fallible) ArrayType[aN]()); +} + +template +typename detail::UniqueSelector::KnownBound MakeUniqueFallible( + Args&&... aArgs) = delete; + +/** + * MakeUniqueForOverwrite and MakeUniqueFallibleForOverwrite are like MakeUnique + * and MakeUniqueFallible except they use default-initialization. This is + * useful, for example, when you have a POD type array that will be overwritten + * directly after construction and so zero-initialization is a waste. + */ +template +typename detail::UniqueSelector::SingleObject MakeUniqueForOverwrite() { + return UniquePtr(new T); +} + +template +typename detail::UniqueSelector::UnknownBound MakeUniqueForOverwrite( + decltype(sizeof(int)) aN) { + using ArrayType = std::remove_extent_t; + return UniquePtr(new ArrayType[aN]); +} + +template +typename detail::UniqueSelector::KnownBound MakeUniqueForOverwrite( + Args&&... aArgs) = delete; + +template +typename detail::UniqueSelector::SingleObject +MakeUniqueForOverwriteFallible() { + return UniquePtr(new (fallible) T); +} + +template +typename detail::UniqueSelector::UnknownBound MakeUniqueForOverwriteFallible( + decltype(sizeof(int)) aN) { + using ArrayType = std::remove_extent_t; + return UniquePtr(new (fallible) ArrayType[aN]); +} + +template +typename detail::UniqueSelector::KnownBound MakeUniqueForOverwriteFallible( + Args&&... aArgs) = delete; + +namespace detail { + +template +struct FreePolicy { + void operator()(const void* ptr) { free(const_cast(ptr)); } +}; + +#if defined(XP_WIN) +// Can't include to get the actual definition of HANDLE +// because of namespace pollution. +typedef void* FileHandleType; +#elif defined(XP_UNIX) +typedef int FileHandleType; +#else +# error "Unsupported OS?" +#endif + +struct FileHandleHelper { + MOZ_IMPLICIT FileHandleHelper(FileHandleType aHandle) : mHandle(aHandle) {} + + MOZ_IMPLICIT constexpr FileHandleHelper(std::nullptr_t) + : mHandle(kInvalidHandle) {} + + bool operator!=(std::nullptr_t) const { +#ifdef XP_WIN + // Windows uses both nullptr and INVALID_HANDLE_VALUE (-1 cast to + // HANDLE) in different situations, but nullptr is more reliably + // null while -1 is also valid input to some calls that take + // handles. So class considers both to be null (since neither + // should be closed) but default-constructs as nullptr. + if (mHandle == (void*)-1) { + return false; + } +#endif + return mHandle != kInvalidHandle; + } + + operator FileHandleType() const { return mHandle; } + +#ifdef XP_WIN + // NSPR uses an integer type for PROsfd, so this conversion is + // provided for working with it without needing reinterpret casts + // everywhere. + operator std::intptr_t() const { + return reinterpret_cast(mHandle); + } +#endif + + // When there's only one user-defined conversion operator, the + // compiler will use that to derive equality, but that doesn't work + // when the conversion is ambiguoug (the XP_WIN case above). + bool operator==(const FileHandleHelper& aOther) const { + return mHandle == aOther.mHandle; + } + + private: + FileHandleType mHandle; + +#ifdef XP_WIN + // See above for why this is nullptr. (Also, INVALID_HANDLE_VALUE + // can't be expressed as a constexpr.) + static constexpr FileHandleType kInvalidHandle = nullptr; +#else + static constexpr FileHandleType kInvalidHandle = -1; +#endif +}; + +struct FileHandleDeleter { + using pointer = FileHandleHelper; + using receiver = FileHandleType; + MFBT_API void operator()(FileHandleHelper aHelper); +}; + +#if defined(XP_MACOSX) && !defined(RUST_BINDGEN) +struct MachPortHelper { + MOZ_IMPLICIT MachPortHelper(mach_port_t aPort) : mPort(aPort) {} + + MOZ_IMPLICIT constexpr MachPortHelper(std::nullptr_t) + : mPort(MACH_PORT_NULL) {} + + bool operator!=(std::nullptr_t) const { return mPort != MACH_PORT_NULL; } + + operator const mach_port_t&() const { return mPort; } + operator mach_port_t&() { return mPort; } + + private: + mach_port_t mPort; +}; + +struct MachSendRightDeleter { + using pointer = MachPortHelper; + using receiver = mach_port_t; + MFBT_API void operator()(MachPortHelper aHelper) { + DebugOnly kr = + mach_port_deallocate(mach_task_self(), aHelper); + MOZ_ASSERT(kr == KERN_SUCCESS, "failed to deallocate mach send right"); + } +}; + +struct MachReceiveRightDeleter { + using pointer = MachPortHelper; + using receiver = mach_port_t; + MFBT_API void operator()(MachPortHelper aHelper) { + DebugOnly kr = mach_port_mod_refs( + mach_task_self(), aHelper, MACH_PORT_RIGHT_RECEIVE, -1); + MOZ_ASSERT(kr == KERN_SUCCESS, "failed to release mach receive right"); + } +}; + +struct MachPortSetDeleter { + using pointer = MachPortHelper; + using receiver = mach_port_t; + MFBT_API void operator()(MachPortHelper aHelper) { + DebugOnly kr = mach_port_mod_refs( + mach_task_self(), aHelper, MACH_PORT_RIGHT_PORT_SET, -1); + MOZ_ASSERT(kr == KERN_SUCCESS, "failed to release mach port set"); + } +}; +#endif + +} // namespace detail + +template +using UniqueFreePtr = UniquePtr>; + +// A RAII class for the OS construct used for open files and similar +// objects: a file descriptor on Unix or a handle on Windows. +using UniqueFileHandle = + UniquePtr; + +#if defined(XP_MACOSX) && !defined(RUST_BINDGEN) +// A RAII class for a Mach port that names a send right. +using UniqueMachSendRight = + UniquePtr; +// A RAII class for a Mach port that names a receive right. +using UniqueMachReceiveRight = + UniquePtr; +// A RAII class for a Mach port set. +using UniqueMachPortSet = UniquePtr; + +// Increases the user reference count for MACH_PORT_RIGHT_SEND by 1 and returns +// a new UniqueMachSendRight to manage the additional right. +inline UniqueMachSendRight RetainMachSendRight(mach_port_t aPort) { + kern_return_t kr = + mach_port_mod_refs(mach_task_self(), aPort, MACH_PORT_RIGHT_SEND, 1); + if (kr == KERN_SUCCESS) { + return UniqueMachSendRight(aPort); + } + return nullptr; +} +#endif + +namespace detail { + +struct HasReceiverTypeHelper { + template + static double Test(...); + template + static char Test(typename U::receiver* = 0); +}; + +template +class HasReceiverType + : public std::integral_constant( + 0)) == 1> {}; + +template ::value> +struct ReceiverTypeImpl { + using Type = typename D::receiver; +}; + +template +struct ReceiverTypeImpl { + using Type = typename PointerType::Type; +}; + +template +struct ReceiverType { + using Type = typename ReceiverTypeImpl>::Type; +}; + +template +class MOZ_TEMPORARY_CLASS UniquePtrGetterTransfers { + public: + using Ptr = UniquePtr; + using Receiver = typename detail::ReceiverType::Type; + + explicit UniquePtrGetterTransfers(Ptr& p) + : mPtr(p), mReceiver(typename Ptr::Pointer(nullptr)) {} + ~UniquePtrGetterTransfers() { mPtr.reset(mReceiver); } + + operator Receiver*() { return &mReceiver; } + Receiver& operator*() { return mReceiver; } + + // operator void** is conditionally enabled if `Receiver` is a pointer. + template && std::is_same_v, int> = 0> + operator void**() { + return reinterpret_cast(&mReceiver); + } + + private: + Ptr& mPtr; + Receiver mReceiver; +}; + +} // namespace detail + +// Helper for passing a UniquePtr to an old-style function that uses raw +// pointers for out params. Example usage: +// +// void AllocateFoo(Foo** out) { *out = new Foo(); } +// UniquePtr foo; +// AllocateFoo(getter_Transfers(foo)); +template +auto getter_Transfers(UniquePtr& up) { + return detail::UniquePtrGetterTransfers(up); +} + +} // namespace mozilla + +#endif // mozilla_UniquePtrExtensions_h -- cgit v1.2.3