//===-- Standalone implementation of std::optional --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H #define LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H #include "src/__support/CPP/type_traits.h" #include "src/__support/CPP/utility.h" #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { namespace cpp { // Trivial nullopt_t struct. struct nullopt_t { LIBC_INLINE constexpr explicit nullopt_t() = default; }; // nullopt that can be used and returned. LIBC_INLINE_VAR constexpr nullopt_t nullopt{}; // This is very simple implementation of the std::optional class. It makes // several assumptions that the underlying type is trivially constructible, // copyable, or movable. template class optional { template ::value> struct OptionalStorage { union { char empty; U stored_value; }; bool in_use = false; LIBC_INLINE ~OptionalStorage() { reset(); } LIBC_INLINE constexpr OptionalStorage() : empty() {} template LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) : stored_value(forward(args)...) {} LIBC_INLINE constexpr void reset() { if (in_use) stored_value.~U(); in_use = false; } }; // The only difference is that this type U doesn't have a nontrivial // destructor. template struct OptionalStorage { union { char empty; U stored_value; }; bool in_use = false; LIBC_INLINE constexpr OptionalStorage() : empty() {} template LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) : stored_value(forward(args)...) {} LIBC_INLINE constexpr void reset() { in_use = false; } }; OptionalStorage storage; public: LIBC_INLINE constexpr optional() = default; LIBC_INLINE constexpr optional(nullopt_t) {} LIBC_INLINE constexpr optional(const T &t) : storage(in_place, t) { storage.in_use = true; } LIBC_INLINE constexpr optional(const optional &) = default; LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) { storage.in_use = true; } LIBC_INLINE constexpr optional(optional &&O) = default; template LIBC_INLINE constexpr optional(in_place_t, ArgTypes &&...Args) : storage(in_place, forward(Args)...) { storage.in_use = true; } LIBC_INLINE constexpr optional &operator=(T &&t) { storage = move(t); return *this; } LIBC_INLINE constexpr optional &operator=(optional &&) = default; LIBC_INLINE constexpr optional &operator=(const T &t) { storage = t; return *this; } LIBC_INLINE constexpr optional &operator=(const optional &) = default; LIBC_INLINE constexpr void reset() { storage.reset(); } LIBC_INLINE constexpr const T &value() const & { return storage.stored_value; } LIBC_INLINE constexpr T &value() & { return storage.stored_value; } LIBC_INLINE constexpr explicit operator bool() const { return storage.in_use; } LIBC_INLINE constexpr bool has_value() const { return storage.in_use; } LIBC_INLINE constexpr const T *operator->() const { return &storage.stored_value; } LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; } LIBC_INLINE constexpr const T &operator*() const & { return storage.stored_value; } LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; } LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); } LIBC_INLINE constexpr T &&operator*() && { return move(storage.stored_value); } }; } // namespace cpp } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H