xref: /netbsd-src/external/apache2/llvm/dist/llvm/include/llvm/ADT/Optional.h (revision 82d56013d7b633d116a93943de88e08335357a7c)
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