diff --git a/libc/src/__support/CPP/optional.h b/libc/src/__support/CPP/optional.h --- a/libc/src/__support/CPP/optional.h +++ b/libc/src/__support/CPP/optional.h @@ -32,39 +32,82 @@ // in_place that can be used in the constructor. LIBC_INLINE_VAR 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; +template ::value> +struct Storage { + union { + char empty; + U stored_value; + }; + + LIBC_INLINE constexpr Storage() : empty() {} + template + LIBC_INLINE constexpr explicit Storage(in_place_t, Args &&...args) + : stored_value(forward(args)...) {} + + LIBC_INLINE ~Storage() { this->stored_value.~U(); } +}; - public: - LIBC_INLINE ~OptionalStorage() { reset(); } +template struct Storage { + union { + char empty; + U stored_value; + }; - LIBC_INLINE constexpr OptionalStorage() : empty(), in_use(false) {} + LIBC_INLINE constexpr Storage() : empty() {} + template + LIBC_INLINE constexpr explicit Storage(in_place_t, Args &&...args) + : stored_value(forward(args)...) {} +}; - template - LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) - : stored_value(forward(args)...), in_use(true) {} +template struct OptionalStorageBase { + Storage storage; + bool in_use = false; - LIBC_INLINE void reset() { - if (in_use) - stored_value.~U(); - in_use = false; - } + LIBC_INLINE ~OptionalStorageBase() = default; + LIBC_INLINE constexpr OptionalStorageBase() = default; - LIBC_INLINE constexpr bool has_value() const { return in_use; } + template + LIBC_INLINE constexpr OptionalStorageBase(in_place_t, ArgTypes &&...Args) + : storage(in_place, forward(Args)...), in_use(true) {} - 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); } - }; + LIBC_INLINE constexpr void reset() { + if (in_use) + storage.stored_value.~T(); + in_use = false; + } + + LIBC_INLINE constexpr bool has_value() const { return in_use; } + + LIBC_INLINE constexpr T &value() & { return this->storage.stored_value; } + LIBC_INLINE constexpr T const &value() const & { + return this->storage.stored_value; + } + LIBC_INLINE constexpr T &&value() && { + return move(this->storage.stored_value); + } +}; + +// Class template that manages the storage for optionals. +template ::value> +struct OptionalStorage : OptionalStorageBase { + using OptionalStorageBase::OptionalStorageBase; + LIBC_INLINE constexpr OptionalStorage() = default; + + // Destructor needs to destroy the contained value: + LIBC_INLINE ~OptionalStorage() { this->reset(); } +}; + +// storage for optionals with trivial destructors. +template +struct OptionalStorage : OptionalStorageBase { + using OptionalStorageBase::OptionalStorageBase; +}; +// 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 { OptionalStorage storage; public: @@ -81,40 +124,33 @@ LIBC_INLINE constexpr optional(in_place_t, ArgTypes &&...Args) : storage(in_place, forward(Args)...) {} - LIBC_INLINE optional &operator=(T &&t) { + LIBC_INLINE constexpr 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 constexpr optional &operator=(optional &&) = default; - LIBC_INLINE optional &operator=(const T &t) { + LIBC_INLINE constexpr optional &operator=(const T &t) { storage = t; return *this; } - LIBC_INLINE optional &operator=(const optional &) = default; + LIBC_INLINE constexpr optional &operator=(const optional &) = default; - LIBC_INLINE void reset() { storage.reset(); } + LIBC_INLINE constexpr void reset() { storage.reset(); } LIBC_INLINE constexpr const T &value() const & { return storage.value(); } - LIBC_INLINE T &value() & { return storage.value(); } + + LIBC_INLINE constexpr 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 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 constexpr T &operator*() & { return value(); } - LIBC_INLINE T &&value() && { return move(storage.value()); } - LIBC_INLINE T &&operator*() && { return move(storage.value()); } + LIBC_INLINE constexpr T &&value() && { return move(storage.value()); } + LIBC_INLINE constexpr T &&operator*() && { return move(storage.value()); } }; } // namespace cpp diff --git a/libc/src/__support/CPP/type_traits.h b/libc/src/__support/CPP/type_traits.h --- a/libc/src/__support/CPP/type_traits.h +++ b/libc/src/__support/CPP/type_traits.h @@ -214,6 +214,10 @@ details::void_t( declval()))>> = true; +template +struct is_trivially_destructible + : public integral_constant {}; + } // namespace cpp } // namespace __llvm_libc