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/. */
6 
7 /* Useful extensions to UniquePtr. */
8 
9 #ifndef mozilla_UniquePtrExtensions_h
10 #define mozilla_UniquePtrExtensions_h
11 
12 #include <type_traits>
13 
14 #include "mozilla/Attributes.h"
15 #include "mozilla/fallible.h"
16 #include "mozilla/UniquePtr.h"
17 
18 #ifdef XP_WIN
19 #  include <cstdint>
20 #endif
21 
22 namespace mozilla {
23 
24 /**
25  * MakeUniqueFallible works exactly like MakeUnique, except that the memory
26  * allocation performed is done fallibly, i.e. it can return nullptr.
27  */
28 template <typename T, typename... Args>
MakeUniqueFallible(Args &&...aArgs)29 typename detail::UniqueSelector<T>::SingleObject MakeUniqueFallible(
30     Args&&... aArgs) {
31   return UniquePtr<T>(new (fallible) T(std::forward<Args>(aArgs)...));
32 }
33 
34 template <typename T>
MakeUniqueFallible(decltype (sizeof (int))aN)35 typename detail::UniqueSelector<T>::UnknownBound MakeUniqueFallible(
36     decltype(sizeof(int)) aN) {
37   using ArrayType = std::remove_extent_t<T>;
38   return UniquePtr<T>(new (fallible) ArrayType[aN]());
39 }
40 
41 template <typename T, typename... Args>
42 typename detail::UniqueSelector<T>::KnownBound MakeUniqueFallible(
43     Args&&... aArgs) = delete;
44 
45 /**
46  * MakeUniqueForOverwrite and MakeUniqueFallibleForOverwrite are like MakeUnique
47  * and MakeUniqueFallible except they use default-initialization. This is
48  * useful, for example, when you have a POD type array that will be overwritten
49  * directly after construction and so zero-initialization is a waste.
50  */
51 template <typename T, typename... Args>
MakeUniqueForOverwrite()52 typename detail::UniqueSelector<T>::SingleObject MakeUniqueForOverwrite() {
53   return UniquePtr<T>(new T);
54 }
55 
56 template <typename T>
MakeUniqueForOverwrite(decltype (sizeof (int))aN)57 typename detail::UniqueSelector<T>::UnknownBound MakeUniqueForOverwrite(
58     decltype(sizeof(int)) aN) {
59   using ArrayType = std::remove_extent_t<T>;
60   return UniquePtr<T>(new ArrayType[aN]);
61 }
62 
63 template <typename T, typename... Args>
64 typename detail::UniqueSelector<T>::KnownBound MakeUniqueForOverwrite(
65     Args&&... aArgs) = delete;
66 
67 template <typename T, typename... Args>
68 typename detail::UniqueSelector<T>::SingleObject
MakeUniqueForOverwriteFallible()69 MakeUniqueForOverwriteFallible() {
70   return UniquePtr<T>(new (fallible) T);
71 }
72 
73 template <typename T>
MakeUniqueForOverwriteFallible(decltype (sizeof (int))aN)74 typename detail::UniqueSelector<T>::UnknownBound MakeUniqueForOverwriteFallible(
75     decltype(sizeof(int)) aN) {
76   using ArrayType = std::remove_extent_t<T>;
77   return UniquePtr<T>(new (fallible) ArrayType[aN]);
78 }
79 
80 template <typename T, typename... Args>
81 typename detail::UniqueSelector<T>::KnownBound MakeUniqueForOverwriteFallible(
82     Args&&... aArgs) = delete;
83 
84 namespace detail {
85 
86 template <typename T>
87 struct FreePolicy {
operatorFreePolicy88   void operator()(const void* ptr) { free(const_cast<void*>(ptr)); }
89 };
90 
91 #if defined(XP_WIN)
92 // Can't include <windows.h> to get the actual definition of HANDLE
93 // because of namespace pollution.
94 typedef void* FileHandleType;
95 #elif defined(XP_UNIX)
96 typedef int FileHandleType;
97 #else
98 #  error "Unsupported OS?"
99 #endif
100 
101 struct FileHandleHelper {
FileHandleHelperFileHandleHelper102   MOZ_IMPLICIT FileHandleHelper(FileHandleType aHandle) : mHandle(aHandle) {}
103 
FileHandleHelperFileHandleHelper104   MOZ_IMPLICIT constexpr FileHandleHelper(std::nullptr_t)
105       : mHandle(kInvalidHandle) {}
106 
107   bool operator!=(std::nullptr_t) const {
108 #ifdef XP_WIN
109     // Windows uses both nullptr and INVALID_HANDLE_VALUE (-1 cast to
110     // HANDLE) in different situations, but nullptr is more reliably
111     // null while -1 is also valid input to some calls that take
112     // handles.  So class considers both to be null (since neither
113     // should be closed) but default-constructs as nullptr.
114     if (mHandle == (void*)-1) {
115       return false;
116     }
117 #endif
118     return mHandle != kInvalidHandle;
119   }
120 
FileHandleTypeFileHandleHelper121   operator FileHandleType() const { return mHandle; }
122 
123 #ifdef XP_WIN
124   // NSPR uses an integer type for PROsfd, so this conversion is
125   // provided for working with it without needing reinterpret casts
126   // everywhere.
intptr_tFileHandleHelper127   operator std::intptr_t() const {
128     return reinterpret_cast<std::intptr_t>(mHandle);
129   }
130 #endif
131 
132   // When there's only one user-defined conversion operator, the
133   // compiler will use that to derive equality, but that doesn't work
134   // when the conversion is ambiguoug (the XP_WIN case above).
135   bool operator==(const FileHandleHelper& aOther) const {
136     return mHandle == aOther.mHandle;
137   }
138 
139  private:
140   FileHandleType mHandle;
141 
142 #ifdef XP_WIN
143   // See above for why this is nullptr.  (Also, INVALID_HANDLE_VALUE
144   // can't be expressed as a constexpr.)
145   static constexpr FileHandleType kInvalidHandle = nullptr;
146 #else
147   static constexpr FileHandleType kInvalidHandle = -1;
148 #endif
149 };
150 
151 struct FileHandleDeleter {
152   typedef FileHandleHelper pointer;
153   MFBT_API void operator()(FileHandleHelper aHelper);
154 };
155 
156 }  // namespace detail
157 
158 template <typename T>
159 using UniqueFreePtr = UniquePtr<T, detail::FreePolicy<T>>;
160 
161 // A RAII class for the OS construct used for open files and similar
162 // objects: a file descriptor on Unix or a handle on Windows.
163 using UniqueFileHandle =
164     UniquePtr<detail::FileHandleType, detail::FileHandleDeleter>;
165 
166 // Helper for passing a UniquePtr to an old-style function that uses raw
167 // pointers for out params. Example usage:
168 //
169 //   void AllocateFoo(Foo** out) { *out = new Foo(); }
170 //   UniquePtr<Foo> foo;
171 //   AllocateFoo(getter_Transfers(foo));
172 template <typename T, typename D>
getter_Transfers(UniquePtr<T,D> & up)173 auto getter_Transfers(UniquePtr<T, D>& up) {
174   class MOZ_TEMPORARY_CLASS UniquePtrGetterTransfers {
175    public:
176     using Ptr = UniquePtr<T, D>;
177     explicit UniquePtrGetterTransfers(Ptr& p) : mPtr(p) {}
178     ~UniquePtrGetterTransfers() { mPtr.reset(mRawPtr); }
179 
180     operator typename Ptr::ElementType **() { return &mRawPtr; }
181     operator void**() { return reinterpret_cast<void**>(&mRawPtr); }
182     typename Ptr::ElementType*& operator*() { return mRawPtr; }
183 
184    private:
185     Ptr& mPtr;
186     typename Ptr::Pointer mRawPtr = nullptr;
187   };
188 
189   return UniquePtrGetterTransfers(up);
190 }
191 
192 }  // namespace mozilla
193 
194 #endif  // mozilla_UniquePtrExtensions_h
195