xref: /freebsd/contrib/llvm-project/clang/include/clang/Basic/CustomizableOptional.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===- CustomizableOptional.h - Optional with custom storage ----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef CLANG_BASIC_CUSTOMIZABLEOPTIONAL_H
10 #define CLANG_BASIC_CUSTOMIZABLEOPTIONAL_H
11 
12 #include "llvm/ADT/Hashing.h"
13 #include "llvm/Support/Compiler.h"
14 #include "llvm/Support/type_traits.h"
15 #include <cassert>
16 #include <new>
17 #include <optional>
18 #include <utility>
19 
20 namespace clang {
21 
22 namespace optional_detail {
23 template <typename> class OptionalStorage;
24 } // namespace optional_detail
25 
26 // Optional type which internal storage can be specialized by providing
27 // OptionalStorage. The interface follows std::optional.
28 template <typename T> class CustomizableOptional {
29   optional_detail::OptionalStorage<T> Storage;
30 
31 public:
32   using value_type = T;
33 
34   constexpr CustomizableOptional() = default;
CustomizableOptional(std::nullopt_t)35   constexpr CustomizableOptional(std::nullopt_t) {}
36 
CustomizableOptional(const T & y)37   constexpr CustomizableOptional(const T &y) : Storage(std::in_place, y) {}
38   constexpr CustomizableOptional(const CustomizableOptional &O) = default;
39 
CustomizableOptional(T && y)40   constexpr CustomizableOptional(T &&y)
41       : Storage(std::in_place, std::move(y)) {}
42   constexpr CustomizableOptional(CustomizableOptional &&O) = default;
43 
44   template <typename... ArgTypes>
CustomizableOptional(std::in_place_t,ArgTypes &&...Args)45   constexpr CustomizableOptional(std::in_place_t, ArgTypes &&...Args)
46       : Storage(std::in_place, std::forward<ArgTypes>(Args)...) {}
47 
48   // Allow conversion from std::optional<T>.
CustomizableOptional(const std::optional<T> & y)49   constexpr CustomizableOptional(const std::optional<T> &y)
50       : CustomizableOptional(y ? *y : CustomizableOptional()) {}
CustomizableOptional(std::optional<T> && y)51   constexpr CustomizableOptional(std::optional<T> &&y)
52       : CustomizableOptional(y ? std::move(*y) : CustomizableOptional()) {}
53 
54   CustomizableOptional &operator=(T &&y) {
55     Storage = std::move(y);
56     return *this;
57   }
58   CustomizableOptional &operator=(CustomizableOptional &&O) = default;
59 
60   /// Create a new object by constructing it in place with the given arguments.
emplace(ArgTypes &&...Args)61   template <typename... ArgTypes> void emplace(ArgTypes &&...Args) {
62     Storage.emplace(std::forward<ArgTypes>(Args)...);
63   }
64 
65   CustomizableOptional &operator=(const T &y) {
66     Storage = y;
67     return *this;
68   }
69   CustomizableOptional &operator=(const CustomizableOptional &O) = default;
70 
reset()71   void reset() { Storage.reset(); }
72 
73   LLVM_DEPRECATED("Use &*X instead.", "&*X")
getPointer()74   constexpr const T *getPointer() const { return &Storage.value(); }
75   LLVM_DEPRECATED("Use &*X instead.", "&*X")
getPointer()76   T *getPointer() { return &Storage.value(); }
77   LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead", "*X")
value()78   constexpr const T &value() const & { return Storage.value(); }
79   LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead", "*X")
value()80   T &value() & { return Storage.value(); }
81 
82   constexpr explicit operator bool() const { return has_value(); }
has_value()83   constexpr bool has_value() const { return Storage.has_value(); }
84   constexpr const T *operator->() const { return &Storage.value(); }
85   T *operator->() { return &Storage.value(); }
86   constexpr const T &operator*() const & { return Storage.value(); }
87   T &operator*() & { return Storage.value(); }
88 
value_or(U && alt)89   template <typename U> constexpr T value_or(U &&alt) const & {
90     return has_value() ? operator*() : std::forward<U>(alt);
91   }
92 
93   LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead", "*X")
value()94   T &&value() && { return std::move(Storage.value()); }
95   T &&operator*() && { return std::move(Storage.value()); }
96 
value_or(U && alt)97   template <typename U> T value_or(U &&alt) && {
98     return has_value() ? std::move(operator*()) : std::forward<U>(alt);
99   }
100 };
101 
102 template <typename T>
103 CustomizableOptional(const T &) -> CustomizableOptional<T>;
104 
105 template <class T>
hash_value(const CustomizableOptional<T> & O)106 llvm::hash_code hash_value(const CustomizableOptional<T> &O) {
107   return O ? llvm::hash_combine(true, *O) : llvm::hash_value(false);
108 }
109 
110 template <typename T, typename U>
111 constexpr bool operator==(const CustomizableOptional<T> &X,
112                           const CustomizableOptional<U> &Y) {
113   if (X && Y)
114     return *X == *Y;
115   return X.has_value() == Y.has_value();
116 }
117 
118 template <typename T, typename U>
119 constexpr bool operator!=(const CustomizableOptional<T> &X,
120                           const CustomizableOptional<U> &Y) {
121   return !(X == Y);
122 }
123 
124 template <typename T, typename U>
125 constexpr bool operator<(const CustomizableOptional<T> &X,
126                          const CustomizableOptional<U> &Y) {
127   if (X && Y)
128     return *X < *Y;
129   return X.has_value() < Y.has_value();
130 }
131 
132 template <typename T, typename U>
133 constexpr bool operator<=(const CustomizableOptional<T> &X,
134                           const CustomizableOptional<U> &Y) {
135   return !(Y < X);
136 }
137 
138 template <typename T, typename U>
139 constexpr bool operator>(const CustomizableOptional<T> &X,
140                          const CustomizableOptional<U> &Y) {
141   return Y < X;
142 }
143 
144 template <typename T, typename U>
145 constexpr bool operator>=(const CustomizableOptional<T> &X,
146                           const CustomizableOptional<U> &Y) {
147   return !(X < Y);
148 }
149 
150 template <typename T>
151 constexpr bool operator==(const CustomizableOptional<T> &X, std::nullopt_t) {
152   return !X;
153 }
154 
155 template <typename T>
156 constexpr bool operator==(std::nullopt_t, const CustomizableOptional<T> &X) {
157   return X == std::nullopt;
158 }
159 
160 template <typename T>
161 constexpr bool operator!=(const CustomizableOptional<T> &X, std::nullopt_t) {
162   return !(X == std::nullopt);
163 }
164 
165 template <typename T>
166 constexpr bool operator!=(std::nullopt_t, const CustomizableOptional<T> &X) {
167   return X != std::nullopt;
168 }
169 
170 template <typename T>
171 constexpr bool operator<(const CustomizableOptional<T> &, std::nullopt_t) {
172   return false;
173 }
174 
175 template <typename T>
176 constexpr bool operator<(std::nullopt_t, const CustomizableOptional<T> &X) {
177   return X.has_value();
178 }
179 
180 template <typename T>
181 constexpr bool operator<=(const CustomizableOptional<T> &X, std::nullopt_t) {
182   return !(std::nullopt < X);
183 }
184 
185 template <typename T>
186 constexpr bool operator<=(std::nullopt_t, const CustomizableOptional<T> &X) {
187   return !(X < std::nullopt);
188 }
189 
190 template <typename T>
191 constexpr bool operator>(const CustomizableOptional<T> &X, std::nullopt_t) {
192   return std::nullopt < X;
193 }
194 
195 template <typename T>
196 constexpr bool operator>(std::nullopt_t, const CustomizableOptional<T> &X) {
197   return X < std::nullopt;
198 }
199 
200 template <typename T>
201 constexpr bool operator>=(const CustomizableOptional<T> &X, std::nullopt_t) {
202   return std::nullopt <= X;
203 }
204 
205 template <typename T>
206 constexpr bool operator>=(std::nullopt_t, const CustomizableOptional<T> &X) {
207   return X <= std::nullopt;
208 }
209 
210 template <typename T>
211 constexpr bool operator==(const CustomizableOptional<T> &X, const T &Y) {
212   return X && *X == Y;
213 }
214 
215 template <typename T>
216 constexpr bool operator==(const T &X, const CustomizableOptional<T> &Y) {
217   return Y && X == *Y;
218 }
219 
220 template <typename T>
221 constexpr bool operator!=(const CustomizableOptional<T> &X, const T &Y) {
222   return !(X == Y);
223 }
224 
225 template <typename T>
226 constexpr bool operator!=(const T &X, const CustomizableOptional<T> &Y) {
227   return !(X == Y);
228 }
229 
230 template <typename T>
231 constexpr bool operator<(const CustomizableOptional<T> &X, const T &Y) {
232   return !X || *X < Y;
233 }
234 
235 template <typename T>
236 constexpr bool operator<(const T &X, const CustomizableOptional<T> &Y) {
237   return Y && X < *Y;
238 }
239 
240 template <typename T>
241 constexpr bool operator<=(const CustomizableOptional<T> &X, const T &Y) {
242   return !(Y < X);
243 }
244 
245 template <typename T>
246 constexpr bool operator<=(const T &X, const CustomizableOptional<T> &Y) {
247   return !(Y < X);
248 }
249 
250 template <typename T>
251 constexpr bool operator>(const CustomizableOptional<T> &X, const T &Y) {
252   return Y < X;
253 }
254 
255 template <typename T>
256 constexpr bool operator>(const T &X, const CustomizableOptional<T> &Y) {
257   return Y < X;
258 }
259 
260 template <typename T>
261 constexpr bool operator>=(const CustomizableOptional<T> &X, const T &Y) {
262   return !(X < Y);
263 }
264 
265 template <typename T>
266 constexpr bool operator>=(const T &X, const CustomizableOptional<T> &Y) {
267   return !(X < Y);
268 }
269 
270 } // namespace clang
271 
272 #endif // CLANG_BASIC_CUSTOMIZABLEOPTIONAL_H
273