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