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/Attributes.h"
15 #include "mozilla/DebugOnly.h"
16 #include "mozilla/fallible.h"
17 #include "mozilla/UniquePtr.h"
22 #if defined(XP_DARWIN) && !defined(RUST_BINDGEN)
23 # include <mach/mach.h>
29 * MakeUniqueFallible works exactly like MakeUnique, except that the memory
30 * allocation performed is done fallibly, i.e. it can return nullptr.
32 template <typename T
, typename
... Args
>
33 typename
detail::UniqueSelector
<T
>::SingleObject
MakeUniqueFallible(
35 return UniquePtr
<T
>(new (fallible
) T(std::forward
<Args
>(aArgs
)...));
39 typename
detail::UniqueSelector
<T
>::UnknownBound
MakeUniqueFallible(
40 decltype(sizeof(int)) aN
) {
41 using ArrayType
= std::remove_extent_t
<T
>;
42 return UniquePtr
<T
>(new (fallible
) ArrayType
[aN
]());
45 template <typename T
, typename
... Args
>
46 typename
detail::UniqueSelector
<T
>::KnownBound
MakeUniqueFallible(
47 Args
&&... aArgs
) = delete;
50 * MakeUniqueForOverwrite and MakeUniqueFallibleForOverwrite are like MakeUnique
51 * and MakeUniqueFallible except they use default-initialization. This is
52 * useful, for example, when you have a POD type array that will be overwritten
53 * directly after construction and so zero-initialization is a waste.
55 template <typename T
, typename
... Args
>
56 typename
detail::UniqueSelector
<T
>::SingleObject
MakeUniqueForOverwrite() {
57 return UniquePtr
<T
>(new T
);
61 typename
detail::UniqueSelector
<T
>::UnknownBound
MakeUniqueForOverwrite(
62 decltype(sizeof(int)) aN
) {
63 using ArrayType
= std::remove_extent_t
<T
>;
64 return UniquePtr
<T
>(new ArrayType
[aN
]);
67 template <typename T
, typename
... Args
>
68 typename
detail::UniqueSelector
<T
>::KnownBound
MakeUniqueForOverwrite(
69 Args
&&... aArgs
) = delete;
71 template <typename T
, typename
... Args
>
72 typename
detail::UniqueSelector
<T
>::SingleObject
73 MakeUniqueForOverwriteFallible() {
74 return UniquePtr
<T
>(new (fallible
) T
);
78 typename
detail::UniqueSelector
<T
>::UnknownBound
MakeUniqueForOverwriteFallible(
79 decltype(sizeof(int)) aN
) {
80 using ArrayType
= std::remove_extent_t
<T
>;
81 return UniquePtr
<T
>(new (fallible
) ArrayType
[aN
]);
84 template <typename T
, typename
... Args
>
85 typename
detail::UniqueSelector
<T
>::KnownBound
MakeUniqueForOverwriteFallible(
86 Args
&&... aArgs
) = delete;
92 void operator()(const void* ptr
) { free(const_cast<void*>(ptr
)); }
96 // Can't include <windows.h> to get the actual definition of HANDLE
97 // because of namespace pollution.
98 typedef void* FileHandleType
;
99 #elif defined(XP_UNIX)
100 typedef int FileHandleType
;
102 # error "Unsupported OS?"
105 struct FileHandleHelper
{
106 MOZ_IMPLICIT
FileHandleHelper(FileHandleType aHandle
) : mHandle(aHandle
) {}
108 MOZ_IMPLICIT
constexpr FileHandleHelper(std::nullptr_t
)
109 : mHandle(kInvalidHandle
) {}
111 bool operator!=(std::nullptr_t
) const {
113 // Windows uses both nullptr and INVALID_HANDLE_VALUE (-1 cast to
114 // HANDLE) in different situations, but nullptr is more reliably
115 // null while -1 is also valid input to some calls that take
116 // handles. So class considers both to be null (since neither
117 // should be closed) but default-constructs as nullptr.
118 if (mHandle
== (void*)-1) {
122 return mHandle
!= kInvalidHandle
;
125 operator FileHandleType() const { return mHandle
; }
128 // NSPR uses an integer type for PROsfd, so this conversion is
129 // provided for working with it without needing reinterpret casts
131 operator std::intptr_t() const {
132 return reinterpret_cast<std::intptr_t>(mHandle
);
136 // When there's only one user-defined conversion operator, the
137 // compiler will use that to derive equality, but that doesn't work
138 // when the conversion is ambiguoug (the XP_WIN case above).
139 bool operator==(const FileHandleHelper
& aOther
) const {
140 return mHandle
== aOther
.mHandle
;
144 FileHandleType mHandle
;
147 // See above for why this is nullptr. (Also, INVALID_HANDLE_VALUE
148 // can't be expressed as a constexpr.)
149 static constexpr FileHandleType kInvalidHandle
= nullptr;
151 static constexpr FileHandleType kInvalidHandle
= -1;
155 struct FileHandleDeleter
{
156 using pointer
= FileHandleHelper
;
157 using receiver
= FileHandleType
;
158 MFBT_API
void operator()(FileHandleHelper aHelper
);
161 #if defined(XP_DARWIN) && !defined(RUST_BINDGEN)
162 struct MachPortHelper
{
163 MOZ_IMPLICIT
MachPortHelper(mach_port_t aPort
) : mPort(aPort
) {}
165 MOZ_IMPLICIT
constexpr MachPortHelper(std::nullptr_t
)
166 : mPort(MACH_PORT_NULL
) {}
168 bool operator!=(std::nullptr_t
) const { return mPort
!= MACH_PORT_NULL
; }
170 operator const mach_port_t
&() const { return mPort
; }
171 operator mach_port_t
&() { return mPort
; }
177 struct MachSendRightDeleter
{
178 using pointer
= MachPortHelper
;
179 using receiver
= mach_port_t
;
180 MFBT_API
void operator()(MachPortHelper aHelper
) {
181 DebugOnly
<kern_return_t
> kr
=
182 mach_port_deallocate(mach_task_self(), aHelper
);
183 MOZ_ASSERT(kr
== KERN_SUCCESS
, "failed to deallocate mach send right");
187 struct MachReceiveRightDeleter
{
188 using pointer
= MachPortHelper
;
189 using receiver
= mach_port_t
;
190 MFBT_API
void operator()(MachPortHelper aHelper
) {
191 DebugOnly
<kern_return_t
> kr
= mach_port_mod_refs(
192 mach_task_self(), aHelper
, MACH_PORT_RIGHT_RECEIVE
, -1);
193 MOZ_ASSERT(kr
== KERN_SUCCESS
, "failed to release mach receive right");
197 struct MachPortSetDeleter
{
198 using pointer
= MachPortHelper
;
199 using receiver
= mach_port_t
;
200 MFBT_API
void operator()(MachPortHelper aHelper
) {
201 DebugOnly
<kern_return_t
> kr
= mach_port_mod_refs(
202 mach_task_self(), aHelper
, MACH_PORT_RIGHT_PORT_SET
, -1);
203 MOZ_ASSERT(kr
== KERN_SUCCESS
, "failed to release mach port set");
208 } // namespace detail
210 template <typename T
>
211 using UniqueFreePtr
= UniquePtr
<T
, detail::FreePolicy
<T
>>;
213 // A RAII class for the OS construct used for open files and similar
214 // objects: a file descriptor on Unix or a handle on Windows.
215 using UniqueFileHandle
=
216 UniquePtr
<detail::FileHandleType
, detail::FileHandleDeleter
>;
218 #if defined(XP_DARWIN) && !defined(RUST_BINDGEN)
219 // A RAII class for a Mach port that names a send right.
220 using UniqueMachSendRight
=
221 UniquePtr
<mach_port_t
, detail::MachSendRightDeleter
>;
222 // A RAII class for a Mach port that names a receive right.
223 using UniqueMachReceiveRight
=
224 UniquePtr
<mach_port_t
, detail::MachReceiveRightDeleter
>;
225 // A RAII class for a Mach port set.
226 using UniqueMachPortSet
= UniquePtr
<mach_port_t
, detail::MachPortSetDeleter
>;
228 // Increases the user reference count for MACH_PORT_RIGHT_SEND by 1 and returns
229 // a new UniqueMachSendRight to manage the additional right.
230 inline UniqueMachSendRight
RetainMachSendRight(mach_port_t aPort
) {
232 mach_port_mod_refs(mach_task_self(), aPort
, MACH_PORT_RIGHT_SEND
, 1);
233 if (kr
== KERN_SUCCESS
) {
234 return UniqueMachSendRight(aPort
);
242 struct HasReceiverTypeHelper
{
244 static double Test(...);
246 static char Test(typename
U::receiver
* = 0);
250 class HasReceiverType
251 : public std::integral_constant
<bool, sizeof(HasReceiverTypeHelper::Test
<T
>(
254 template <class T
, class D
, bool = HasReceiverType
<D
>::value
>
255 struct ReceiverTypeImpl
{
256 using Type
= typename
D::receiver
;
259 template <class T
, class D
>
260 struct ReceiverTypeImpl
<T
, D
, false> {
261 using Type
= typename PointerType
<T
, D
>::Type
;
264 template <class T
, class D
>
265 struct ReceiverType
{
266 using Type
= typename ReceiverTypeImpl
<T
, std::remove_reference_t
<D
>>::Type
;
269 template <typename T
, typename D
>
270 class MOZ_TEMPORARY_CLASS UniquePtrGetterTransfers
{
272 using Ptr
= UniquePtr
<T
, D
>;
273 using Receiver
= typename
detail::ReceiverType
<T
, D
>::Type
;
275 explicit UniquePtrGetterTransfers(Ptr
& p
)
276 : mPtr(p
), mReceiver(typename
Ptr::Pointer(nullptr)) {}
277 ~UniquePtrGetterTransfers() { mPtr
.reset(mReceiver
); }
279 operator Receiver
*() { return &mReceiver
; }
280 Receiver
& operator*() { return mReceiver
; }
282 // operator void** is conditionally enabled if `Receiver` is a pointer.
283 template <typename U
= Receiver
,
285 std::is_pointer_v
<U
> && std::is_same_v
<U
, Receiver
>, int> = 0>
287 return reinterpret_cast<void**>(&mReceiver
);
295 } // namespace detail
297 // Helper for passing a UniquePtr to an old-style function that uses raw
298 // pointers for out params. Example usage:
300 // void AllocateFoo(Foo** out) { *out = new Foo(); }
301 // UniquePtr<Foo> foo;
302 // AllocateFoo(getter_Transfers(foo));
303 template <typename T
, typename D
>
304 auto getter_Transfers(UniquePtr
<T
, D
>& up
) {
305 return detail::UniquePtrGetterTransfers
<T
, D
>(up
);
308 } // namespace mozilla
310 #endif // mozilla_UniquePtrExtensions_h