1 //===- Optional.h - Simple variant for passing optional values --*- 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 // This file provides Optional, a template class modeled in the spirit of
10 // OCaml's 'opt' variant. The idea is to strongly type whether or not
11 // a value can be optional.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_ADT_OPTIONAL_H
16 #define LLVM_ADT_OPTIONAL_H
17
18 #include "llvm/ADT/Hashing.h"
19 #include "llvm/ADT/None.h"
20 #include "llvm/ADT/STLForwardCompat.h"
21 #include "llvm/Support/Compiler.h"
22 #include "llvm/Support/type_traits.h"
23 #include <cassert>
24 #include <memory>
25 #include <new>
26 #include <utility>
27
28 namespace llvm {
29
30 class raw_ostream;
31
32 namespace optional_detail {
33
34 /// Storage for any type.
35 //
36 // The specialization condition intentionally uses
37 // llvm::is_trivially_copy_constructible instead of
38 // std::is_trivially_copy_constructible. GCC versions prior to 7.4 may
39 // instantiate the copy constructor of `T` when
40 // std::is_trivially_copy_constructible is instantiated. This causes
41 // compilation to fail if we query the trivially copy constructible property of
42 // a class which is not copy constructible.
43 //
44 // The current implementation of OptionalStorage insists that in order to use
45 // the trivial specialization, the value_type must be trivially copy
46 // constructible and trivially copy assignable due to =default implementations
47 // of the copy/move constructor/assignment. It does not follow that this is
48 // necessarily the case std::is_trivially_copyable is true (hence the expanded
49 // specialization condition).
50 //
51 // The move constructible / assignable conditions emulate the remaining behavior
52 // of std::is_trivially_copyable.
53 template <typename T, bool = (llvm::is_trivially_copy_constructible<T>::value &&
54 std::is_trivially_copy_assignable<T>::value &&
55 (std::is_trivially_move_constructible<T>::value ||
56 !std::is_move_constructible<T>::value) &&
57 (std::is_trivially_move_assignable<T>::value ||
58 !std::is_move_assignable<T>::value))>
59 class OptionalStorage {
60 union {
61 char empty;
62 T value;
63 };
64 bool hasVal;
65
66 public:
~OptionalStorage()67 ~OptionalStorage() { reset(); }
68
OptionalStorage()69 constexpr OptionalStorage() noexcept : empty(), hasVal(false) {}
70
OptionalStorage(OptionalStorage const & other)71 constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() {
72 if (other.hasValue()) {
73 emplace(other.value);
74 }
75 }
OptionalStorage(OptionalStorage && other)76 constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() {
77 if (other.hasValue()) {
78 emplace(std::move(other.value));
79 }
80 }
81
82 template <class... Args>
OptionalStorage(in_place_t,Args &&...args)83 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
84 : value(std::forward<Args>(args)...), hasVal(true) {}
85
reset()86 void reset() noexcept {
87 if (hasVal) {
88 value.~T();
89 hasVal = false;
90 }
91 }
92
hasValue()93 constexpr bool hasValue() const noexcept { return hasVal; }
94
getValue()95 T &getValue() LLVM_LVALUE_FUNCTION noexcept {
96 assert(hasVal);
97 return value;
98 }
getValue()99 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
100 assert(hasVal);
101 return value;
102 }
103 #if LLVM_HAS_RVALUE_REFERENCE_THIS
getValue()104 T &&getValue() && noexcept {
105 assert(hasVal);
106 return std::move(value);
107 }
108 #endif
109
emplace(Args &&...args)110 template <class... Args> void emplace(Args &&... args) {
111 reset();
112 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
113 hasVal = true;
114 }
115
116 OptionalStorage &operator=(T const &y) {
117 if (hasValue()) {
118 value = y;
119 } else {
120 ::new ((void *)std::addressof(value)) T(y);
121 hasVal = true;
122 }
123 return *this;
124 }
125 OptionalStorage &operator=(T &&y) {
126 if (hasValue()) {
127 value = std::move(y);
128 } else {
129 ::new ((void *)std::addressof(value)) T(std::move(y));
130 hasVal = true;
131 }
132 return *this;
133 }
134
135 OptionalStorage &operator=(OptionalStorage const &other) {
136 if (other.hasValue()) {
137 if (hasValue()) {
138 value = other.value;
139 } else {
140 ::new ((void *)std::addressof(value)) T(other.value);
141 hasVal = true;
142 }
143 } else {
144 reset();
145 }
146 return *this;
147 }
148
149 OptionalStorage &operator=(OptionalStorage &&other) {
150 if (other.hasValue()) {
151 if (hasValue()) {
152 value = std::move(other.value);
153 } else {
154 ::new ((void *)std::addressof(value)) T(std::move(other.value));
155 hasVal = true;
156 }
157 } else {
158 reset();
159 }
160 return *this;
161 }
162 };
163
164 template <typename T> class OptionalStorage<T, true> {
165 union {
166 char empty;
167 T value;
168 };
169 bool hasVal = false;
170
171 public:
172 ~OptionalStorage() = default;
173
OptionalStorage()174 constexpr OptionalStorage() noexcept : empty{} {}
175
176 constexpr OptionalStorage(OptionalStorage const &other) = default;
177 constexpr OptionalStorage(OptionalStorage &&other) = default;
178
179 OptionalStorage &operator=(OptionalStorage const &other) = default;
180 OptionalStorage &operator=(OptionalStorage &&other) = default;
181
182 template <class... Args>
OptionalStorage(in_place_t,Args &&...args)183 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
184 : value(std::forward<Args>(args)...), hasVal(true) {}
185
reset()186 void reset() noexcept {
187 if (hasVal) {
188 value.~T();
189 hasVal = false;
190 }
191 }
192
hasValue()193 constexpr bool hasValue() const noexcept { return hasVal; }
194
getValue()195 T &getValue() LLVM_LVALUE_FUNCTION noexcept {
196 assert(hasVal);
197 return value;
198 }
getValue()199 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept {
200 assert(hasVal);
201 return value;
202 }
203 #if LLVM_HAS_RVALUE_REFERENCE_THIS
getValue()204 T &&getValue() && noexcept {
205 assert(hasVal);
206 return std::move(value);
207 }
208 #endif
209
emplace(Args &&...args)210 template <class... Args> void emplace(Args &&... args) {
211 reset();
212 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
213 hasVal = true;
214 }
215
216 OptionalStorage &operator=(T const &y) {
217 if (hasValue()) {
218 value = y;
219 } else {
220 ::new ((void *)std::addressof(value)) T(y);
221 hasVal = true;
222 }
223 return *this;
224 }
225 OptionalStorage &operator=(T &&y) {
226 if (hasValue()) {
227 value = std::move(y);
228 } else {
229 ::new ((void *)std::addressof(value)) T(std::move(y));
230 hasVal = true;
231 }
232 return *this;
233 }
234 };
235
236 } // namespace optional_detail
237
238 template <typename T> class Optional {
239 optional_detail::OptionalStorage<T> Storage;
240
241 public:
242 using value_type = T;
243
Optional()244 constexpr Optional() {}
Optional(NoneType)245 constexpr Optional(NoneType) {}
246
Optional(const T & y)247 constexpr Optional(const T &y) : Storage(in_place, y) {}
248 constexpr Optional(const Optional &O) = default;
249
Optional(T && y)250 constexpr Optional(T &&y) : Storage(in_place, std::move(y)) {}
251 constexpr Optional(Optional &&O) = default;
252
253 template <typename... ArgTypes>
Optional(in_place_t,ArgTypes &&...Args)254 constexpr Optional(in_place_t, ArgTypes &&...Args)
255 : Storage(in_place, std::forward<ArgTypes>(Args)...) {}
256
257 Optional &operator=(T &&y) {
258 Storage = std::move(y);
259 return *this;
260 }
261 Optional &operator=(Optional &&O) = default;
262
263 /// Create a new object by constructing it in place with the given arguments.
emplace(ArgTypes &&...Args)264 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
265 Storage.emplace(std::forward<ArgTypes>(Args)...);
266 }
267
create(const T * y)268 static constexpr Optional create(const T *y) {
269 return y ? Optional(*y) : Optional();
270 }
271
272 Optional &operator=(const T &y) {
273 Storage = y;
274 return *this;
275 }
276 Optional &operator=(const Optional &O) = default;
277
reset()278 void reset() { Storage.reset(); }
279
getPointer()280 constexpr const T *getPointer() const { return &Storage.getValue(); }
getPointer()281 T *getPointer() { return &Storage.getValue(); }
getValue()282 constexpr const T &getValue() const LLVM_LVALUE_FUNCTION {
283 return Storage.getValue();
284 }
getValue()285 T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); }
286
287 constexpr explicit operator bool() const { return hasValue(); }
hasValue()288 constexpr bool hasValue() const { return Storage.hasValue(); }
289 constexpr const T *operator->() const { return getPointer(); }
290 T *operator->() { return getPointer(); }
291 constexpr const T &operator*() const LLVM_LVALUE_FUNCTION {
292 return getValue();
293 }
294 T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); }
295
296 template <typename U>
getValueOr(U && value)297 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
298 return hasValue() ? getValue() : std::forward<U>(value);
299 }
300
301 /// Apply a function to the value if present; otherwise return None.
302 template <class Function>
303 auto map(const Function &F) const LLVM_LVALUE_FUNCTION
304 -> Optional<decltype(F(getValue()))> {
305 if (*this) return F(getValue());
306 return None;
307 }
308
309 #if LLVM_HAS_RVALUE_REFERENCE_THIS
getValue()310 T &&getValue() && { return std::move(Storage.getValue()); }
311 T &&operator*() && { return std::move(Storage.getValue()); }
312
313 template <typename U>
getValueOr(U && value)314 T getValueOr(U &&value) && {
315 return hasValue() ? std::move(getValue()) : std::forward<U>(value);
316 }
317
318 /// Apply a function to the value if present; otherwise return None.
319 template <class Function>
320 auto map(const Function &F) &&
321 -> Optional<decltype(F(std::move(*this).getValue()))> {
322 if (*this) return F(std::move(*this).getValue());
323 return None;
324 }
325 #endif
326 };
327
hash_value(const Optional<T> & O)328 template <class T> llvm::hash_code hash_value(const Optional<T> &O) {
329 return O ? hash_combine(true, *O) : hash_value(false);
330 }
331
332 template <typename T, typename U>
333 constexpr bool operator==(const Optional<T> &X, const Optional<U> &Y) {
334 if (X && Y)
335 return *X == *Y;
336 return X.hasValue() == Y.hasValue();
337 }
338
339 template <typename T, typename U>
340 constexpr bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
341 return !(X == Y);
342 }
343
344 template <typename T, typename U>
345 constexpr bool operator<(const Optional<T> &X, const Optional<U> &Y) {
346 if (X && Y)
347 return *X < *Y;
348 return X.hasValue() < Y.hasValue();
349 }
350
351 template <typename T, typename U>
352 constexpr bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
353 return !(Y < X);
354 }
355
356 template <typename T, typename U>
357 constexpr bool operator>(const Optional<T> &X, const Optional<U> &Y) {
358 return Y < X;
359 }
360
361 template <typename T, typename U>
362 constexpr bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
363 return !(X < Y);
364 }
365
366 template <typename T>
367 constexpr bool operator==(const Optional<T> &X, NoneType) {
368 return !X;
369 }
370
371 template <typename T>
372 constexpr bool operator==(NoneType, const Optional<T> &X) {
373 return X == None;
374 }
375
376 template <typename T>
377 constexpr bool operator!=(const Optional<T> &X, NoneType) {
378 return !(X == None);
379 }
380
381 template <typename T>
382 constexpr bool operator!=(NoneType, const Optional<T> &X) {
383 return X != None;
384 }
385
386 template <typename T> constexpr bool operator<(const Optional<T> &, NoneType) {
387 return false;
388 }
389
390 template <typename T> constexpr bool operator<(NoneType, const Optional<T> &X) {
391 return X.hasValue();
392 }
393
394 template <typename T>
395 constexpr bool operator<=(const Optional<T> &X, NoneType) {
396 return !(None < X);
397 }
398
399 template <typename T>
400 constexpr bool operator<=(NoneType, const Optional<T> &X) {
401 return !(X < None);
402 }
403
404 template <typename T> constexpr bool operator>(const Optional<T> &X, NoneType) {
405 return None < X;
406 }
407
408 template <typename T> constexpr bool operator>(NoneType, const Optional<T> &X) {
409 return X < None;
410 }
411
412 template <typename T>
413 constexpr bool operator>=(const Optional<T> &X, NoneType) {
414 return None <= X;
415 }
416
417 template <typename T>
418 constexpr bool operator>=(NoneType, const Optional<T> &X) {
419 return X <= None;
420 }
421
422 template <typename T>
423 constexpr bool operator==(const Optional<T> &X, const T &Y) {
424 return X && *X == Y;
425 }
426
427 template <typename T>
428 constexpr bool operator==(const T &X, const Optional<T> &Y) {
429 return Y && X == *Y;
430 }
431
432 template <typename T>
433 constexpr bool operator!=(const Optional<T> &X, const T &Y) {
434 return !(X == Y);
435 }
436
437 template <typename T>
438 constexpr bool operator!=(const T &X, const Optional<T> &Y) {
439 return !(X == Y);
440 }
441
442 template <typename T>
443 constexpr bool operator<(const Optional<T> &X, const T &Y) {
444 return !X || *X < Y;
445 }
446
447 template <typename T>
448 constexpr bool operator<(const T &X, const Optional<T> &Y) {
449 return Y && X < *Y;
450 }
451
452 template <typename T>
453 constexpr bool operator<=(const Optional<T> &X, const T &Y) {
454 return !(Y < X);
455 }
456
457 template <typename T>
458 constexpr bool operator<=(const T &X, const Optional<T> &Y) {
459 return !(Y < X);
460 }
461
462 template <typename T>
463 constexpr bool operator>(const Optional<T> &X, const T &Y) {
464 return Y < X;
465 }
466
467 template <typename T>
468 constexpr bool operator>(const T &X, const Optional<T> &Y) {
469 return Y < X;
470 }
471
472 template <typename T>
473 constexpr bool operator>=(const Optional<T> &X, const T &Y) {
474 return !(X < Y);
475 }
476
477 template <typename T>
478 constexpr bool operator>=(const T &X, const Optional<T> &Y) {
479 return !(X < Y);
480 }
481
482 raw_ostream &operator<<(raw_ostream &OS, NoneType);
483
484 template <typename T, typename = decltype(std::declval<raw_ostream &>()
485 << std::declval<const T &>())>
486 raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) {
487 if (O)
488 OS << *O;
489 else
490 OS << None;
491 return OS;
492 }
493
494 } // end namespace llvm
495
496 #endif // LLVM_ADT_OPTIONAL_H
497