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; |
35 | constexpr CustomizableOptional(std::nullopt_t) {} |
36 | |
37 | constexpr CustomizableOptional(const T &y) : Storage(std::in_place, y) {} |
38 | constexpr CustomizableOptional(const CustomizableOptional &O) = default; |
39 | |
40 | constexpr CustomizableOptional(T &&y) |
41 | : Storage(std::in_place, std::move(y)) {} |
42 | constexpr CustomizableOptional(CustomizableOptional &&O) = default; |
43 | |
44 | template <typename... ArgTypes> |
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>. |
49 | constexpr CustomizableOptional(const std::optional<T> &y) |
50 | : CustomizableOptional(y ? *y : CustomizableOptional()) {} |
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. |
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 | |
71 | void reset() { Storage.reset(); } |
72 | |
73 | LLVM_DEPRECATED("Use &*X instead." , "&*X" ) |
74 | constexpr const T *getPointer() const { return &Storage.value(); } |
75 | LLVM_DEPRECATED("Use &*X instead." , "&*X" ) |
76 | T *getPointer() { return &Storage.value(); } |
77 | LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead" , "*X" ) |
78 | constexpr const T &value() const & { return Storage.value(); } |
79 | LLVM_DEPRECATED("std::optional::value is throwing. Use *X instead" , "*X" ) |
80 | T &value() & { return Storage.value(); } |
81 | |
82 | constexpr explicit operator bool() const { return 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 | |
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" ) |
94 | T &&value() && { return std::move(Storage.value()); } |
95 | T &&operator*() && { return std::move(Storage.value()); } |
96 | |
97 | template <typename U> T value_or(U &&alt) && { |
98 | return has_value() ? std::move(operator*()) : std::forward<U>(alt); |
99 | } |
100 | |
101 | // Allow conversion to std::optional<T>. |
102 | explicit operator std::optional<T> &() const & { |
103 | return *this ? **this : std::optional<T>(); |
104 | } |
105 | explicit operator std::optional<T> &&() const && { |
106 | return *this ? std::move(**this) : std::optional<T>(); |
107 | } |
108 | }; |
109 | |
110 | template <typename T> |
111 | CustomizableOptional(const T &) -> CustomizableOptional<T>; |
112 | |
113 | template <class T> |
114 | llvm::hash_code hash_value(const CustomizableOptional<T> &O) { |
115 | return O ? llvm::hash_combine(true, *O) : llvm::hash_value(value: false); |
116 | } |
117 | |
118 | template <typename T, typename U> |
119 | constexpr bool operator==(const CustomizableOptional<T> &X, |
120 | const CustomizableOptional<U> &Y) { |
121 | if (X && Y) |
122 | return *X == *Y; |
123 | return X.has_value() == Y.has_value(); |
124 | } |
125 | |
126 | template <typename T, typename U> |
127 | constexpr bool operator!=(const CustomizableOptional<T> &X, |
128 | const CustomizableOptional<U> &Y) { |
129 | return !(X == Y); |
130 | } |
131 | |
132 | template <typename T, typename U> |
133 | constexpr bool operator<(const CustomizableOptional<T> &X, |
134 | const CustomizableOptional<U> &Y) { |
135 | if (X && Y) |
136 | return *X < *Y; |
137 | return X.has_value() < Y.has_value(); |
138 | } |
139 | |
140 | template <typename T, typename U> |
141 | constexpr bool operator<=(const CustomizableOptional<T> &X, |
142 | const CustomizableOptional<U> &Y) { |
143 | return !(Y < X); |
144 | } |
145 | |
146 | template <typename T, typename U> |
147 | constexpr bool operator>(const CustomizableOptional<T> &X, |
148 | const CustomizableOptional<U> &Y) { |
149 | return Y < X; |
150 | } |
151 | |
152 | template <typename T, typename U> |
153 | constexpr bool operator>=(const CustomizableOptional<T> &X, |
154 | const CustomizableOptional<U> &Y) { |
155 | return !(X < Y); |
156 | } |
157 | |
158 | template <typename T> |
159 | constexpr bool operator==(const CustomizableOptional<T> &X, std::nullopt_t) { |
160 | return !X; |
161 | } |
162 | |
163 | template <typename T> |
164 | constexpr bool operator==(std::nullopt_t, const CustomizableOptional<T> &X) { |
165 | return X == std::nullopt; |
166 | } |
167 | |
168 | template <typename T> |
169 | constexpr bool operator!=(const CustomizableOptional<T> &X, std::nullopt_t) { |
170 | return !(X == std::nullopt); |
171 | } |
172 | |
173 | template <typename T> |
174 | constexpr bool operator!=(std::nullopt_t, const CustomizableOptional<T> &X) { |
175 | return X != std::nullopt; |
176 | } |
177 | |
178 | template <typename T> |
179 | constexpr bool operator<(const CustomizableOptional<T> &, std::nullopt_t) { |
180 | return false; |
181 | } |
182 | |
183 | template <typename T> |
184 | constexpr bool operator<(std::nullopt_t, const CustomizableOptional<T> &X) { |
185 | return X.has_value(); |
186 | } |
187 | |
188 | template <typename T> |
189 | constexpr bool operator<=(const CustomizableOptional<T> &X, std::nullopt_t) { |
190 | return !(std::nullopt < X); |
191 | } |
192 | |
193 | template <typename T> |
194 | constexpr bool operator<=(std::nullopt_t, const CustomizableOptional<T> &X) { |
195 | return !(X < std::nullopt); |
196 | } |
197 | |
198 | template <typename T> |
199 | constexpr bool operator>(const CustomizableOptional<T> &X, std::nullopt_t) { |
200 | return std::nullopt < X; |
201 | } |
202 | |
203 | template <typename T> |
204 | constexpr bool operator>(std::nullopt_t, const CustomizableOptional<T> &X) { |
205 | return X < std::nullopt; |
206 | } |
207 | |
208 | template <typename T> |
209 | constexpr bool operator>=(const CustomizableOptional<T> &X, std::nullopt_t) { |
210 | return std::nullopt <= X; |
211 | } |
212 | |
213 | template <typename T> |
214 | constexpr bool operator>=(std::nullopt_t, const CustomizableOptional<T> &X) { |
215 | return X <= std::nullopt; |
216 | } |
217 | |
218 | template <typename T> |
219 | constexpr bool operator==(const CustomizableOptional<T> &X, const T &Y) { |
220 | return X && *X == Y; |
221 | } |
222 | |
223 | template <typename T> |
224 | constexpr bool operator==(const T &X, const CustomizableOptional<T> &Y) { |
225 | return Y && X == *Y; |
226 | } |
227 | |
228 | template <typename T> |
229 | constexpr bool operator!=(const CustomizableOptional<T> &X, const T &Y) { |
230 | return !(X == Y); |
231 | } |
232 | |
233 | template <typename T> |
234 | constexpr bool operator!=(const T &X, const CustomizableOptional<T> &Y) { |
235 | return !(X == Y); |
236 | } |
237 | |
238 | template <typename T> |
239 | constexpr bool operator<(const CustomizableOptional<T> &X, const T &Y) { |
240 | return !X || *X < Y; |
241 | } |
242 | |
243 | template <typename T> |
244 | constexpr bool operator<(const T &X, const CustomizableOptional<T> &Y) { |
245 | return Y && X < *Y; |
246 | } |
247 | |
248 | template <typename T> |
249 | constexpr bool operator<=(const CustomizableOptional<T> &X, const T &Y) { |
250 | return !(Y < X); |
251 | } |
252 | |
253 | template <typename T> |
254 | constexpr bool operator<=(const T &X, const CustomizableOptional<T> &Y) { |
255 | return !(Y < X); |
256 | } |
257 | |
258 | template <typename T> |
259 | constexpr bool operator>(const CustomizableOptional<T> &X, const T &Y) { |
260 | return Y < X; |
261 | } |
262 | |
263 | template <typename T> |
264 | constexpr bool operator>(const T &X, const CustomizableOptional<T> &Y) { |
265 | return Y < X; |
266 | } |
267 | |
268 | template <typename T> |
269 | constexpr bool operator>=(const CustomizableOptional<T> &X, const T &Y) { |
270 | return !(X < Y); |
271 | } |
272 | |
273 | template <typename T> |
274 | constexpr bool operator>=(const T &X, const CustomizableOptional<T> &Y) { |
275 | return !(X < Y); |
276 | } |
277 | |
278 | } // namespace clang |
279 | |
280 | #endif // CLANG_BASIC_CUSTOMIZABLEOPTIONAL_H |
281 | |