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 /* Useful extensions to UniquePtr. */
9 #ifndef mozilla_UniquePtrExtensions_h
10 #define mozilla_UniquePtrExtensions_h
12 #include <type_traits>
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Attributes.h"
16 #include "mozilla/DebugOnly.h"
17 #include "mozilla/fallible.h"
18 #include "mozilla/UniquePtr.h"
23 #if defined(XP_DARWIN) && !defined(RUST_BINDGEN)
24 # include <mach/mach.h>
30 * MakeUniqueFallible works exactly like MakeUnique, except that the memory
31 * allocation performed is done fallibly, i.e. it can return nullptr.
33 template <typename T
, typename
... Args
>
34 typename
detail::UniqueSelector
<T
>::SingleObject
MakeUniqueFallible(
36 return UniquePtr
<T
>(new (fallible
) T(std::forward
<Args
>(aArgs
)...));
40 typename
detail::UniqueSelector
<T
>::UnknownBound
MakeUniqueFallible(
41 decltype(sizeof(int)) aN
) {
42 using ArrayType
= std::remove_extent_t
<T
>;
43 return UniquePtr
<T
>(new (fallible
) ArrayType
[aN
]());
46 template <typename T
, typename
... Args
>
47 typename
detail::UniqueSelector
<T
>::KnownBound
MakeUniqueFallible(
48 Args
&&... aArgs
) = delete;
51 * MakeUniqueForOverwrite and MakeUniqueFallibleForOverwrite are like MakeUnique
52 * and MakeUniqueFallible except they use default-initialization. This is
53 * useful, for example, when you have a POD type array that will be overwritten
54 * directly after construction and so zero-initialization is a waste.
56 template <typename T
, typename
... Args
>
57 typename
detail::UniqueSelector
<T
>::SingleObject
MakeUniqueForOverwrite() {
58 return UniquePtr
<T
>(new T
);
62 typename
detail::UniqueSelector
<T
>::UnknownBound
MakeUniqueForOverwrite(
63 decltype(sizeof(int)) aN
) {
64 using ArrayType
= std::remove_extent_t
<T
>;
65 return UniquePtr
<T
>(new ArrayType
[aN
]);
68 template <typename T
, typename
... Args
>
69 typename
detail::UniqueSelector
<T
>::KnownBound
MakeUniqueForOverwrite(
70 Args
&&... aArgs
) = delete;
72 template <typename T
, typename
... Args
>
73 typename
detail::UniqueSelector
<T
>::SingleObject
74 MakeUniqueForOverwriteFallible() {
75 return UniquePtr
<T
>(new (fallible
) T
);
79 typename
detail::UniqueSelector
<T
>::UnknownBound
MakeUniqueForOverwriteFallible(
80 decltype(sizeof(int)) aN
) {
81 using ArrayType
= std::remove_extent_t
<T
>;
82 return UniquePtr
<T
>(new (fallible
) ArrayType
[aN
]);
85 template <typename T
, typename
... Args
>
86 typename
detail::UniqueSelector
<T
>::KnownBound
MakeUniqueForOverwriteFallible(
87 Args
&&... aArgs
) = delete;
93 void operator()(const void* ptr
) { free(const_cast<void*>(ptr
)); }
97 // Can't include <windows.h> to get the actual definition of HANDLE
98 // because of namespace pollution.
99 typedef void* FileHandleType
;
100 #elif defined(XP_UNIX)
101 typedef int FileHandleType
;
103 # error "Unsupported OS?"
106 struct FileHandleHelper
{
107 MOZ_IMPLICIT
FileHandleHelper(FileHandleType aHandle
) : mHandle(aHandle
) {
108 #if defined(XP_UNIX) && (defined(DEBUG) || defined(FUZZING))
109 MOZ_RELEASE_ASSERT(aHandle
== kInvalidHandle
|| aHandle
> 2);
113 MOZ_IMPLICIT
constexpr FileHandleHelper(std::nullptr_t
)
114 : mHandle(kInvalidHandle
) {}
116 bool operator!=(std::nullptr_t
) const {
118 // Windows uses both nullptr and INVALID_HANDLE_VALUE (-1 cast to
119 // HANDLE) in different situations, but nullptr is more reliably
120 // null while -1 is also valid input to some calls that take
121 // handles. So class considers both to be null (since neither
122 // should be closed) but default-constructs as nullptr.
123 if (mHandle
== (void*)-1) {
127 return mHandle
!= kInvalidHandle
;
130 operator FileHandleType() const { return mHandle
; }
133 // NSPR uses an integer type for PROsfd, so this conversion is
134 // provided for working with it without needing reinterpret casts
136 operator std::intptr_t() const {
137 return reinterpret_cast<std::intptr_t>(mHandle
);
141 // When there's only one user-defined conversion operator, the
142 // compiler will use that to derive equality, but that doesn't work
143 // when the conversion is ambiguoug (the XP_WIN case above).
144 bool operator==(const FileHandleHelper
& aOther
) const {
145 return mHandle
== aOther
.mHandle
;
149 FileHandleType mHandle
;
152 // See above for why this is nullptr. (Also, INVALID_HANDLE_VALUE
153 // can't be expressed as a constexpr.)
154 static constexpr FileHandleType kInvalidHandle
= nullptr;
156 static constexpr FileHandleType kInvalidHandle
= -1;
160 struct FileHandleDeleter
{
161 using pointer
= FileHandleHelper
;
162 using receiver
= FileHandleType
;
163 MFBT_API
void operator()(FileHandleHelper aHelper
);
166 #if defined(XP_DARWIN) && !defined(RUST_BINDGEN)
167 struct MachPortHelper
{
168 MOZ_IMPLICIT
MachPortHelper(mach_port_t aPort
) : mPort(aPort
) {}
170 MOZ_IMPLICIT
constexpr MachPortHelper(std::nullptr_t
)
171 : mPort(MACH_PORT_NULL
) {}
173 bool operator!=(std::nullptr_t
) const { return mPort
!= MACH_PORT_NULL
; }
175 operator const mach_port_t
&() const { return mPort
; }
176 operator mach_port_t
&() { return mPort
; }
182 struct MachSendRightDeleter
{
183 using pointer
= MachPortHelper
;
184 using receiver
= mach_port_t
;
185 MFBT_API
void operator()(MachPortHelper aHelper
) {
186 DebugOnly
<kern_return_t
> kr
=
187 mach_port_deallocate(mach_task_self(), aHelper
);
188 MOZ_ASSERT(kr
== KERN_SUCCESS
, "failed to deallocate mach send right");
192 struct MachReceiveRightDeleter
{
193 using pointer
= MachPortHelper
;
194 using receiver
= mach_port_t
;
195 MFBT_API
void operator()(MachPortHelper aHelper
) {
196 DebugOnly
<kern_return_t
> kr
= mach_port_mod_refs(
197 mach_task_self(), aHelper
, MACH_PORT_RIGHT_RECEIVE
, -1);
198 MOZ_ASSERT(kr
== KERN_SUCCESS
, "failed to release mach receive right");
202 struct MachPortSetDeleter
{
203 using pointer
= MachPortHelper
;
204 using receiver
= mach_port_t
;
205 MFBT_API
void operator()(MachPortHelper aHelper
) {
206 DebugOnly
<kern_return_t
> kr
= mach_port_mod_refs(
207 mach_task_self(), aHelper
, MACH_PORT_RIGHT_PORT_SET
, -1);
208 MOZ_ASSERT(kr
== KERN_SUCCESS
, "failed to release mach port set");
213 } // namespace detail
215 template <typename T
>
216 using UniqueFreePtr
= UniquePtr
<T
, detail::FreePolicy
<T
>>;
218 // A RAII class for the OS construct used for open files and similar
219 // objects: a file descriptor on Unix or a handle on Windows.
220 using UniqueFileHandle
=
221 UniquePtr
<detail::FileHandleType
, detail::FileHandleDeleter
>;
223 #if defined(XP_DARWIN) && !defined(RUST_BINDGEN)
224 // A RAII class for a Mach port that names a send right.
225 using UniqueMachSendRight
=
226 UniquePtr
<mach_port_t
, detail::MachSendRightDeleter
>;
227 // A RAII class for a Mach port that names a receive right.
228 using UniqueMachReceiveRight
=
229 UniquePtr
<mach_port_t
, detail::MachReceiveRightDeleter
>;
230 // A RAII class for a Mach port set.
231 using UniqueMachPortSet
= UniquePtr
<mach_port_t
, detail::MachPortSetDeleter
>;
233 // Increases the user reference count for MACH_PORT_RIGHT_SEND by 1 and returns
234 // a new UniqueMachSendRight to manage the additional right.
235 inline UniqueMachSendRight
RetainMachSendRight(mach_port_t aPort
) {
237 mach_port_mod_refs(mach_task_self(), aPort
, MACH_PORT_RIGHT_SEND
, 1);
238 if (kr
== KERN_SUCCESS
) {
239 return UniqueMachSendRight(aPort
);
247 struct HasReceiverTypeHelper
{
249 static double Test(...);
251 static char Test(typename
U::receiver
* = 0);
255 class HasReceiverType
256 : public std::integral_constant
<bool, sizeof(HasReceiverTypeHelper::Test
<T
>(
259 template <class T
, class D
, bool = HasReceiverType
<D
>::value
>
260 struct ReceiverTypeImpl
{
261 using Type
= typename
D::receiver
;
264 template <class T
, class D
>
265 struct ReceiverTypeImpl
<T
, D
, false> {
266 using Type
= typename PointerType
<T
, D
>::Type
;
269 template <class T
, class D
>
270 struct ReceiverType
{
271 using Type
= typename ReceiverTypeImpl
<T
, std::remove_reference_t
<D
>>::Type
;
274 template <typename T
, typename D
>
275 class MOZ_TEMPORARY_CLASS UniquePtrGetterTransfers
{
277 using Ptr
= UniquePtr
<T
, D
>;
278 using Receiver
= typename
detail::ReceiverType
<T
, D
>::Type
;
280 explicit UniquePtrGetterTransfers(Ptr
& p
)
281 : mPtr(p
), mReceiver(typename
Ptr::Pointer(nullptr)) {}
282 ~UniquePtrGetterTransfers() { mPtr
.reset(mReceiver
); }
284 operator Receiver
*() { return &mReceiver
; }
285 Receiver
& operator*() { return mReceiver
; }
287 // operator void** is conditionally enabled if `Receiver` is a pointer.
288 template <typename U
= Receiver
,
290 std::is_pointer_v
<U
> && std::is_same_v
<U
, Receiver
>, int> = 0>
292 return reinterpret_cast<void**>(&mReceiver
);
300 } // namespace detail
302 // Helper for passing a UniquePtr to an old-style function that uses raw
303 // pointers for out params. Example usage:
305 // void AllocateFoo(Foo** out) { *out = new Foo(); }
306 // UniquePtr<Foo> foo;
307 // AllocateFoo(getter_Transfers(foo));
308 template <typename T
, typename D
>
309 auto getter_Transfers(UniquePtr
<T
, D
>& up
) {
310 return detail::UniquePtrGetterTransfers
<T
, D
>(up
);
313 } // namespace mozilla
315 #endif // mozilla_UniquePtrExtensions_h