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