1 //===-- Standalone implementation of std::optional --------------*- 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 LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H 10 #define LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H 11 12 #include "src/__support/CPP/type_traits.h" 13 #include "src/__support/CPP/utility.h" 14 #include "src/__support/macros/attributes.h" 15 16 namespace LIBC_NAMESPACE { 17 namespace cpp { 18 19 // Trivial nullopt_t struct. 20 struct nullopt_t { 21 LIBC_INLINE constexpr explicit nullopt_t() = default; 22 }; 23 24 // nullopt that can be used and returned. 25 LIBC_INLINE_VAR constexpr nullopt_t nullopt{}; 26 27 // This is very simple implementation of the std::optional class. It makes 28 // several assumptions that the underlying type is trivially constructible, 29 // copyable, or movable. 30 template <typename T> class optional { 31 template <typename U, bool = !is_trivially_destructible<U>::value> 32 struct OptionalStorage { 33 union { 34 char empty; 35 U stored_value; 36 }; 37 38 bool in_use = false; 39 ~OptionalStorageOptionalStorage40 LIBC_INLINE ~OptionalStorage() { reset(); } 41 OptionalStorageOptionalStorage42 LIBC_INLINE constexpr OptionalStorage() : empty() {} 43 44 template <typename... Args> OptionalStorageOptionalStorage45 LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) 46 : stored_value(forward<Args>(args)...) {} 47 resetOptionalStorage48 LIBC_INLINE constexpr void reset() { 49 if (in_use) 50 stored_value.~U(); 51 in_use = false; 52 } 53 }; 54 55 // The only difference is that this type U doesn't have a nontrivial 56 // destructor. 57 template <typename U> struct OptionalStorage<U, false> { 58 union { 59 char empty; 60 U stored_value; 61 }; 62 63 bool in_use = false; 64 65 LIBC_INLINE constexpr OptionalStorage() : empty() {} 66 67 template <typename... Args> 68 LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) 69 : stored_value(forward<Args>(args)...) {} 70 71 LIBC_INLINE constexpr void reset() { in_use = false; } 72 }; 73 74 OptionalStorage<T> storage; 75 76 public: 77 LIBC_INLINE constexpr optional() = default; 78 LIBC_INLINE constexpr optional(nullopt_t) {} 79 80 LIBC_INLINE constexpr optional(const T &t) : storage(in_place, t) { 81 storage.in_use = true; 82 } 83 LIBC_INLINE constexpr optional(const optional &) = default; 84 85 LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) { 86 storage.in_use = true; 87 } 88 LIBC_INLINE constexpr optional(optional &&O) = default; 89 90 template <typename... ArgTypes> 91 LIBC_INLINE constexpr optional(in_place_t, ArgTypes &&...Args) 92 : storage(in_place, forward<ArgTypes>(Args)...) { 93 storage.in_use = true; 94 } 95 96 LIBC_INLINE constexpr optional &operator=(T &&t) { 97 storage = move(t); 98 return *this; 99 } 100 LIBC_INLINE constexpr optional &operator=(optional &&) = default; 101 102 LIBC_INLINE constexpr optional &operator=(const T &t) { 103 storage = t; 104 return *this; 105 } 106 LIBC_INLINE constexpr optional &operator=(const optional &) = default; 107 108 LIBC_INLINE constexpr void reset() { storage.reset(); } 109 110 LIBC_INLINE constexpr const T &value() const & { 111 return storage.stored_value; 112 } 113 114 LIBC_INLINE constexpr T &value() & { return storage.stored_value; } 115 116 LIBC_INLINE constexpr explicit operator bool() const { 117 return storage.in_use; 118 } 119 LIBC_INLINE constexpr bool has_value() const { return storage.in_use; } 120 LIBC_INLINE constexpr const T *operator->() const { 121 return &storage.stored_value; 122 } 123 LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; } 124 LIBC_INLINE constexpr const T &operator*() const & { 125 return storage.stored_value; 126 } 127 LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; } 128 129 LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); } 130 LIBC_INLINE constexpr T &&operator*() && { 131 return move(storage.stored_value); 132 } 133 }; 134 135 } // namespace cpp 136 } // namespace LIBC_NAMESPACE 137 138 #endif // LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H 139