//===-- 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" namespace __llvm_libc { namespace cpp { // Trivial in_place_t struct. struct in_place_t { LIBC_INLINE explicit in_place_t() = default; }; // Trivial nullopt_t struct. struct nullopt_t { LIBC_INLINE explicit nullopt_t() = default; }; // nullopt that can be used and returned. inline constexpr nullopt_t nullopt{}; // in_place that can be used in the constructor. inline constexpr in_place_t in_place{}; // This is very simple implementation of the std::optional class. It makes // several assumptions that the underlying type is trivially constructable, // copyable, or movable. template class optional { template class OptionalStorage { union { char empty; U stored_value; }; bool in_use; public: LIBC_INLINE ~OptionalStorage() { reset(); } LIBC_INLINE constexpr OptionalStorage() : empty(), in_use(false) {} template LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) : stored_value(forward(args)...), in_use(true) {} LIBC_INLINE void reset() { if (in_use) stored_value.~U(); in_use = false; } LIBC_INLINE constexpr bool has_value() const { return in_use; } LIBC_INLINE U &value() & { return stored_value; } LIBC_INLINE constexpr U const &value() const & { return stored_value; } LIBC_INLINE U &&value() && { return move(stored_value); } }; 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) {} LIBC_INLINE constexpr optional(const optional &) = default; LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) {} LIBC_INLINE constexpr optional(optional &&O) = default; template LIBC_INLINE constexpr optional(in_place_t, ArgTypes &&...Args) : storage(in_place, forward(Args)...) {} LIBC_INLINE optional &operator=(T &&t) { storage = move(t); return *this; } LIBC_INLINE optional &operator=(optional &&) = default; LIBC_INLINE static constexpr optional create(const T *t) { return t ? optional(*t) : optional(); } LIBC_INLINE optional &operator=(const T &t) { storage = t; return *this; } LIBC_INLINE optional &operator=(const optional &) = default; LIBC_INLINE void reset() { storage.reset(); } LIBC_INLINE constexpr const T &value() const & { return storage.value(); } LIBC_INLINE T &value() & { return storage.value(); } LIBC_INLINE constexpr explicit operator bool() const { return has_value(); } LIBC_INLINE constexpr bool has_value() const { return storage.has_value(); } LIBC_INLINE constexpr const T *operator->() const { return &storage.value(); } LIBC_INLINE T *operator->() { return &storage.value(); } LIBC_INLINE constexpr const T &operator*() const & { return value(); } LIBC_INLINE T &operator*() & { return value(); } template LIBC_INLINE constexpr T value_or(U &&value) const & { return has_value() ? value() : forward(value); } LIBC_INLINE T &&value() && { return move(storage.value()); } LIBC_INLINE T &&operator*() && { return move(storage.value()); } }; } // namespace cpp } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_SUPPORT_CPP_OPTIONAL_H