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 @@ -36,85 +36,93 @@ // several assumptions that the underlying type is trivially constructable, // copyable, or movable. template class optional { - template class OptionalStorage { + template ::value> + struct OptionalStorage { union { char empty; U stored_value; }; - bool in_use; - public: - LIBC_INLINE ~OptionalStorage() { reset(); } - - LIBC_INLINE constexpr OptionalStorage() : empty(), in_use(false) {} + LIBC_INLINE ~OptionalStorage() { stored_value.~U(); } + LIBC_INLINE constexpr OptionalStorage() : empty() {} template LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) - : stored_value(forward(args)...), in_use(true) {} + : stored_value(forward(args)...) {} + }; - LIBC_INLINE void reset() { - if (in_use) - stored_value.~U(); - in_use = false; - } + template struct OptionalStorage { + union { + char empty; + U stored_value; + }; - LIBC_INLINE constexpr bool has_value() const { return in_use; } + // The only difference is that this class doesn't have a destructor. + LIBC_INLINE constexpr OptionalStorage() : empty() {} - 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); } + template + LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) + : stored_value(forward(args)...) {} }; OptionalStorage storage; + bool in_use = false; 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 T &t) + : storage(in_place, t), in_use(true) {} LIBC_INLINE constexpr optional(const optional &) = default; - LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) {} + LIBC_INLINE constexpr optional(T &&t) + : storage(in_place, move(t)), 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_place, forward(Args)...), in_use(true) {} - 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() { + if (in_use) + storage.~OptionalStorage(); + in_use = false; + } - LIBC_INLINE constexpr const T &value() const & { return storage.value(); } - LIBC_INLINE T &value() & { return storage.value(); } + LIBC_INLINE constexpr const T &value() const & { + return storage.stored_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(); } + LIBC_INLINE constexpr T &value() & { return storage.stored_value; } - template LIBC_INLINE constexpr T value_or(U &&value) const & { - return has_value() ? value() : forward(value); + LIBC_INLINE constexpr explicit operator bool() const { return in_use; } + LIBC_INLINE constexpr bool has_value() const { return 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 T &&value() && { return move(storage.value()); } - LIBC_INLINE T &&operator*() && { return move(storage.value()); } + LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); } + LIBC_INLINE constexpr T &&operator*() && { + return move(storage.stored_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 @@ -11,6 +11,8 @@ #include "src/__support/macros/attributes.h" +#include // For size_t. + namespace __llvm_libc { namespace cpp { @@ -30,6 +32,8 @@ using true_type = cpp::integral_constant; using false_type = cpp::integral_constant; +template using bool_constant = integral_constant; + template struct is_trivially_copyable : public integral_constant {}; @@ -214,6 +218,128 @@ details::void_t( declval()))>> = true; +#if __has_builtin(__is_lvalue_reference) && \ + __has_builtin(__is_rvalue_reference) && __has_builtin(__is_reference) + +template +struct is_lvalue_reference : bool_constant<__is_lvalue_reference(T)> {}; +template +struct is_rvalue_reference : bool_constant<__is_rvalue_reference(T)> {}; +template struct is_reference : bool_constant<__is_reference(T)> {}; + +#else // __has_builtin(__is_lvalue_reference) && etc... + +template struct is_lvalue_reference : public false_type {}; +template struct is_lvalue_reference : public true_type {}; + +template struct is_rvalue_reference : public false_type {}; +template struct is_rvalue_reference : public true_type {}; + +template struct is_reference : public false_type {}; +template struct is_reference : public true_type {}; +template struct is_reference : public true_type {}; + +#endif // __has_builtin(__is_lvalue_reference) && etc... + +#if __has_builtin(__remove_all_extents) +template using __remove_all_extents_t = __remove_all_extents(T); +#else +template struct remove_all_extents { + typedef T type; +}; +template struct remove_all_extents { + typedef typename remove_all_extents::type type; +}; +template struct remove_all_extents { + typedef typename remove_all_extents::type type; +}; + +template +using __remove_all_extents_t = typename remove_all_extents::type; +#endif // __has_builtin(__remove_all_extents) + +#if __has_builtin(__is_function) + +template +struct is_function : integral_constant {}; + +#else + +template +struct is_function + : public integral_constant::value || + is_const::value)> {}; + +#endif // __has_builtin(__is_function) + +#if __has_builtin(__is_destructible) + +template +struct is_destructible : bool_constant<__is_destructible(T)> {}; + +#else // __has_builtin(__is_destructible) + +// if it's a reference, return true +// if it's a function, return false +// if it's void, return false +// if it's an array of unknown bound, return false +// Otherwise, return "declval().~T()" is well-formed +// where T is remove_all_extents::type + +template struct __is_destructible_apply { + typedef int type; +}; + +template struct __is_destructor_wellformed { + template + static true_type __test( + typename __is_destructible_apply().~T1())>::type); + + template static false_type __test(...); + + static const bool value = decltype(__test(12))::value; +}; + +template struct __destructible_imp; + +template +struct __destructible_imp + : public integral_constant< + bool, __is_destructor_wellformed<__remove_all_extents_t>::value> { +}; + +template struct __destructible_imp : public true_type {}; + +template struct __destructible_false; +template +struct __destructible_false + : public __destructible_imp::value> {}; +template +struct __destructible_false : public false_type {}; + +template +struct is_destructible : public __destructible_false::value> { +}; +template struct is_destructible : public false_type {}; +template <> struct is_destructible : public false_type {}; + +#endif // __has_builtin(__is_destructible) + +#if __has_builtin(__is_trivially_destructible) + +template +struct is_trivially_destructible + : public integral_constant {}; + +#elif __has_builtin(__has_trivial_destructor) + +template +struct is_trivially_destructible + : public integral_constant< + bool, is_destructible::value &&__has_trivial_destructor(T)> {}; + +#endif // __has_builtin(__is_trivially_destructible) + } // namespace cpp } // namespace __llvm_libc