Bug 1866894 - Update failing subtest for content-visibility-auto-resize.html. r=fredw
[gecko.git] / mfbt / UniquePtrExtensions.h
blobf5c43ae29e0086e42548407e4eabb518954ac108
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"
19 #ifdef XP_WIN
20 # include <cstdint>
21 #endif
22 #if defined(XP_DARWIN) && !defined(RUST_BINDGEN)
23 # include <mach/mach.h>
24 #endif
26 namespace mozilla {
28 /**
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(
34 Args&&... aArgs) {
35 return UniquePtr<T>(new (fallible) T(std::forward<Args>(aArgs)...));
38 template <typename T>
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;
49 /**
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);
60 template <typename 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);
77 template <typename 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;
88 namespace detail {
90 template <typename T>
91 struct FreePolicy {
92 void operator()(const void* ptr) { free(const_cast<void*>(ptr)); }
95 #if defined(XP_WIN)
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;
101 #else
102 # error "Unsupported OS?"
103 #endif
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 {
112 #ifdef XP_WIN
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) {
119 return false;
121 #endif
122 return mHandle != kInvalidHandle;
125 operator FileHandleType() const { return mHandle; }
127 #ifdef XP_WIN
128 // NSPR uses an integer type for PROsfd, so this conversion is
129 // provided for working with it without needing reinterpret casts
130 // everywhere.
131 operator std::intptr_t() const {
132 return reinterpret_cast<std::intptr_t>(mHandle);
134 #endif
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;
143 private:
144 FileHandleType mHandle;
146 #ifdef XP_WIN
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;
150 #else
151 static constexpr FileHandleType kInvalidHandle = -1;
152 #endif
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; }
173 private:
174 mach_port_t 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");
206 #endif
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) {
231 kern_return_t kr =
232 mach_port_mod_refs(mach_task_self(), aPort, MACH_PORT_RIGHT_SEND, 1);
233 if (kr == KERN_SUCCESS) {
234 return UniqueMachSendRight(aPort);
236 return nullptr;
238 #endif
240 namespace detail {
242 struct HasReceiverTypeHelper {
243 template <class U>
244 static double Test(...);
245 template <class U>
246 static char Test(typename U::receiver* = 0);
249 template <class T>
250 class HasReceiverType
251 : public std::integral_constant<bool, sizeof(HasReceiverTypeHelper::Test<T>(
252 0)) == 1> {};
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 {
271 public:
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,
284 std::enable_if_t<
285 std::is_pointer_v<U> && std::is_same_v<U, Receiver>, int> = 0>
286 operator void**() {
287 return reinterpret_cast<void**>(&mReceiver);
290 private:
291 Ptr& mPtr;
292 Receiver 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