From 7ded638ea33b96d9fd628e2a5cbc06df12ede153 Mon Sep 17 00:00:00 2001 From: William Tran-Viet Date: Wed, 29 Jul 2026 23:12:15 -0400 Subject: [PATCH] [libc++] Granularize `` (#206644) Certain headers require `optional`, so it may be beneficial to split out `optional` and `optional`. This can allow consumers to only bring in the `optional` flavour it needs.. - Parcel out the respective pieces into their own header. - Certain sources rely on transitive includes brought in by ``, so they're kept there for now, and only tests have been fixed. --------- Co-authored-by: Louis Dionne --- libcxx/include/CMakeLists.txt | 9 + libcxx/include/__fwd/optional.h | 42 + libcxx/include/__optional/common.h | 97 ++ libcxx/include/__optional/comparison.h | 349 ++++ libcxx/include/__optional/hash.h | 47 + libcxx/include/__optional/make_optional.h | 91 + libcxx/include/__optional/nullopt_t.h | 40 + libcxx/include/__optional/optional.h | 757 +++++++++ libcxx/include/__optional/optional_ref.h | 357 ++++ libcxx/include/__optional/swap.h | 45 + libcxx/include/module.modulemap.in | 27 + libcxx/include/optional | 1492 +---------------- .../make_ostream_joiner.pass.cpp | 1 + .../ostream_joiner.op.assign.pass.cpp | 1 + .../derive.pass.cpp | 1 + .../optional.object.ctor/ctor.verify.cpp | 24 +- .../optional.object.ctor/deduct.verify.cpp | 2 +- ...al_requires_destructible_object.verify.cpp | 26 +- 18 files changed, 1903 insertions(+), 1505 deletions(-) create mode 100644 libcxx/include/__fwd/optional.h create mode 100644 libcxx/include/__optional/common.h create mode 100644 libcxx/include/__optional/comparison.h create mode 100644 libcxx/include/__optional/hash.h create mode 100644 libcxx/include/__optional/make_optional.h create mode 100644 libcxx/include/__optional/nullopt_t.h create mode 100644 libcxx/include/__optional/optional.h create mode 100644 libcxx/include/__optional/optional_ref.h create mode 100644 libcxx/include/__optional/swap.h diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 159418d5e8fc..5034d5f6fe95 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -472,6 +472,7 @@ set(files __fwd/mdspan.h __fwd/memory.h __fwd/memory_resource.h + __fwd/optional.h __fwd/ostream.h __fwd/pair.h __fwd/queue.h @@ -666,6 +667,14 @@ set(files __numeric/transform_exclusive_scan.h __numeric/transform_inclusive_scan.h __numeric/transform_reduce.h + __optional/common.h + __optional/comparison.h + __optional/hash.h + __optional/make_optional.h + __optional/nullopt_t.h + __optional/optional.h + __optional/optional_ref.h + __optional/swap.h __ostream/basic_ostream.h __ostream/print.h __ostream/put_character_sequence.h diff --git a/libcxx/include/__fwd/optional.h b/libcxx/include/__fwd/optional.h new file mode 100644 index 000000000000..fd1935c84c95 --- /dev/null +++ b/libcxx/include/__fwd/optional.h @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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 _LIBCPP___FWD_OPTIONAL_H +#define _LIBCPP___FWD_OPTIONAL_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class optional; + +# if _LIBCPP_STD_VER >= 26 +template +class optional<_Tp&>; +# endif + +template +optional(_Tp) -> optional<_Tp>; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FWD_OPTIONAL_H diff --git a/libcxx/include/__optional/common.h b/libcxx/include/__optional/common.h new file mode 100644 index 000000000000..5ddb993f3e37 --- /dev/null +++ b/libcxx/include/__optional/common.h @@ -0,0 +1,97 @@ +// -*- 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 _LIBCPP___OPTIONAL_COMMON_H +#define _LIBCPP___OPTIONAL_COMMON_H + +#include <__assert> +#include <__config> +#include <__exception/exception.h> +#include <__fwd/format.h> +#include <__ranges/enable_borrowed_range.h> +#include <__ranges/enable_view.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_reference.h> +#include <__verbose_abort> + +#include <__fwd/optional.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +namespace std // purposefully not using versioning namespace +{ + +class _LIBCPP_EXPORTED_FROM_ABI bad_optional_access : public exception { +public: + _LIBCPP_HIDE_FROM_ABI bad_optional_access() _NOEXCEPT = default; + _LIBCPP_HIDE_FROM_ABI bad_optional_access(const bad_optional_access&) _NOEXCEPT = default; + _LIBCPP_HIDE_FROM_ABI bad_optional_access& operator=(const bad_optional_access&) _NOEXCEPT = default; + // Get the key function ~bad_optional_access() into the dylib + ~bad_optional_access() _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; +}; + +} // namespace std + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +[[noreturn]] inline _LIBCPP_HIDE_FROM_ABI void __throw_bad_optional_access() { +# if _LIBCPP_HAS_EXCEPTIONS + throw bad_optional_access(); +# else + _LIBCPP_VERBOSE_ABORT("bad_optional_access was thrown in -fno-exceptions mode"); +# endif +} + +struct __optional_construct_from_invoke_tag {}; + +template +inline constexpr bool __is_std_optional_v = false; + +template +inline constexpr bool __is_std_optional_v> = true; + +template ::value> +struct __optional_storage_base; + +# if _LIBCPP_STD_VER < 26 +template +inline constexpr bool __is_valid_optional_contained_type = is_object_v<_Tp>; +# else +template +inline constexpr bool __is_valid_optional_contained_type = is_object_v<_Tp> || is_lvalue_reference_v<_Tp>; +# endif + +# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR + +template +constexpr bool ranges::enable_view> = true; + +template +constexpr range_format format_kind> = range_format::disabled; + +template +constexpr bool ranges::enable_borrowed_range> = true; + +# endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___OPTIONAL_COMMON_H diff --git a/libcxx/include/__optional/comparison.h b/libcxx/include/__optional/comparison.h new file mode 100644 index 000000000000..ba5cddb1acbf --- /dev/null +++ b/libcxx/include/__optional/comparison.h @@ -0,0 +1,349 @@ +//===----------------------------------------------------------------------===// +// +// 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 _LIBCPP___OPTIONAL_COMPARISON_H +#define _LIBCPP___OPTIONAL_COMPARISON_H + +#include <__compare/compare_three_way_result.h> +#include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> +#include <__config> +#include <__optional/nullopt_t.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_core_convertible.h> +#include <__type_traits/is_swappable.h> +#include <__utility/declval.h> + +#include <__fwd/optional.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +// [optional.relops] Relational operators + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() == std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const optional<_Up>& __y) { + if (static_cast(__x) != static_cast(__y)) + return false; + if (!static_cast(__x)) + return true; + return *__x == *__y; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() != std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const optional<_Up>& __y) { + if (static_cast(__x) != static_cast(__y)) + return true; + if (!static_cast(__x)) + return false; + return *__x != *__y; +} + +template < class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() < std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const optional<_Up>& __y) { + if (!static_cast(__y)) + return false; + if (!static_cast(__x)) + return true; + return *__x < *__y; +} + +template < class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() > std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const optional<_Up>& __y) { + if (!static_cast(__x)) + return false; + if (!static_cast(__y)) + return true; + return *__x > *__y; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() <= std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const optional<_Up>& __y) { + if (!static_cast(__x)) + return true; + if (!static_cast(__y)) + return false; + return *__x <= *__y; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() >= std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const optional<_Up>& __y) { + if (!static_cast(__y)) + return true; + if (!static_cast(__x)) + return false; + return *__x >= *__y; +} + +# if _LIBCPP_STD_VER >= 20 + +template _Up> +_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up> +operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) { + if (__x && __y) + return *__x <=> *__y; + return __x.has_value() <=> __y.has_value(); +} + +# endif // _LIBCPP_STD_VER >= 20 + +// [optional.nullops] Comparison with nullopt + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, nullopt_t) noexcept { + return !static_cast(__x); +} + +# if _LIBCPP_STD_VER <= 17 + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(nullopt_t, const optional<_Tp>& __x) noexcept { + return !static_cast(__x); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, nullopt_t) noexcept { + return static_cast(__x); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(nullopt_t, const optional<_Tp>& __x) noexcept { + return static_cast(__x); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>&, nullopt_t) noexcept { + return false; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(nullopt_t, const optional<_Tp>& __x) noexcept { + return static_cast(__x); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, nullopt_t) noexcept { + return !static_cast(__x); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(nullopt_t, const optional<_Tp>&) noexcept { + return true; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, nullopt_t) noexcept { + return static_cast(__x); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(nullopt_t, const optional<_Tp>&) noexcept { + return false; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>&, nullopt_t) noexcept { + return true; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(nullopt_t, const optional<_Tp>& __x) noexcept { + return !static_cast(__x); +} + +# else // _LIBCPP_STD_VER <= 17 + +template +_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept { + return __x.has_value() <=> false; +} + +# endif // _LIBCPP_STD_VER <= 17 + +// [optional.comp.with.t] Comparison with T + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() == std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v) { + if (__x.has_value()) + return *__x == __v; + return false; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() == std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x) { + if (__x.has_value()) + return __v == *__x; + return false; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() != std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v) { + if (__x.has_value()) + return *__x != __v; + return true; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() != std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x) { + if (__x.has_value()) + return __v != *__x; + return true; +} + +template < class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() < std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v) { + if (__x.has_value()) + return *__x < __v; + return true; +} + +template < class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() < std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x) { + if (__x.has_value()) + return __v < *__x; + return false; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() <= std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v) { + if (__x.has_value()) + return *__x <= __v; + return true; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() <= std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x) { + if (__x.has_value()) + return __v <= *__x; + return false; +} + +template < class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() > std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v) { + if (__x.has_value()) + return *__x > __v; + return false; +} + +template < class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() > std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x) { + if (__x.has_value()) + return __v > *__x; + return true; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() >= std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v) { + if (__x.has_value()) + return *__x >= __v; + return false; +} + +template < + class _Tp, + class _Up, + enable_if_t<__is_core_convertible_v() >= std::declval()), bool>, + int> = 0> +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x) { + if (__x.has_value()) + return __v >= *__x; + return true; +} + +# if _LIBCPP_STD_VER >= 20 + +template +concept __is_derived_from_optional = requires(const _Tp& __t) { [](const optional<_Up>&) {}(__t); }; + +template + requires(!__is_derived_from_optional<_Up>) && three_way_comparable_with<_Tp, _Up> +_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up> +operator<=>(const optional<_Tp>& __x, const _Up& __v) { + return __x.has_value() ? *__x <=> __v : strong_ordering::less; +} + +# endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___OPTIONAL_COMPARISON_H diff --git a/libcxx/include/__optional/hash.h b/libcxx/include/__optional/hash.h new file mode 100644 index 000000000000..fba655d6f8e7 --- /dev/null +++ b/libcxx/include/__optional/hash.h @@ -0,0 +1,47 @@ +// -*- 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 _LIBCPP___OPTIONAL_HASH_H +#define _LIBCPP___OPTIONAL_HASH_H + +#include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> +#include <__fwd/optional.h> +#include <__type_traits/remove_const.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct hash< __enable_hash_helper, remove_const_t<_Tp>> > { +# if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + _LIBCPP_DEPRECATED_IN_CXX17 typedef optional<_Tp> argument_type; + _LIBCPP_DEPRECATED_IN_CXX17 typedef size_t result_type; +# endif + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const optional<_Tp>& __opt) const { + return static_cast(__opt) ? hash>()(*__opt) : 0; + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS +#endif // _LIBCPP___OPTIONAL_HASH_H diff --git a/libcxx/include/__optional/make_optional.h b/libcxx/include/__optional/make_optional.h new file mode 100644 index 000000000000..9c403d913769 --- /dev/null +++ b/libcxx/include/__optional/make_optional.h @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// 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 _LIBCPP___OPTIONAL_MAKE_OPTIONAL_H +#define _LIBCPP___OPTIONAL_MAKE_OPTIONAL_H + +#include <__config> +#include <__fwd/optional.h> +#include <__type_traits/decay.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/reference_constructs_from_temporary.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> + +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct __make_optional_barrier_tag { + explicit __make_optional_barrier_tag() = default; +}; + +template +inline constexpr bool __is_constructible_for_optional_v = is_constructible_v<_Tp, _Args...>; + +template +struct __is_constructible_for_optional : bool_constant<__is_constructible_for_optional_v<_Tp, _Args...>> {}; + +template +inline constexpr bool __is_constructible_for_optional_initializer_list_v = + is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>; + +# if _LIBCPP_STD_VER >= 26 +template +inline constexpr bool __is_constructible_for_optional_v<_Tp&, _Args...> = false; + +template +inline constexpr bool __is_constructible_for_optional_v<_Tp&, _Arg> = + is_constructible_v<_Tp&, _Arg> && !reference_constructs_from_temporary_v<_Tp&, _Arg>; + +template +inline constexpr bool __is_constructible_for_optional_initializer_list_v<_Tp&, _Up, _Args...> = false; +# endif + +template < +# if _LIBCPP_STD_VER >= 26 + __make_optional_barrier_tag = __make_optional_barrier_tag{}, +# endif + class _Tp, + enable_if_t, _Tp>, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional> make_optional(_Tp&& __v) { + return optional>(std::forward<_Tp>(__v)); +} + +template , int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(_Args&&... __args) { + return optional<_Tp>(in_place, std::forward<_Args>(__args)...); +} + +template , int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> +make_optional(initializer_list<_Up> __il, _Args&&... __args) { + return optional<_Tp>(in_place, __il, std::forward<_Args>(__args)...); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___OPTIONAL_MAKE_OPTIONAL_H diff --git a/libcxx/include/__optional/nullopt_t.h b/libcxx/include/__optional/nullopt_t.h new file mode 100644 index 000000000000..afca31927254 --- /dev/null +++ b/libcxx/include/__optional/nullopt_t.h @@ -0,0 +1,40 @@ +// -*- 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 _LIBCPP___OPTIONAL_NULLOPT_T_H +#define _LIBCPP___OPTIONAL_NULLOPT_T_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct nullopt_t { + struct __secret_tag { + explicit __secret_tag() = default; + }; + _LIBCPP_HIDE_FROM_ABI constexpr explicit nullopt_t(__secret_tag, __secret_tag) noexcept {} +}; + +inline constexpr nullopt_t nullopt{nullopt_t::__secret_tag{}, nullopt_t::__secret_tag{}}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS +#endif // _LIBCPP___OPTIONAL_NULLOPT_T_H diff --git a/libcxx/include/__optional/optional.h b/libcxx/include/__optional/optional.h new file mode 100644 index 000000000000..4279adf1fbbb --- /dev/null +++ b/libcxx/include/__optional/optional.h @@ -0,0 +1,757 @@ +//===----------------------------------------------------------------------===// +// +// 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 _LIBCPP___OPTIONAL_OPTIONAL_H +#define _LIBCPP___OPTIONAL_OPTIONAL_H + +#include <__assert> +#include <__concepts/invocable.h> +#include <__config> +#include <__functional/invoke.h> +#include <__fwd/optional.h> +#include <__iterator/bounded_iter.h> +#include <__iterator/capacity_aware_iterator.h> +#include <__memory/addressof.h> +#include <__memory/construct_at.h> +#include <__optional/common.h> +#include <__optional/comparison.h> +#include <__optional/hash.h> +#include <__optional/nullopt_t.h> +#include <__optional/swap.h> +#include <__tuple/sfinae_helpers.h> +#include <__type_traits/add_pointer.h> +#include <__type_traits/conditional.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/decay.h> +#include <__type_traits/disjunction.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_destructible.h> +#include <__type_traits/is_nothrow_assignable.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_scalar.h> +#include <__type_traits/is_swappable.h> +#include <__type_traits/is_trivially_assignable.h> +#include <__type_traits/is_trivially_constructible.h> +#include <__type_traits/is_trivially_destructible.h> +#include <__type_traits/is_trivially_relocatable.h> +#include <__type_traits/negation.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_cvref.h> +#include <__type_traits/remove_reference.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template ::value> +struct __optional_destruct_base; + +template +struct __optional_destruct_base<_Tp, false> { + typedef _Tp value_type; + static_assert(is_object_v, "instantiation of optional with a non-object type is undefined behavior"); + union { + char __null_state_; + remove_cv_t __val_; + }; + bool __engaged_; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__optional_destruct_base() { + if (__engaged_) + __val_.~value_type(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base() noexcept : __null_state_(), __engaged_(false) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base(in_place_t, _Args&&... __args) + : __val_(std::forward<_Args>(__args)...), __engaged_(true) {} + +# if _LIBCPP_STD_VER >= 23 + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base( + __optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) + : __val_(std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)), __engaged_(true) {} +# endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { + if (__engaged_) { + __val_.~value_type(); + __engaged_ = false; + } + } +}; + +template +struct __optional_destruct_base<_Tp, true> { + typedef _Tp value_type; + static_assert(is_object_v, "instantiation of optional with a non-object type is undefined behavior"); + union { + char __null_state_; + remove_cv_t __val_; + }; + bool __engaged_; + + _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base() noexcept : __null_state_(), __engaged_(false) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base(in_place_t, _Args&&... __args) + : __val_(std::forward<_Args>(__args)...), __engaged_(true) {} + +# if _LIBCPP_STD_VER >= 23 + template + _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base( + __optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) + : __val_(std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)), __engaged_(true) {} +# endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { + if (__engaged_) { + __engaged_ = false; + } + } +}; + +template +struct __optional_storage_base : __optional_destruct_base<_Tp> { + using __base _LIBCPP_NODEBUG = __optional_destruct_base<_Tp>; + using value_type = _Tp; + using __base::__base; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__engaged_; } + + _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() & noexcept { return this->__val_; } + _LIBCPP_HIDE_FROM_ABI constexpr const value_type& __get() const& noexcept { return this->__val_; } + _LIBCPP_HIDE_FROM_ABI constexpr value_type&& __get() && noexcept { return std::move(this->__val_); } + _LIBCPP_HIDE_FROM_ABI constexpr const value_type&& __get() const&& noexcept { return std::move(this->__val_); } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_Args&&... __args) { + _LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage"); + std::__construct_at(std::addressof(this->__val_), std::forward<_Args>(__args)...); + this->__engaged_ = true; + } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_from(_That&& __opt) { + if (__opt.has_value()) + __construct(std::forward<_That>(__opt).__get()); + } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from(_That&& __opt) { + if (this->__engaged_ == __opt.has_value()) { + if (this->__engaged_) + static_cast<_Tp&>(this->__val_) = std::forward<_That>(__opt).__get(); + } else { + if (this->__engaged_) + this->reset(); + else + __construct(std::forward<_That>(__opt).__get()); + } + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void + __swap(__optional_storage_base& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) { + using std::swap; + if (this->has_value() == __rhs.has_value()) { + if (this->has_value()) + swap(this->__get(), __rhs.__get()); + } else { + if (this->has_value()) { + __rhs.__construct(std::move(this->__get())); + this->reset(); + } else { + this->__construct(std::move(__rhs.__get())); + __rhs.reset(); + } + } + } + + // [optional.observe] + _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); + return std::addressof(this->__get()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); + return std::addressof(this->__get()); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); + return this->__get(); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); + return this->__get(); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); + return std::move(this->__get()); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); + return std::move(this->__get()); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& { + if (!this->has_value()) + std::__throw_bad_optional_access(); + return this->__get(); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & { + if (!this->has_value()) + std::__throw_bad_optional_access(); + return this->__get(); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && { + if (!this->has_value()) + std::__throw_bad_optional_access(); + return std::move(this->__get()); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& { + if (!this->has_value()) + std::__throw_bad_optional_access(); + return std::move(this->__get()); + } +}; + +template > +struct __optional_copy_base : __optional_storage_base<_Tp> { + using __optional_storage_base<_Tp>::__optional_storage_base; +}; + +template +struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp> { + using __optional_storage_base<_Tp>::__optional_storage_base; + + _LIBCPP_HIDE_FROM_ABI __optional_copy_base() = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __optional_copy_base(const __optional_copy_base& __opt) { + this->__construct_from(__opt); + } + + _LIBCPP_HIDE_FROM_ABI __optional_copy_base(__optional_copy_base&&) = default; + _LIBCPP_HIDE_FROM_ABI __optional_copy_base& operator=(const __optional_copy_base&) = default; + _LIBCPP_HIDE_FROM_ABI __optional_copy_base& operator=(__optional_copy_base&&) = default; +}; + +template > +struct __optional_move_base : __optional_copy_base<_Tp> { + using __optional_copy_base<_Tp>::__optional_copy_base; +}; + +template +struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp> { + using value_type = _Tp; + using __optional_copy_base<_Tp>::__optional_copy_base; + + _LIBCPP_HIDE_FROM_ABI __optional_move_base() = default; + _LIBCPP_HIDE_FROM_ABI __optional_move_base(const __optional_move_base&) = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + __optional_move_base(__optional_move_base&& __opt) noexcept(is_nothrow_move_constructible_v) { + this->__construct_from(std::move(__opt)); + } + + _LIBCPP_HIDE_FROM_ABI __optional_move_base& operator=(const __optional_move_base&) = default; + _LIBCPP_HIDE_FROM_ABI __optional_move_base& operator=(__optional_move_base&&) = default; +}; + +template && is_trivially_copy_constructible_v<_Tp> && + is_trivially_copy_assignable_v<_Tp>)> +struct __optional_copy_assign_base : __optional_move_base<_Tp> { + using __optional_move_base<_Tp>::__optional_move_base; +}; + +template +struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp> { + using __optional_move_base<_Tp>::__optional_move_base; + + _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base() = default; + _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base(const __optional_copy_assign_base&) = default; + _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base(__optional_copy_assign_base&&) = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __optional_copy_assign_base& + operator=(const __optional_copy_assign_base& __opt) { + this->__assign_from(__opt); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default; +}; + +template && is_trivially_move_constructible_v<_Tp> && + is_trivially_move_assignable_v<_Tp>)> +struct __optional_move_assign_base : __optional_copy_assign_base<_Tp> { + using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base; +}; + +template +struct __optional_move_assign_base<_Tp, false> : __optional_copy_assign_base<_Tp> { + using value_type = _Tp; + using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base; + + _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base() = default; + _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base(const __optional_move_assign_base& __opt) = default; + _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base(__optional_move_assign_base&&) = default; + _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base& operator=(const __optional_move_assign_base&) = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __optional_move_assign_base& + operator=(__optional_move_assign_base&& __opt) noexcept( + is_nothrow_move_assignable_v && is_nothrow_move_constructible_v) { + this->__assign_from(std::move(__opt)); + return *this; + } +}; + +template +using __optional_sfinae_ctor_base_t _LIBCPP_NODEBUG = + __sfinae_ctor_base< is_copy_constructible<_Tp>::value, is_move_constructible<_Tp>::value >; + +template +using __optional_sfinae_assign_base_t _LIBCPP_NODEBUG = + __sfinae_assign_base< (is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Tp>), + (is_move_constructible_v<_Tp> && is_move_assignable_v<_Tp>)>; + +template +struct __optional_iterator_base : __optional_move_assign_base<_Tp> { + using __optional_move_assign_base<_Tp>::__optional_move_assign_base; +}; + +# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR + +template + requires is_object_v<_Tp> +struct __optional_iterator_base<_Tp> : __optional_move_assign_base<_Tp> { +private: + using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>; + using __const_pointer _LIBCPP_NODEBUG = add_pointer_t; + +public: + using __optional_move_assign_base<_Tp>::__optional_move_assign_base; + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + using iterator = __bounded_iter<__pointer>; + using const_iterator = __bounded_iter<__const_pointer>; +# else + using iterator = __capacity_aware_iterator<__pointer, optional<_Tp>, 1>; + using const_iterator = __capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>; +# endif + + // [optional.iterators], iterator support + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept { + auto* __ptr = std::addressof(this->__get()); + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0)); +# else + return std::__make_capacity_aware_iterator<__pointer, optional<_Tp>, 1>(__ptr); +# endif + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { + auto* __ptr = std::addressof(this->__get()); + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0)); +# else + return std::__make_capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>(__ptr); +# endif + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept { + return begin() + (this->has_value() ? 1 : 0); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { + return begin() + (this->has_value() ? 1 : 0); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR + +template +class _LIBCPP_DECLSPEC_EMPTY_BASES optional + : public __optional_iterator_base<_Tp>, + private __optional_sfinae_ctor_base_t<_Tp>, + private __optional_sfinae_assign_base_t<_Tp> { + using __base _LIBCPP_NODEBUG = __optional_iterator_base<_Tp>; + +public: + using value_type = __libcpp_remove_reference_t<_Tp>; + + using __trivially_relocatable _LIBCPP_NODEBUG = + conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>; + +private: + static_assert(!is_same_v, in_place_t>, "instantiation of optional with in_place_t is ill-formed"); + static_assert(!is_same_v, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed"); +# if _LIBCPP_STD_VER >= 26 + static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed"); +# else + static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed"); +# endif + static_assert(is_destructible_v<_Tp>, "instantiation of optional with a non-destructible type is ill-formed"); + static_assert(!is_array_v<_Tp>, "instantiation of optional with an array type is ill-formed"); + + // LWG2756: conditionally explicit conversion from _Up + struct _CheckOptionalArgsConstructor { + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() { + return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>; + } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() { + return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>; + } + }; + template + using _CheckOptionalArgsCtor _LIBCPP_NODEBUG = + _If< _IsNotSame<__remove_cvref_t<_Up>, in_place_t>::value && _IsNotSame<__remove_cvref_t<_Up>, optional>::value && + (!is_same_v, bool> || !__is_std_optional_v<__remove_cvref_t<_Up>>), + _CheckOptionalArgsConstructor, + __check_tuple_constructor_fail >; + template + struct _CheckOptionalLikeConstructor { + template > + using __check_constructible_from_opt _LIBCPP_NODEBUG = + _Or< is_constructible<_Tp, _Opt&>, + is_constructible<_Tp, _Opt const&>, + is_constructible<_Tp, _Opt&&>, + is_constructible<_Tp, _Opt const&&>, + is_convertible<_Opt&, _Tp>, + is_convertible<_Opt const&, _Tp>, + is_convertible<_Opt&&, _Tp>, + is_convertible<_Opt const&&, _Tp> >; + template > + using __check_assignable_from_opt _LIBCPP_NODEBUG = + _Or< is_assignable<_Tp&, _Opt&>, + is_assignable<_Tp&, _Opt const&>, + is_assignable<_Tp&, _Opt&&>, + is_assignable<_Tp&, _Opt const&&> >; + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() { + return is_convertible<_QUp, _Tp>::value && + (is_same_v, bool> || !__check_constructible_from_opt<_Up>::value); + } + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() { + return !is_convertible<_QUp, _Tp>::value && + (is_same_v, bool> || !__check_constructible_from_opt<_Up>::value); + } + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_assign() { + // Construction and assignability of _QUp to _Tp has already been + // checked. + return !__check_constructible_from_opt<_Up>::value && !__check_assignable_from_opt<_Up>::value; + } + }; + + template + using _CheckOptionalLikeCtor _LIBCPP_NODEBUG = + _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp> >::value, + _CheckOptionalLikeConstructor<_QualUp>, + __check_tuple_constructor_fail >; + template + using _CheckOptionalLikeAssign _LIBCPP_NODEBUG = + _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>, is_assignable<_Tp&, _QualUp> >::value, + _CheckOptionalLikeConstructor<_QualUp>, + __check_tuple_constructor_fail >; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr optional() noexcept {} + _LIBCPP_HIDE_FROM_ABI constexpr optional(const optional&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr optional(optional&&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr optional(nullopt_t) noexcept {} + + template , is_constructible<_Tp, _Args...>>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_InPlaceT, _Args&&... __args) + : __base(in_place, std::forward<_Args>(__args)...) {} + + template &, _Args...>, int> = 0> + _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) + : __base(in_place, __il, std::forward<_Args>(__args)...) {} + + template ::template __enable_implicit<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened + : __base(in_place, std::forward<_Up>(__v)) {} + + template , + enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) noexcept( + is_nothrow_constructible_v<_Tp, _Up>) // strengthened + : __base(in_place, std::forward<_Up>(__v)) {} + + // LWG2756: conditionally explicit conversion from const optional<_Up>& + template ::template __enable_implicit<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) { + this->__construct_from(__v); + } + + template ::template __enable_explicit<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) { + this->__construct_from(__v); + } + + // LWG2756: conditionally explicit conversion from optional<_Up>&& + template ::template __enable_implicit<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v) { + this->__construct_from(std::move(__v)); + } + + template ::template __enable_explicit<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v) { + this->__construct_from(std::move(__v)); + } + +# if _LIBCPP_STD_VER >= 23 + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Tag, _Fp&& __f, _Args&&... __args) + : __base(__optional_construct_from_invoke_tag{}, std::forward<_Fp>(__f), std::forward<_Args>(__args)...) {} +# endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(nullopt_t) noexcept { + reset(); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(const optional&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(optional&&) = default; + + // LWG2756 + template , + enable_if_t<_And<_IsNotSame<__remove_cvref_t<_Up>, optional>, + _Or<_IsNotSame<__remove_cvref_t<_Up>, _Tp>, _Not>>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(_Up&& __v) { + if (this->has_value()) + this->__get() = std::forward<_Up>(__v); + else + this->__construct(std::forward<_Up>(__v)); + return *this; + } + + // LWG2756 + template ::template __enable_assign<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(const optional<_Up>& __v) { + this->__assign_from(__v); + return *this; + } + + // LWG2756 + template ::template __enable_assign<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(optional<_Up>&& __v) { + this->__assign_from(std::move(__v)); + return *this; + } + + template , int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(_Args&&... __args) { + reset(); + this->__construct(std::forward<_Args>(__args)...); + return this->__get(); + } + + template &, _Args...>, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { + reset(); + this->__construct(__il, std::forward<_Args>(__args)...); + return this->__get(); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void + swap(optional& __opt) noexcept((is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>)) { + this->__swap(__opt); + } + + using __base::operator*; + using __base::operator->; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return has_value(); } + + using __base::__get; + using __base::has_value; + using __base::value; + + template > + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& { + static_assert(is_copy_constructible_v<_Tp>, "optional::value_or: T must be copy constructible"); + static_assert(is_convertible_v<_Up, _Tp>, "optional::value_or: U must be convertible to T"); + return this->has_value() ? this->__get() : static_cast<_Tp>(std::forward<_Up>(__v)); + } + + template > + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && { + static_assert(is_move_constructible_v<_Tp>, "optional::value_or: T must be move constructible"); + static_assert(is_convertible_v<_Up, _Tp>, "optional::value_or: U must be convertible to T"); + return this->has_value() ? std::move(this->__get()) : static_cast<_Tp>(std::forward<_Up>(__v)); + } + +# if _LIBCPP_STD_VER >= 23 + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + using _Up = invoke_result_t<_Func, _Tp&>; + static_assert( + __is_std_optional_v>, "Result of f(value()) must be a specialization of std::optional"); + if (*this) + return std::invoke(std::forward<_Func>(__f), value()); + return remove_cvref_t<_Up>(); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + using _Up = invoke_result_t<_Func, const _Tp&>; + static_assert( + __is_std_optional_v>, "Result of f(value()) must be a specialization of std::optional"); + if (*this) + return std::invoke(std::forward<_Func>(__f), value()); + return remove_cvref_t<_Up>(); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + using _Up = invoke_result_t<_Func, _Tp&&>; + static_assert(__is_std_optional_v>, + "Result of f(std::move(value())) must be a specialization of std::optional"); + if (*this) + return std::invoke(std::forward<_Func>(__f), std::move(value())); + return remove_cvref_t<_Up>(); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + using _Up = invoke_result_t<_Func, const _Tp&&>; + static_assert(__is_std_optional_v>, + "Result of f(std::move(value())) must be a specialization of std::optional"); + if (*this) + return std::invoke(std::forward<_Func>(__f), std::move(value())); + return remove_cvref_t<_Up>(); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + using _Up = remove_cv_t>; + static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array"); + static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t"); + static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t"); + static_assert( + __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); + if (*this) + return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value()); + return optional<_Up>(); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + using _Up = remove_cv_t>; + static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array"); + static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t"); + static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t"); + static_assert( + __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); + if (*this) + return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value()); + return optional<_Up>(); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + using _Up = remove_cv_t>; + static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array"); + static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t"); + static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t"); + static_assert( + __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); + if (*this) + return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value())); + return optional<_Up>(); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + using _Up = remove_cv_t>; + static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array"); + static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t"); + static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t"); + static_assert( + __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); + if (*this) + return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value())); + return optional<_Up>(); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const& + requires is_copy_constructible_v<_Tp> + { + static_assert(is_same_v>, optional>, + "Result of f() should be the same type as this optional"); + if (*this) + return *this; + return std::forward<_Func>(__f)(); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) && + requires is_move_constructible_v<_Tp> + { + static_assert(is_same_v>, optional>, + "Result of f() should be the same type as this optional"); + if (*this) + return std::move(*this); + return std::forward<_Func>(__f)(); + } +# endif // _LIBCPP_STD_VER >= 23 + + using __base::reset; +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___OPTIONAL_OPTIONAL_H diff --git a/libcxx/include/__optional/optional_ref.h b/libcxx/include/__optional/optional_ref.h new file mode 100644 index 000000000000..d137b3c40c7e --- /dev/null +++ b/libcxx/include/__optional/optional_ref.h @@ -0,0 +1,357 @@ +//===----------------------------------------------------------------------===// +// +// 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 _LIBCPP___OPTIONAL_OPTIONAL_REF_H +#define _LIBCPP___OPTIONAL_OPTIONAL_REF_H + +#include <__assert> +#include <__concepts/invocable.h> +#include <__config> +#include <__functional/invoke.h> +#include <__fwd/optional.h> +#include <__iterator/bounded_iter.h> +#include <__iterator/capacity_aware_iterator.h> +#include <__memory/addressof.h> +#include <__optional/common.h> +#include <__optional/comparison.h> +#include <__optional/hash.h> +#include <__optional/nullopt_t.h> +#include <__optional/swap.h> +#include <__type_traits/add_pointer.h> +#include <__type_traits/decay.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_trivially_relocatable.h> +#include <__type_traits/reference_constructs_from_temporary.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_cvref.h> +#include <__type_traits/remove_reference.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include <__utility/swap.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __optional_storage_base<_Tp, true> { + using value_type = _Tp; + using __raw_type _LIBCPP_NODEBUG = remove_reference_t<_Tp>; + __raw_type* __value_; + + _LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __value_(nullptr) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __convert_init_ref_val(_Up&& __val) { + _Tp& __r(std::forward<_Up>(__val)); + __value_ = std::addressof(__r); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg) { + static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>, + "Attempted to construct a reference element in optional from a " + "possible temporary"); + __convert_init_ref_val(std::forward<_UArg>(__uarg)); + } + +# if _LIBCPP_STD_VER >= 23 + template + constexpr __optional_storage_base(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) { + __convert_init_ref_val(std::forward>( + std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...))); + } +# endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { __value_ = nullptr; } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; } + + _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const noexcept { return *__value_; } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val) { + static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>, + "Attempted to construct a reference element in tuple from a " + "possible temporary"); + __convert_init_ref_val(std::forward<_UArg>(__val)); + } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_from(_That&& __opt) { + if (__opt.has_value()) + __construct(std::forward<_That>(__opt).__get()); + } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from(_That&& __opt) { + if (has_value() == __opt.has_value()) { + if (has_value()) + *__value_ = std::forward<_That>(__opt).__get(); + } else { + if (has_value()) + reset(); + else + __construct(std::forward<_That>(__opt).__get()); + } + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_storage_base& __rhs) noexcept { + std::swap(__value_, __rhs.__value_); + } + + // [optional.ref.observe] + _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); + return std::addressof(this->__get()); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() const noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); + return this->__get(); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() const { + if (!this->has_value()) + std::__throw_bad_optional_access(); + return this->__get(); + } +}; + +# if _LIBCPP_STD_VER >= 26 + +template +struct __optional_iterator_base; + +template +struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> { + using __optional_storage_base<_Tp&>::__optional_storage_base; +}; + +# if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR + +template + requires(is_object_v<_Tp> && !__is_unbounded_array_v<_Tp>) +struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> { +private: + using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>; + +public: + using __optional_storage_base<_Tp&>::__optional_storage_base; + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + using iterator = __bounded_iter<__pointer>; +# else + using iterator = __capacity_aware_iterator<__pointer, optional<_Tp&>, 1>; +# endif + + // [optional.ref.iterators], iterator support + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const noexcept { + auto* __ptr = this->has_value() ? std::addressof(this->__get()) : nullptr; + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0)); +# else + return std::__make_capacity_aware_iterator<__pointer, optional<_Tp&>, 1>(__ptr); +# endif + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const noexcept { + return begin() + (this->has_value() ? 1 : 0); + } +}; + +# endif + +template +class optional<_Tp&> : public __optional_iterator_base<_Tp&> { + using __base _LIBCPP_NODEBUG = __optional_iterator_base<_Tp&>; + + template + static constexpr bool __check_optionalU_ctor = + !is_same_v, optional<_Up>> && !is_same_v<_Tp&, _Up> && is_constructible_v<_Tp&, _QualUp>; + static_assert(!is_same_v, in_place_t>, "instantiation of optional with in_place_t is ill-formed"); + static_assert(!is_same_v, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed"); + +public: + using value_type = _Tp; + + constexpr optional() noexcept = default; + constexpr optional(nullopt_t) noexcept {} + constexpr optional(const optional&) noexcept = default; + + template + requires(is_constructible_v<_Tp&, _Arg> && !reference_constructs_from_temporary_v<_Tp&, _Arg>) + constexpr explicit optional(in_place_t, _Arg&& __arg) : __base(in_place, std::forward<_Arg>(__arg)) {} + + template + requires(!is_same_v, optional> && !is_same_v, in_place_t> && + is_constructible_v<_Tp&, _Up> && !reference_constructs_from_temporary_v<_Tp&, _Up>) + constexpr explicit(!is_convertible_v<_Up, _Tp&>) optional(_Up&& __v) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) + : __base(in_place, std::forward<_Up>(__v)) {} + + template + requires(__check_optionalU_ctor<_Up, _Up&> && !reference_constructs_from_temporary_v<_Tp&, _Up&>) + constexpr explicit(!is_convertible_v<_Up&, _Tp&>) + optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) { + this->__construct_from(__rhs); + } + + template + requires(__check_optionalU_ctor<_Up, const _Up&> && !reference_constructs_from_temporary_v<_Tp&, const _Up&>) + constexpr explicit(!is_convertible_v) + optional(const optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up&>) { + this->__construct_from(__rhs); + } + + template + requires(__check_optionalU_ctor<_Up, _Up> && !reference_constructs_from_temporary_v<_Tp&, _Up>) + constexpr explicit(!is_convertible_v<_Up, _Tp&>) + optional(optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) { + this->__construct_from(std::move(__rhs)); + } + + template + requires(__check_optionalU_ctor<_Up, const _Up> && !reference_constructs_from_temporary_v<_Tp&, const _Up>) + constexpr explicit(!is_convertible_v) + optional(const optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) { + this->__construct_from(std::move(__rhs)); + } + + template + requires(is_same_v<_Tag, __optional_construct_from_invoke_tag>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Tag, _Fp&& __f, _Args&&... __args) + : __base(__optional_construct_from_invoke_tag{}, std::forward<_Fp>(__f), std::forward<_Args>(__args)...) {} + + // deleted overloads + + template + requires(!is_same_v, optional> && !is_same_v, in_place_t> && + is_constructible_v<_Tp&, _Up> && reference_constructs_from_temporary_v<_Tp&, _Up>) + constexpr explicit(!is_convertible_v<_Up, _Tp&>) + optional(_Up&& __v) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) = delete; + + template + requires(__check_optionalU_ctor<_Up, _Up&> && reference_constructs_from_temporary_v<_Tp&, _Up&>) + constexpr explicit(!is_convertible_v<_Up&, _Tp&>) + optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) = delete; + + template + requires(__check_optionalU_ctor<_Up, const _Up&> && reference_constructs_from_temporary_v<_Tp&, const _Up&>) + constexpr explicit(!is_convertible_v) + optional(const optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up&>) = delete; + + template + requires(__check_optionalU_ctor<_Up, _Up> && reference_constructs_from_temporary_v<_Tp&, _Up>) + constexpr explicit(!is_convertible_v<_Up, _Tp&>) + optional(optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) = delete; + + template + requires(__check_optionalU_ctor<_Up, const _Up> && reference_constructs_from_temporary_v<_Tp&, const _Up>) + constexpr explicit(!is_convertible_v) + optional(const optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) = delete; + + constexpr ~optional() = default; + + using __base::__get; + + _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(nullopt_t) noexcept { + reset(); + return *this; + } + + constexpr optional& operator=(const optional&) noexcept = default; + + template + requires(is_constructible_v<_Tp&, _Up> && !reference_constructs_from_temporary_v<_Tp&, _Up>) + constexpr _Tp& emplace(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) { + this->__construct(std::forward<_Up>(__u)); + + return this->__get(); + } + + constexpr void swap(optional& __rhs) noexcept { this->__swap(__rhs); } + + using __base::operator->; + using __base::operator*; + + constexpr explicit operator bool() const noexcept { return has_value(); } + + using __base::has_value; + using __base::value; + + template > + requires(!is_array_v<_Tp> && is_object_v<_Tp>) + [[nodiscard]] constexpr decay_t<_Tp> value_or(_Up&& __v) const { + using _XTp = remove_cv_t<_Tp>; + static_assert(is_constructible_v<_XTp, _Tp&>, "optional::value_or: remove_cv_t must be constructible"); + static_assert(is_convertible_v<_Up, _XTp>, "optional::value_or: U must be convertible to remove_cv_t"); + return this->has_value() ? this->__get() : static_cast<_XTp>(std::forward<_Up>(__v)); + } + + template + [[nodiscard]] constexpr auto and_then(_Func&& __f) const { + using _Up = invoke_result_t<_Func, _Tp&>; + static_assert( + __is_std_optional_v>, "Result of f(value()) must be a specialization of std::optional"); + if (*this) + return std::invoke(std::forward<_Func>(__f), value()); + return remove_cvref_t<_Up>(); + } + + template + [[nodiscard]] constexpr optional>> transform(_Func&& __f) const { + using _Up = remove_cv_t>; + static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array"); + static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t"); + static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t"); + static_assert( + __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); + + if (*this) + return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value()); + return optional<_Up>(); + } + + template + [[nodiscard]] constexpr optional or_else(_Func&& __f) const { + static_assert(is_same_v>, optional>, + "Result of f() should be the same type as this optional"); + if (*this) + return *this; + return std::forward<_Func>(__f)(); + } + + using __base::reset; +}; + +# endif // _LIBCPP_STD_VER >= 26 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___OPTIONAL_OPTIONAL_REF_H diff --git a/libcxx/include/__optional/swap.h b/libcxx/include/__optional/swap.h new file mode 100644 index 000000000000..2aba7c0e2966 --- /dev/null +++ b/libcxx/include/__optional/swap.h @@ -0,0 +1,45 @@ +// -*- 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 _LIBCPP___OPTIONAL_SWAP_H +#define _LIBCPP___OPTIONAL_SWAP_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_swappable.h> + +#include <__fwd/optional.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template && is_swappable_v<_Tp>) +# if _LIBCPP_STD_VER >= 26 + || is_reference_v<_Tp> +# endif + , + int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +swap(optional<_Tp>& __x, optional<_Tp>& __y) noexcept(noexcept(__x.swap(__y))) { + __x.swap(__y); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___OPTIONAL_SWAP_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 4327478e986f..6b491e4e2589 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1807,6 +1807,33 @@ module std { } module optional { + module fwd { header "__fwd/optional.h" } + module hash { + header "__optional/hash.h" + export std.functional.hash + } + module common { + header "__optional/common.h" + export std.format.fwd + } + + module comparison { header "__optional/comparison.h" } + module make_optional { header "__optional/make_optional.h" } + module nullopt_t { header "__optional/nullopt_t.h" } + module optional { + header "__optional/optional.h" + export std.iterator.bounded_iter + export std.iterator.capacity_aware_iterator + export std.utility.swap + } + module optional_ref { + header "__optional/optional_ref.h" + export std.iterator.bounded_iter + export std.iterator.capacity_aware_iterator + export std.utility.swap + } + module swap { header "__optional/swap.h" } + header "optional" export * } diff --git a/libcxx/include/optional b/libcxx/include/optional index ffa071c2304b..170062aa3249 100644 --- a/libcxx/include/optional +++ b/libcxx/include/optional @@ -258,68 +258,35 @@ namespace std { #if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) # include <__cxx03/__config> #else -# include <__assert> -# include <__compare/compare_three_way_result.h> -# include <__compare/ordering.h> -# include <__compare/three_way_comparable.h> -# include <__concepts/invocable.h> # include <__config> -# include <__exception/exception.h> -# include <__functional/hash.h> -# include <__functional/invoke.h> -# include <__functional/unary_function.h> -# include <__fwd/format.h> -# include <__fwd/functional.h> -# include <__iterator/bounded_iter.h> -# include <__iterator/capacity_aware_iterator.h> -# include <__memory/addressof.h> -# include <__memory/construct_at.h> -# include <__ranges/enable_borrowed_range.h> -# include <__ranges/enable_view.h> -# include <__tuple/sfinae_helpers.h> -# include <__type_traits/add_pointer.h> +# include + +# include <__optional/common.h> +# include <__optional/comparison.h> +# include <__optional/hash.h> +# include <__optional/make_optional.h> +# include <__optional/optional.h> +# include <__optional/optional_ref.h> +# include <__optional/swap.h> + +// TODO: Some headers rely on these transitive includes +# include <__cstddef/size_t.h> # include <__type_traits/conditional.h> -# include <__type_traits/conjunction.h> -# include <__type_traits/decay.h> -# include <__type_traits/disjunction.h> # include <__type_traits/enable_if.h> -# include <__type_traits/integral_constant.h> # include <__type_traits/invoke.h> -# include <__type_traits/is_array.h> -# include <__type_traits/is_assignable.h> # include <__type_traits/is_constructible.h> -# include <__type_traits/is_convertible.h> -# include <__type_traits/is_core_convertible.h> -# include <__type_traits/is_destructible.h> -# include <__type_traits/is_function.h> -# include <__type_traits/is_nothrow_assignable.h> -# include <__type_traits/is_nothrow_constructible.h> # include <__type_traits/is_object.h> # include <__type_traits/is_reference.h> -# include <__type_traits/is_same.h> -# include <__type_traits/is_scalar.h> -# include <__type_traits/is_swappable.h> -# include <__type_traits/is_trivially_assignable.h> -# include <__type_traits/is_trivially_constructible.h> -# include <__type_traits/is_trivially_destructible.h> -# include <__type_traits/is_trivially_relocatable.h> -# include <__type_traits/negation.h> -# include <__type_traits/reference_constructs_from_temporary.h> # include <__type_traits/remove_const.h> -# include <__type_traits/remove_cv.h> # include <__type_traits/remove_cvref.h> -# include <__type_traits/remove_reference.h> # include <__utility/declval.h> # include <__utility/forward.h> # include <__utility/in_place.h> # include <__utility/move.h> -# include <__utility/swap.h> -# include <__verbose_abort> + # include -# include // standard-mandated includes - // [optional.syn] # include @@ -327,1439 +294,6 @@ namespace std { # pragma GCC system_header # endif -_LIBCPP_PUSH_MACROS -# include <__undef_macros> - -namespace std // purposefully not using versioning namespace -{ - -class _LIBCPP_EXPORTED_FROM_ABI bad_optional_access : public exception { -public: - _LIBCPP_HIDE_FROM_ABI bad_optional_access() _NOEXCEPT = default; - _LIBCPP_HIDE_FROM_ABI bad_optional_access(const bad_optional_access&) _NOEXCEPT = default; - _LIBCPP_HIDE_FROM_ABI bad_optional_access& operator=(const bad_optional_access&) _NOEXCEPT = default; - // Get the key function ~bad_optional_access() into the dylib - ~bad_optional_access() _NOEXCEPT override; - [[__nodiscard__]] const char* what() const _NOEXCEPT override; -}; - -} // namespace std - -# if _LIBCPP_STD_VER >= 17 - -_LIBCPP_BEGIN_NAMESPACE_STD - -[[noreturn]] inline _LIBCPP_HIDE_FROM_ABI void __throw_bad_optional_access() { -# if _LIBCPP_HAS_EXCEPTIONS - throw bad_optional_access(); -# else - _LIBCPP_VERBOSE_ABORT("bad_optional_access was thrown in -fno-exceptions mode"); -# endif -} - -struct nullopt_t { - struct __secret_tag { - explicit __secret_tag() = default; - }; - _LIBCPP_HIDE_FROM_ABI constexpr explicit nullopt_t(__secret_tag, __secret_tag) noexcept {} -}; - -inline constexpr nullopt_t nullopt{nullopt_t::__secret_tag{}, nullopt_t::__secret_tag{}}; - -struct __optional_construct_from_invoke_tag {}; - -template ::value> -struct __optional_destruct_base; - -template -struct __optional_destruct_base<_Tp, false> { - typedef _Tp value_type; - static_assert(is_object_v, "instantiation of optional with a non-object type is undefined behavior"); - union { - char __null_state_; - remove_cv_t __val_; - }; - bool __engaged_; - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__optional_destruct_base() { - if (__engaged_) - __val_.~value_type(); - } - - _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base() noexcept : __null_state_(), __engaged_(false) {} - - template - _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base(in_place_t, _Args&&... __args) - : __val_(std::forward<_Args>(__args)...), __engaged_(true) {} - -# if _LIBCPP_STD_VER >= 23 - template - _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base( - __optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) - : __val_(std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)), __engaged_(true) {} -# endif - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { - if (__engaged_) { - __val_.~value_type(); - __engaged_ = false; - } - } -}; - -template -struct __optional_destruct_base<_Tp, true> { - typedef _Tp value_type; - static_assert(is_object_v, "instantiation of optional with a non-object type is undefined behavior"); - union { - char __null_state_; - remove_cv_t __val_; - }; - bool __engaged_; - - _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base() noexcept : __null_state_(), __engaged_(false) {} - - template - _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base(in_place_t, _Args&&... __args) - : __val_(std::forward<_Args>(__args)...), __engaged_(true) {} - -# if _LIBCPP_STD_VER >= 23 - template - _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base( - __optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) - : __val_(std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)), __engaged_(true) {} -# endif - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { - if (__engaged_) { - __engaged_ = false; - } - } -}; - -template ::value> -struct __optional_storage_base : __optional_destruct_base<_Tp> { - using __base _LIBCPP_NODEBUG = __optional_destruct_base<_Tp>; - using value_type = _Tp; - using __base::__base; - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__engaged_; } - - _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() & noexcept { return this->__val_; } - _LIBCPP_HIDE_FROM_ABI constexpr const value_type& __get() const& noexcept { return this->__val_; } - _LIBCPP_HIDE_FROM_ABI constexpr value_type&& __get() && noexcept { return std::move(this->__val_); } - _LIBCPP_HIDE_FROM_ABI constexpr const value_type&& __get() const&& noexcept { return std::move(this->__val_); } - - template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_Args&&... __args) { - _LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage"); - std::__construct_at(std::addressof(this->__val_), std::forward<_Args>(__args)...); - this->__engaged_ = true; - } - - template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_from(_That&& __opt) { - if (__opt.has_value()) - __construct(std::forward<_That>(__opt).__get()); - } - - template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from(_That&& __opt) { - if (this->__engaged_ == __opt.has_value()) { - if (this->__engaged_) - static_cast<_Tp&>(this->__val_) = std::forward<_That>(__opt).__get(); - } else { - if (this->__engaged_) - this->reset(); - else - __construct(std::forward<_That>(__opt).__get()); - } - } - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void - __swap(__optional_storage_base& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) { - using std::swap; - if (this->has_value() == __rhs.has_value()) { - if (this->has_value()) - swap(this->__get(), __rhs.__get()); - } else { - if (this->has_value()) { - __rhs.__construct(std::move(this->__get())); - this->reset(); - } else { - this->__construct(std::move(__rhs.__get())); - __rhs.reset(); - } - } - } - - // [optional.observe] - _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); - return std::addressof(this->__get()); - } - - _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); - return std::addressof(this->__get()); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); - return this->__get(); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); - return this->__get(); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); - return std::move(this->__get()); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); - return std::move(this->__get()); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& { - if (!this->has_value()) - std::__throw_bad_optional_access(); - return this->__get(); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & { - if (!this->has_value()) - std::__throw_bad_optional_access(); - return this->__get(); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && { - if (!this->has_value()) - std::__throw_bad_optional_access(); - return std::move(this->__get()); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& { - if (!this->has_value()) - std::__throw_bad_optional_access(); - return std::move(this->__get()); - } -}; - -template -struct __optional_storage_base<_Tp, true> { - using value_type = _Tp; - using __raw_type _LIBCPP_NODEBUG = remove_reference_t<_Tp>; - __raw_type* __value_; - - _LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __value_(nullptr) {} - - template - _LIBCPP_HIDE_FROM_ABI constexpr void __convert_init_ref_val(_Up&& __val) { - _Tp& __r(std::forward<_Up>(__val)); - __value_ = std::addressof(__r); - } - - template - _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg) { - static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>, - "Attempted to construct a reference element in optional from a " - "possible temporary"); - __convert_init_ref_val(std::forward<_UArg>(__uarg)); - } - -# if _LIBCPP_STD_VER >= 23 - template - constexpr __optional_storage_base(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) { - __convert_init_ref_val(std::forward>( - std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...))); - } -# endif - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { __value_ = nullptr; } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; } - - _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const noexcept { return *__value_; } - - template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val) { - static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>, - "Attempted to construct a reference element in tuple from a " - "possible temporary"); - __convert_init_ref_val(std::forward<_UArg>(__val)); - } - - template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_from(_That&& __opt) { - if (__opt.has_value()) - __construct(std::forward<_That>(__opt).__get()); - } - - template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from(_That&& __opt) { - if (has_value() == __opt.has_value()) { - if (has_value()) - *__value_ = std::forward<_That>(__opt).__get(); - } else { - if (has_value()) - reset(); - else - __construct(std::forward<_That>(__opt).__get()); - } - } - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_storage_base& __rhs) noexcept { - std::swap(__value_, __rhs.__value_); - } - - // [optional.ref.observe] - _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); - return std::addressof(this->__get()); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() const noexcept { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); - return this->__get(); - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() const { - if (!this->has_value()) - std::__throw_bad_optional_access(); - return this->__get(); - } -}; - -template > -struct __optional_copy_base : __optional_storage_base<_Tp> { - using __optional_storage_base<_Tp>::__optional_storage_base; -}; - -template -struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp> { - using __optional_storage_base<_Tp>::__optional_storage_base; - - _LIBCPP_HIDE_FROM_ABI __optional_copy_base() = default; - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __optional_copy_base(const __optional_copy_base& __opt) { - this->__construct_from(__opt); - } - - _LIBCPP_HIDE_FROM_ABI __optional_copy_base(__optional_copy_base&&) = default; - _LIBCPP_HIDE_FROM_ABI __optional_copy_base& operator=(const __optional_copy_base&) = default; - _LIBCPP_HIDE_FROM_ABI __optional_copy_base& operator=(__optional_copy_base&&) = default; -}; - -template > -struct __optional_move_base : __optional_copy_base<_Tp> { - using __optional_copy_base<_Tp>::__optional_copy_base; -}; - -template -struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp> { - using value_type = _Tp; - using __optional_copy_base<_Tp>::__optional_copy_base; - - _LIBCPP_HIDE_FROM_ABI __optional_move_base() = default; - _LIBCPP_HIDE_FROM_ABI __optional_move_base(const __optional_move_base&) = default; - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 - __optional_move_base(__optional_move_base&& __opt) noexcept(is_nothrow_move_constructible_v) { - this->__construct_from(std::move(__opt)); - } - - _LIBCPP_HIDE_FROM_ABI __optional_move_base& operator=(const __optional_move_base&) = default; - _LIBCPP_HIDE_FROM_ABI __optional_move_base& operator=(__optional_move_base&&) = default; -}; - -template && is_trivially_copy_constructible_v<_Tp> && - is_trivially_copy_assignable_v<_Tp>)> -struct __optional_copy_assign_base : __optional_move_base<_Tp> { - using __optional_move_base<_Tp>::__optional_move_base; -}; - -template -struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp> { - using __optional_move_base<_Tp>::__optional_move_base; - - _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base() = default; - _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base(const __optional_copy_assign_base&) = default; - _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base(__optional_copy_assign_base&&) = default; - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __optional_copy_assign_base& - operator=(const __optional_copy_assign_base& __opt) { - this->__assign_from(__opt); - return *this; - } - - _LIBCPP_HIDE_FROM_ABI __optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default; -}; - -template && is_trivially_move_constructible_v<_Tp> && - is_trivially_move_assignable_v<_Tp>)> -struct __optional_move_assign_base : __optional_copy_assign_base<_Tp> { - using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base; -}; - -template -struct __optional_move_assign_base<_Tp, false> : __optional_copy_assign_base<_Tp> { - using value_type = _Tp; - using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base; - - _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base() = default; - _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base(const __optional_move_assign_base& __opt) = default; - _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base(__optional_move_assign_base&&) = default; - _LIBCPP_HIDE_FROM_ABI __optional_move_assign_base& operator=(const __optional_move_assign_base&) = default; - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __optional_move_assign_base& - operator=(__optional_move_assign_base&& __opt) noexcept( - is_nothrow_move_assignable_v && is_nothrow_move_constructible_v) { - this->__assign_from(std::move(__opt)); - return *this; - } -}; - -template -using __optional_sfinae_ctor_base_t _LIBCPP_NODEBUG = - __sfinae_ctor_base< is_copy_constructible<_Tp>::value, is_move_constructible<_Tp>::value >; - -template -using __optional_sfinae_assign_base_t _LIBCPP_NODEBUG = - __sfinae_assign_base< (is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Tp>), - (is_move_constructible_v<_Tp> && is_move_assignable_v<_Tp>)>; - -template -class optional; - -# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR -template -constexpr bool ranges::enable_view> = true; - -template -constexpr range_format format_kind> = range_format::disabled; - -template -constexpr bool ranges::enable_borrowed_range> = true; - -# endif - -# if _LIBCPP_STD_VER >= 20 - -template -concept __is_derived_from_optional = requires(const _Tp& __t) { [](const optional<_Up>&) {}(__t); }; - -# endif // _LIBCPP_STD_VER >= 20 - -template -inline constexpr bool __is_std_optional_v = false; - -template -inline constexpr bool __is_std_optional_v> = true; - -# if _LIBCPP_STD_VER < 26 -template -inline constexpr bool __is_valid_optional_contained_type = is_object_v<_Tp>; -# else -template -inline constexpr bool __is_valid_optional_contained_type = is_object_v<_Tp> || is_lvalue_reference_v<_Tp>; -# endif - -template -struct __optional_iterator_base : __optional_move_assign_base<_Tp> { - using __optional_move_assign_base<_Tp>::__optional_move_assign_base; -}; - -# if _LIBCPP_STD_VER >= 26 -template -struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> { - using __optional_storage_base<_Tp&>::__optional_storage_base; -}; - -# if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR - -template - requires is_object_v<_Tp> -struct __optional_iterator_base<_Tp> : __optional_move_assign_base<_Tp> { -private: - using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>; - using __const_pointer _LIBCPP_NODEBUG = add_pointer_t; - -public: - using __optional_move_assign_base<_Tp>::__optional_move_assign_base; - -# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL - using iterator = __bounded_iter<__pointer>; - using const_iterator = __bounded_iter<__const_pointer>; -# else - using iterator = __capacity_aware_iterator<__pointer, optional<_Tp>, 1>; - using const_iterator = __capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>; -# endif - - // [optional.iterators], iterator support - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept { - auto* __ptr = std::addressof(this->__get()); - -# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL - return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0)); -# else - return std::__make_capacity_aware_iterator<__pointer, optional<_Tp>, 1>(__ptr); -# endif - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { - auto* __ptr = std::addressof(this->__get()); - -# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL - return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0)); -# else - return std::__make_capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>(__ptr); -# endif - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept { - return begin() + (this->has_value() ? 1 : 0); - } - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { - return begin() + (this->has_value() ? 1 : 0); - } -}; - -template - requires(is_object_v<_Tp> && !__is_unbounded_array_v<_Tp>) -struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> { -private: - using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>; - -public: - using __optional_storage_base<_Tp&>::__optional_storage_base; - -# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL - using iterator = __bounded_iter<__pointer>; -# else - using iterator = __capacity_aware_iterator<__pointer, optional<_Tp&>, 1>; -# endif - - // [optional.ref.iterators], iterator support - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const noexcept { - auto* __ptr = this->has_value() ? std::addressof(this->__get()) : nullptr; - -# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL - return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0)); -# else - return std::__make_capacity_aware_iterator<__pointer, optional<_Tp&>, 1>(__ptr); -# endif - } - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const noexcept { - return begin() + (this->has_value() ? 1 : 0); - } -}; - -# endif // _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR -# endif // _LIBCPP_STD_VER >= 26 - -template -class _LIBCPP_DECLSPEC_EMPTY_BASES optional - : public __optional_iterator_base<_Tp>, - private __optional_sfinae_ctor_base_t<_Tp>, - private __optional_sfinae_assign_base_t<_Tp> { - using __base _LIBCPP_NODEBUG = __optional_iterator_base<_Tp>; - -public: - using value_type = __libcpp_remove_reference_t<_Tp>; - - using __trivially_relocatable _LIBCPP_NODEBUG = - conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>; - -private: - static_assert(!is_same_v, in_place_t>, "instantiation of optional with in_place_t is ill-formed"); - static_assert(!is_same_v, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed"); -# if _LIBCPP_STD_VER >= 26 - static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed"); -# else - static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed"); -# endif - static_assert(is_destructible_v<_Tp>, "instantiation of optional with a non-destructible type is ill-formed"); - static_assert(!is_array_v<_Tp>, "instantiation of optional with an array type is ill-formed"); - - // LWG2756: conditionally explicit conversion from _Up - struct _CheckOptionalArgsConstructor { - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() { - return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>; - } - - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() { - return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>; - } - }; - template - using _CheckOptionalArgsCtor _LIBCPP_NODEBUG = - _If< _IsNotSame<__remove_cvref_t<_Up>, in_place_t>::value && _IsNotSame<__remove_cvref_t<_Up>, optional>::value && - (!is_same_v, bool> || !__is_std_optional_v<__remove_cvref_t<_Up>>), - _CheckOptionalArgsConstructor, - __check_tuple_constructor_fail >; - template - struct _CheckOptionalLikeConstructor { - template > - using __check_constructible_from_opt _LIBCPP_NODEBUG = - _Or< is_constructible<_Tp, _Opt&>, - is_constructible<_Tp, _Opt const&>, - is_constructible<_Tp, _Opt&&>, - is_constructible<_Tp, _Opt const&&>, - is_convertible<_Opt&, _Tp>, - is_convertible<_Opt const&, _Tp>, - is_convertible<_Opt&&, _Tp>, - is_convertible<_Opt const&&, _Tp> >; - template > - using __check_assignable_from_opt _LIBCPP_NODEBUG = - _Or< is_assignable<_Tp&, _Opt&>, - is_assignable<_Tp&, _Opt const&>, - is_assignable<_Tp&, _Opt&&>, - is_assignable<_Tp&, _Opt const&&> >; - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() { - return is_convertible<_QUp, _Tp>::value && - (is_same_v, bool> || !__check_constructible_from_opt<_Up>::value); - } - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() { - return !is_convertible<_QUp, _Tp>::value && - (is_same_v, bool> || !__check_constructible_from_opt<_Up>::value); - } - template - _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_assign() { - // Construction and assignability of _QUp to _Tp has already been - // checked. - return !__check_constructible_from_opt<_Up>::value && !__check_assignable_from_opt<_Up>::value; - } - }; - - template - using _CheckOptionalLikeCtor _LIBCPP_NODEBUG = - _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp> >::value, - _CheckOptionalLikeConstructor<_QualUp>, - __check_tuple_constructor_fail >; - template - using _CheckOptionalLikeAssign _LIBCPP_NODEBUG = - _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>, is_assignable<_Tp&, _QualUp> >::value, - _CheckOptionalLikeConstructor<_QualUp>, - __check_tuple_constructor_fail >; - -public: - _LIBCPP_HIDE_FROM_ABI constexpr optional() noexcept {} - _LIBCPP_HIDE_FROM_ABI constexpr optional(const optional&) = default; - _LIBCPP_HIDE_FROM_ABI constexpr optional(optional&&) = default; - _LIBCPP_HIDE_FROM_ABI constexpr optional(nullopt_t) noexcept {} - - template , is_constructible<_Tp, _Args...>>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_InPlaceT, _Args&&... __args) - : __base(in_place, std::forward<_Args>(__args)...) {} - - template &, _Args...>, int> = 0> - _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) - : __base(in_place, __il, std::forward<_Args>(__args)...) {} - - template ::template __enable_implicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened - : __base(in_place, std::forward<_Up>(__v)) {} - - template , - enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) noexcept( - is_nothrow_constructible_v<_Tp, _Up>) // strengthened - : __base(in_place, std::forward<_Up>(__v)) {} - - // LWG2756: conditionally explicit conversion from const optional<_Up>& - template ::template __enable_implicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) { - this->__construct_from(__v); - } - - template ::template __enable_explicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) { - this->__construct_from(__v); - } - - // LWG2756: conditionally explicit conversion from optional<_Up>&& - template ::template __enable_implicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v) { - this->__construct_from(std::move(__v)); - } - - template ::template __enable_explicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v) { - this->__construct_from(std::move(__v)); - } - -# if _LIBCPP_STD_VER >= 23 - template ::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Tag, _Fp&& __f, _Args&&... __args) - : __base(__optional_construct_from_invoke_tag{}, std::forward<_Fp>(__f), std::forward<_Args>(__args)...) {} -# endif - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(nullopt_t) noexcept { - reset(); - return *this; - } - - _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(const optional&) = default; - _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(optional&&) = default; - - // LWG2756 - template , - enable_if_t<_And<_IsNotSame<__remove_cvref_t<_Up>, optional>, - _Or<_IsNotSame<__remove_cvref_t<_Up>, _Tp>, _Not>>, - is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>>::value, - int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(_Up&& __v) { - if (this->has_value()) - this->__get() = std::forward<_Up>(__v); - else - this->__construct(std::forward<_Up>(__v)); - return *this; - } - - // LWG2756 - template ::template __enable_assign<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(const optional<_Up>& __v) { - this->__assign_from(__v); - return *this; - } - - // LWG2756 - template ::template __enable_assign<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(optional<_Up>&& __v) { - this->__assign_from(std::move(__v)); - return *this; - } - - template , int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(_Args&&... __args) { - reset(); - this->__construct(std::forward<_Args>(__args)...); - return this->__get(); - } - - template &, _Args...>, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { - reset(); - this->__construct(__il, std::forward<_Args>(__args)...); - return this->__get(); - } - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void - swap(optional& __opt) noexcept((is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>)) { - this->__swap(__opt); - } - - using __base::operator*; - using __base::operator->; - - _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return has_value(); } - - using __base::__get; - using __base::has_value; - using __base::value; - - template > - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& { - static_assert(is_copy_constructible_v<_Tp>, "optional::value_or: T must be copy constructible"); - static_assert(is_convertible_v<_Up, _Tp>, "optional::value_or: U must be convertible to T"); - return this->has_value() ? this->__get() : static_cast<_Tp>(std::forward<_Up>(__v)); - } - - template > - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && { - static_assert(is_move_constructible_v<_Tp>, "optional::value_or: T must be move constructible"); - static_assert(is_convertible_v<_Up, _Tp>, "optional::value_or: U must be convertible to T"); - return this->has_value() ? std::move(this->__get()) : static_cast<_Tp>(std::forward<_Up>(__v)); - } - -# if _LIBCPP_STD_VER >= 23 - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { - using _Up = invoke_result_t<_Func, _Tp&>; - static_assert( - __is_std_optional_v>, "Result of f(value()) must be a specialization of std::optional"); - if (*this) - return std::invoke(std::forward<_Func>(__f), value()); - return remove_cvref_t<_Up>(); - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { - using _Up = invoke_result_t<_Func, const _Tp&>; - static_assert( - __is_std_optional_v>, "Result of f(value()) must be a specialization of std::optional"); - if (*this) - return std::invoke(std::forward<_Func>(__f), value()); - return remove_cvref_t<_Up>(); - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { - using _Up = invoke_result_t<_Func, _Tp&&>; - static_assert(__is_std_optional_v>, - "Result of f(std::move(value())) must be a specialization of std::optional"); - if (*this) - return std::invoke(std::forward<_Func>(__f), std::move(value())); - return remove_cvref_t<_Up>(); - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { - using _Up = invoke_result_t<_Func, const _Tp&&>; - static_assert(__is_std_optional_v>, - "Result of f(std::move(value())) must be a specialization of std::optional"); - if (*this) - return std::invoke(std::forward<_Func>(__f), std::move(value())); - return remove_cvref_t<_Up>(); - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { - using _Up = remove_cv_t>; - static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array"); - static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t"); - static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t"); - static_assert( - __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); - if (*this) - return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value()); - return optional<_Up>(); - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { - using _Up = remove_cv_t>; - static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array"); - static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t"); - static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t"); - static_assert( - __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); - if (*this) - return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value()); - return optional<_Up>(); - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { - using _Up = remove_cv_t>; - static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array"); - static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t"); - static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t"); - static_assert( - __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); - if (*this) - return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value())); - return optional<_Up>(); - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { - using _Up = remove_cv_t>; - static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array"); - static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t"); - static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t"); - static_assert( - __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); - if (*this) - return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value())); - return optional<_Up>(); - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const& - requires is_copy_constructible_v<_Tp> - { - static_assert(is_same_v>, optional>, - "Result of f() should be the same type as this optional"); - if (*this) - return *this; - return std::forward<_Func>(__f)(); - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) && - requires is_move_constructible_v<_Tp> - { - static_assert(is_same_v>, optional>, - "Result of f() should be the same type as this optional"); - if (*this) - return std::move(*this); - return std::forward<_Func>(__f)(); - } -# endif // _LIBCPP_STD_VER >= 23 - - using __base::reset; -}; - -# if _LIBCPP_STD_VER >= 26 -template -class optional<_Tp&> : public __optional_iterator_base<_Tp&> { - using __base _LIBCPP_NODEBUG = __optional_iterator_base<_Tp&>; - - template - static constexpr bool __check_optionalU_ctor = - !is_same_v, optional<_Up>> && !is_same_v<_Tp&, _Up> && is_constructible_v<_Tp&, _QualUp>; - static_assert(!is_same_v, in_place_t>, "instantiation of optional with in_place_t is ill-formed"); - static_assert(!is_same_v, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed"); - -public: - using value_type = _Tp; - - constexpr optional() noexcept = default; - constexpr optional(nullopt_t) noexcept {} - constexpr optional(const optional&) noexcept = default; - - template - requires(is_constructible_v<_Tp&, _Arg> && !reference_constructs_from_temporary_v<_Tp&, _Arg>) - constexpr explicit optional(in_place_t, _Arg&& __arg) : __base(in_place, std::forward<_Arg>(__arg)) {} - - template - requires(!is_same_v, optional> && !is_same_v, in_place_t> && - is_constructible_v<_Tp&, _Up> && !reference_constructs_from_temporary_v<_Tp&, _Up>) - constexpr explicit(!is_convertible_v<_Up, _Tp&>) optional(_Up&& __v) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) - : __base(in_place, std::forward<_Up>(__v)) {} - - template - requires(__check_optionalU_ctor<_Up, _Up&> && !reference_constructs_from_temporary_v<_Tp&, _Up&>) - constexpr explicit(!is_convertible_v<_Up&, _Tp&>) - optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) { - this->__construct_from(__rhs); - } - - template - requires(__check_optionalU_ctor<_Up, const _Up&> && !reference_constructs_from_temporary_v<_Tp&, const _Up&>) - constexpr explicit(!is_convertible_v) - optional(const optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up&>) { - this->__construct_from(__rhs); - } - - template - requires(__check_optionalU_ctor<_Up, _Up> && !reference_constructs_from_temporary_v<_Tp&, _Up>) - constexpr explicit(!is_convertible_v<_Up, _Tp&>) - optional(optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) { - this->__construct_from(std::move(__rhs)); - } - - template - requires(__check_optionalU_ctor<_Up, const _Up> && !reference_constructs_from_temporary_v<_Tp&, const _Up>) - constexpr explicit(!is_convertible_v) - optional(const optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) { - this->__construct_from(std::move(__rhs)); - } - - template - requires(is_same_v<_Tag, __optional_construct_from_invoke_tag>) - _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Tag, _Fp&& __f, _Args&&... __args) - : __base(__optional_construct_from_invoke_tag{}, std::forward<_Fp>(__f), std::forward<_Args>(__args)...) {} - - // deleted overloads - - template - requires(!is_same_v, optional> && !is_same_v, in_place_t> && - is_constructible_v<_Tp&, _Up> && reference_constructs_from_temporary_v<_Tp&, _Up>) - constexpr explicit(!is_convertible_v<_Up, _Tp&>) - optional(_Up&& __v) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) = delete; - - template - requires(__check_optionalU_ctor<_Up, _Up&> && reference_constructs_from_temporary_v<_Tp&, _Up&>) - constexpr explicit(!is_convertible_v<_Up&, _Tp&>) - optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) = delete; - - template - requires(__check_optionalU_ctor<_Up, const _Up&> && reference_constructs_from_temporary_v<_Tp&, const _Up&>) - constexpr explicit(!is_convertible_v) - optional(const optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up&>) = delete; - - template - requires(__check_optionalU_ctor<_Up, _Up> && reference_constructs_from_temporary_v<_Tp&, _Up>) - constexpr explicit(!is_convertible_v<_Up, _Tp&>) - optional(optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) = delete; - - template - requires(__check_optionalU_ctor<_Up, const _Up> && reference_constructs_from_temporary_v<_Tp&, const _Up>) - constexpr explicit(!is_convertible_v) - optional(const optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) = delete; - - constexpr ~optional() = default; - - using __base::__get; - - _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(nullopt_t) noexcept { - reset(); - return *this; - } - - constexpr optional& operator=(const optional&) noexcept = default; - - template - requires(is_constructible_v<_Tp&, _Up> && !reference_constructs_from_temporary_v<_Tp&, _Up>) - constexpr _Tp& emplace(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) { - this->__construct(std::forward<_Up>(__u)); - - return this->__get(); - } - - constexpr void swap(optional& __rhs) noexcept { this->__swap(__rhs); } - - using __base::operator->; - using __base::operator*; - - constexpr explicit operator bool() const noexcept { return has_value(); } - - using __base::has_value; - using __base::value; - - template > - requires(!is_array_v<_Tp> && is_object_v<_Tp>) - [[nodiscard]] constexpr decay_t<_Tp> value_or(_Up&& __v) const { - using _XTp = remove_cv_t<_Tp>; - static_assert(is_constructible_v<_XTp, _Tp&>, "optional::value_or: remove_cv_t must be constructible"); - static_assert(is_convertible_v<_Up, _XTp>, "optional::value_or: U must be convertible to remove_cv_t"); - return this->has_value() ? this->__get() : static_cast<_XTp>(std::forward<_Up>(__v)); - } - - template - [[nodiscard]] constexpr auto and_then(_Func&& __f) const { - using _Up = invoke_result_t<_Func, _Tp&>; - static_assert( - __is_std_optional_v>, "Result of f(value()) must be a specialization of std::optional"); - if (*this) - return std::invoke(std::forward<_Func>(__f), value()); - return remove_cvref_t<_Up>(); - } - - template - [[nodiscard]] constexpr optional>> transform(_Func&& __f) const { - using _Up = remove_cv_t>; - static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array"); - static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t"); - static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t"); - static_assert( - __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional"); - - if (*this) - return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value()); - return optional<_Up>(); - } - - template - [[nodiscard]] constexpr optional or_else(_Func&& __f) const { - static_assert(is_same_v>, optional>, - "Result of f() should be the same type as this optional"); - if (*this) - return *this; - return std::forward<_Func>(__f)(); - } - - using __base::reset; -}; -# endif - -template -optional(_Tp) -> optional<_Tp>; - -// [optional.relops] Relational operators - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() == std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const optional<_Up>& __y) { - if (static_cast(__x) != static_cast(__y)) - return false; - if (!static_cast(__x)) - return true; - return *__x == *__y; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() != std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const optional<_Up>& __y) { - if (static_cast(__x) != static_cast(__y)) - return true; - if (!static_cast(__x)) - return false; - return *__x != *__y; -} - -template < class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() < std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const optional<_Up>& __y) { - if (!static_cast(__y)) - return false; - if (!static_cast(__x)) - return true; - return *__x < *__y; -} - -template < class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() > std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const optional<_Up>& __y) { - if (!static_cast(__x)) - return false; - if (!static_cast(__y)) - return true; - return *__x > *__y; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() <= std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const optional<_Up>& __y) { - if (!static_cast(__x)) - return true; - if (!static_cast(__y)) - return false; - return *__x <= *__y; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() >= std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const optional<_Up>& __y) { - if (!static_cast(__y)) - return true; - if (!static_cast(__x)) - return false; - return *__x >= *__y; -} - -# if _LIBCPP_STD_VER >= 20 - -template _Up> -_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up> -operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) { - if (__x && __y) - return *__x <=> *__y; - return __x.has_value() <=> __y.has_value(); -} - -# endif // _LIBCPP_STD_VER >= 20 - -// [optional.nullops] Comparison with nullopt - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, nullopt_t) noexcept { - return !static_cast(__x); -} - -# if _LIBCPP_STD_VER <= 17 - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(nullopt_t, const optional<_Tp>& __x) noexcept { - return !static_cast(__x); -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, nullopt_t) noexcept { - return static_cast(__x); -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(nullopt_t, const optional<_Tp>& __x) noexcept { - return static_cast(__x); -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>&, nullopt_t) noexcept { - return false; -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(nullopt_t, const optional<_Tp>& __x) noexcept { - return static_cast(__x); -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, nullopt_t) noexcept { - return !static_cast(__x); -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(nullopt_t, const optional<_Tp>&) noexcept { - return true; -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, nullopt_t) noexcept { - return static_cast(__x); -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(nullopt_t, const optional<_Tp>&) noexcept { - return false; -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>&, nullopt_t) noexcept { - return true; -} - -template -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(nullopt_t, const optional<_Tp>& __x) noexcept { - return !static_cast(__x); -} - -# else // _LIBCPP_STD_VER <= 17 - -template -_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept { - return __x.has_value() <=> false; -} - -# endif // _LIBCPP_STD_VER <= 17 - -// [optional.comp.with.t] Comparison with T - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() == std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v) { - if (__x.has_value()) - return *__x == __v; - return false; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() == std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x) { - if (__x.has_value()) - return __v == *__x; - return false; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() != std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v) { - if (__x.has_value()) - return *__x != __v; - return true; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() != std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x) { - if (__x.has_value()) - return __v != *__x; - return true; -} - -template < class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() < std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v) { - if (__x.has_value()) - return *__x < __v; - return true; -} - -template < class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() < std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x) { - if (__x.has_value()) - return __v < *__x; - return false; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() <= std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v) { - if (__x.has_value()) - return *__x <= __v; - return true; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() <= std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x) { - if (__x.has_value()) - return __v <= *__x; - return false; -} - -template < class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() > std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v) { - if (__x.has_value()) - return *__x > __v; - return false; -} - -template < class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() > std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x) { - if (__x.has_value()) - return __v > *__x; - return true; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() >= std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v) { - if (__x.has_value()) - return *__x >= __v; - return false; -} - -template < - class _Tp, - class _Up, - enable_if_t<__is_core_convertible_v() >= std::declval()), bool>, - int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x) { - if (__x.has_value()) - return __v >= *__x; - return true; -} - -# if _LIBCPP_STD_VER >= 20 - -template - requires(!__is_derived_from_optional<_Up>) && three_way_comparable_with<_Tp, _Up> -_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up> -operator<=>(const optional<_Tp>& __x, const _Up& __v) { - return __x.has_value() ? *__x <=> __v : strong_ordering::less; -} - -# endif // _LIBCPP_STD_VER >= 20 - -template && is_swappable_v<_Tp>) -# if _LIBCPP_STD_VER >= 26 - || is_reference_v<_Tp> -# endif - , - int> = 0> -inline _LIBCPP_HIDE_FROM_ABI -_LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(optional<_Tp>& __x, optional<_Tp>& __y) noexcept(noexcept(__x.swap(__y))) { - __x.swap(__y); -} - -struct __make_optional_barrier_tag { - explicit __make_optional_barrier_tag() = default; -}; - -template -inline constexpr bool __is_constructible_for_optional_v = is_constructible_v<_Tp, _Args...>; - -template -struct __is_constructible_for_optional : bool_constant<__is_constructible_for_optional_v<_Tp, _Args...>> {}; - -template -inline constexpr bool __is_constructible_for_optional_initializer_list_v = - is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>; - -# if _LIBCPP_STD_VER >= 26 -template -inline constexpr bool __is_constructible_for_optional_v<_Tp&, _Args...> = false; - -template -inline constexpr bool __is_constructible_for_optional_v<_Tp&, _Arg> = - is_constructible_v<_Tp&, _Arg> && !reference_constructs_from_temporary_v<_Tp&, _Arg>; - -template -inline constexpr bool __is_constructible_for_optional_initializer_list_v<_Tp&, _Up, _Args...> = false; -# endif - -template < -# if _LIBCPP_STD_VER >= 26 - __make_optional_barrier_tag = __make_optional_barrier_tag{}, -# endif - class _Tp, - enable_if_t, _Tp>, int> = 0> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional> make_optional(_Tp&& __v) { - return optional>(std::forward<_Tp>(__v)); -} - -template , int> = 0> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(_Args&&... __args) { - return optional<_Tp>(in_place, std::forward<_Args>(__args)...); -} - -template , int> = 0> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> -make_optional(initializer_list<_Up> __il, _Args&&... __args) { - return optional<_Tp>(in_place, __il, std::forward<_Args>(__args)...); -} - -template -struct hash< __enable_hash_helper, remove_const_t<_Tp>> > { -# if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) - _LIBCPP_DEPRECATED_IN_CXX17 typedef optional<_Tp> argument_type; - _LIBCPP_DEPRECATED_IN_CXX17 typedef size_t result_type; -# endif - - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const optional<_Tp>& __opt) const { - return static_cast(__opt) ? hash>()(*__opt) : 0; - } -}; - -_LIBCPP_END_NAMESPACE_STD - -# endif // _LIBCPP_STD_VER >= 17 - -_LIBCPP_POP_MACROS - # if defined(_LIBCPP_KEEP_TRANSITIVE_INCLUDES_LLVM23) && _LIBCPP_STD_VER <= 20 # include # include diff --git a/libcxx/test/std/experimental/iterator/ostream.joiner/ostream.joiner.creation/make_ostream_joiner.pass.cpp b/libcxx/test/std/experimental/iterator/ostream.joiner/ostream.joiner.creation/make_ostream_joiner.pass.cpp index 05f798fcae3d..0f16ff3b31d5 100644 --- a/libcxx/test/std/experimental/iterator/ostream.joiner/ostream.joiner.creation/make_ostream_joiner.pass.cpp +++ b/libcxx/test/std/experimental/iterator/ostream.joiner/ostream.joiner.creation/make_ostream_joiner.pass.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "test_macros.h" #include "test_iterators.h" diff --git a/libcxx/test/std/experimental/iterator/ostream.joiner/ostream.joiner.ops/ostream_joiner.op.assign.pass.cpp b/libcxx/test/std/experimental/iterator/ostream.joiner/ostream.joiner.ops/ostream_joiner.op.assign.pass.cpp index 7a193e839f2a..f7e5bdcccbee 100644 --- a/libcxx/test/std/experimental/iterator/ostream.joiner/ostream.joiner.ops/ostream_joiner.op.assign.pass.cpp +++ b/libcxx/test/std/experimental/iterator/ostream.joiner/ostream.joiner.ops/ostream_joiner.op.assign.pass.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "test_macros.h" #include "test_iterators.h" diff --git a/libcxx/test/std/utilities/optional/optional.bad_optional_access/derive.pass.cpp b/libcxx/test/std/utilities/optional/optional.bad_optional_access/derive.pass.cpp index 9cf3b0893012..606ee4002040 100644 --- a/libcxx/test/std/utilities/optional/optional.bad_optional_access/derive.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.bad_optional_access/derive.pass.cpp @@ -12,6 +12,7 @@ // class bad_optional_access : public exception +#include #include #include diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ctor.verify.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ctor.verify.cpp index 00ca941668eb..a13b4334da33 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ctor.verify.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ctor.verify.cpp @@ -26,26 +26,26 @@ int main(int, char**) { // clang-format off { #if TEST_STD_VER >= 26 - std::optional opt2; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with an rvalue reference type is ill-formed}} + std::optional opt2; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with an rvalue reference type is ill-formed}} #else - std::optional o1; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a reference type is ill-formed}} + std::optional o1; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with a reference type is ill-formed}} #endif - std::optional o2; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} - std::optional o3; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with an array type is ill-formed}} + std::optional o2; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} + std::optional o3; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with an array type is ill-formed}} } { - std::optional< std::in_place_t> o1; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} - std::optional o2; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} - std::optional< volatile std::in_place_t> o3; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} - std::optional o4; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} + std::optional< std::in_place_t> o1; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} + std::optional o2; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} + std::optional< volatile std::in_place_t> o3; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} + std::optional o4; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with in_place_t is ill-formed}} } { - std::optional< std::nullopt_t> o1; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} - std::optional o2; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} - std::optional< volatile std::nullopt_t> o3; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} - std::optional o4; // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} + std::optional< std::nullopt_t> o1; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} + std::optional o2; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} + std::optional< volatile std::nullopt_t> o3; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} + std::optional o4; // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} } // clang-format on return 0; diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/deduct.verify.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/deduct.verify.cpp index 7ab842bf68c5..28d3c61db4a9 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/deduct.verify.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/deduct.verify.cpp @@ -31,7 +31,7 @@ int main(int, char**) { { // optional(nullopt_t) - std::optional opt(std::nullopt); // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} + std::optional opt(std::nullopt); // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with nullopt_t is ill-formed}} } // clang-format on return 0; diff --git a/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp b/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp index a956ab3a219c..cdf456c4154f 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional_requires_destructible_object.verify.cpp @@ -28,30 +28,30 @@ int main(int, char**) using std::optional; { #if TEST_STD_VER >= 26 - // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with an rvalue reference type is ill-formed}} + // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with an rvalue reference type is ill-formed}} #else - // expected-error-re@optional:* 2 {{static assertion failed{{.*}}instantiation of optional with a reference type is ill-formed}} + // expected-error-re@*:* 2 {{static assertion failed{{.*}}instantiation of optional with a reference type is ill-formed}} #endif optional opt1; optional opt2; } { - // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} - optional opt3; + // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} + optional opt3; } { - // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-object type is undefined behavior}} - // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} - optional opt4; + // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with a non-object type is undefined behavior}} + // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} + optional opt4; } { - // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-object type is undefined behavior}} - // expected-error-re@optional:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} - // expected-error@optional:* 1+ {{cannot form a reference to 'void'}} - optional opt4; + // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with a non-object type is undefined behavior}} + // expected-error-re@*:* {{static assertion failed{{.*}}instantiation of optional with a non-destructible type is ill-formed}} + // expected-error@*:* 1+ {{cannot form a reference to 'void'}} + optional opt4; } // FIXME these are garbage diagnostics that Clang should not produce - // expected-error@optional:* 0+ {{is not a base class}} + // expected-error@*:* 0+ {{is not a base class}} - return 0; + return 0; }