diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -100,7 +100,7 @@ "`P1478R8 `__","LWG", "``Byte-wise`` ``atomic`` ``memcpy``", "November 2022","","","|concurrency TS|" "`P2167R3 `__","LWG", "Improved Proposed Wording for LWG 2114", "November 2022","","","" "`P2396R1 `__","LWG", "Concurrency TS 2 fixes ", "November 2022","","","|concurrency TS|" -"`P2505R5 `__","LWG", "Monadic Functions for ``std::expected``", "November 2022","","","" +"`P2505R5 `__","LWG", "Monadic Functions for ``std::expected``", "November 2022","July 2022","|Complete|","16.0" "`P2539R4 `__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","","","|format|" "`P2602R2 `__","LWG", "Poison Pills are Too Toxic", "November 2022","","","|ranges|" "`P2708R1 `__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","","" diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h --- a/libcxx/include/__expected/expected.h +++ b/libcxx/include/__expected/expected.h @@ -14,10 +14,12 @@ #include <__expected/bad_expected_access.h> #include <__expected/unexpect.h> #include <__expected/unexpected.h> +#include <__functional/invoke.h> #include <__memory/addressof.h> #include <__memory/construct_at.h> #include <__type_traits/conjunction.h> #include <__type_traits/disjunction.h> +#include <__type_traits/integral_constant.h> #include <__type_traits/is_assignable.h> #include <__type_traits/is_constructible.h> #include <__type_traits/is_convertible.h> @@ -60,8 +62,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +class expected; + namespace __expected { +template +struct __is_expected : false_type {}; + +template +struct __is_expected> : true_type {}; + +struct __expected_construct_in_place_from_invoke_tag {}; +struct __expected_construct_unexpected_from_invoke_tag {}; + template _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) { # ifndef _LIBCPP_NO_EXCEPTIONS @@ -166,6 +180,15 @@ _Not, const expected<_Up, _OtherErr>&>>, _Not, const expected<_Up, _OtherErr>>> >; + template + constexpr explicit expected( + __expected::__expected_construct_in_place_from_invoke_tag __tag, _Func&& __f, _Args&&... __args) + : __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(true) {} + + template + constexpr explicit expected( + __expected::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args) + : __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(false) {} public: template @@ -595,6 +618,227 @@ return __has_val_ ? std::move(__union_.__val_) : static_cast<_Tp>(std::forward<_Up>(__v)); } + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __v) const& { + static_assert(is_copy_constructible_v<_Err>, "error_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + return __has_val_ ? static_cast<_Err>(std::forward<_Up>(__v)) : __union_.__unex_; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __v) && { + static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + return __has_val_ ? static_cast<_Err>(std::forward<_Up>(__v)) : std::move(__union_.__unex_); + } + + // [expected.void.monadic], monadic + template + requires is_copy_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_expected<_Up>::value, "result of f(value()) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t>::error_type must same as error_type"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), value()); + } + return _Up(unexpect, error()); + } + + template + requires is_copy_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_expected<_Up>::value, "result of f(value()) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t>::error_type must same as error_type"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), value()); + } + return _Up(unexpect, error()); + } + + template + requires is_move_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, + "result of f(std::move(value())) must be a specialization of std::expected"); + static_assert( + is_same_v, + "std::remove_cvref_t>::error_type must same as error_type"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), std::move(value())); + } + return _Up(unexpect, std::move(error())); + } + + template + requires is_move_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, + "result of f(std::move(value())) must be a specialization of std::expected"); + static_assert( + is_same_v, + "std::remove_cvref_t>::error_type must same as error_type"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), std::move(value())); + } + return _Up(unexpect, std::move(error())); + } + + template + requires is_copy_constructible_v<_Tp> _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_expected<_Up>::value, "result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t::value_type must same as value_type"); + if (has_value()) { + return _Up(in_place, value()); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + requires is_copy_constructible_v<_Tp> _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_expected<_Up>::value, "result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t::value_type must same as value_type"); + if (has_value()) { + return _Up(in_place, value()); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + requires is_move_constructible_v<_Tp> _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, + "result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t::value_type must same as value_type"); + if (has_value()) { + return _Up(in_place, std::move(value())); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_move_constructible_v<_Tp> _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, + "result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t::value_type must same as value_type"); + if (has_value()) { + return _Up(in_place, std::move(value())); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_copy_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + using _Up = remove_cv_t>; + if (has_value()) { + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), value()); + } else { + std::invoke(std::forward<_Func>(__f), value()); + return expected<_Up, _Err>(); + } + } + return expected<_Up, _Err>(unexpect, error()); + } + + template + requires is_copy_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + using _Up = remove_cv_t>; + if (has_value()) { + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), value()); + } else { + std::invoke(std::forward<_Func>(__f), value()); + return expected<_Up, _Err>(); + } + } + return expected<_Up, _Err>(unexpect, error()); + } + + template + requires is_move_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + using _Up = remove_cv_t>; + if (has_value()) { + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value())); + } else { + std::invoke(std::forward<_Func>(__f), std::move(value())); + return expected<_Up, _Err>(); + } + } + return expected<_Up, _Err>(unexpect, std::move(error())); + } + + template + requires is_move_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + using _Up = remove_cv_t>; + if (has_value()) { + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value())); + } else { + std::invoke(std::forward<_Func>(__f), std::move(value())); + return expected<_Up, _Err>(); + } + } + return expected<_Up, _Err>(unexpect, std::move(error())); + } + + template + requires is_copy_constructible_v<_Tp> _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { + using _Up = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Up>(in_place, value()); + } + return expected<_Tp, _Up>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + requires is_copy_constructible_v<_Tp> _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { + using _Up = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Up>(in_place, value()); + } + return expected<_Tp, _Up>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + requires is_move_constructible_v<_Tp> _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { + using _Up = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Up>(in_place, std::move(value())); + } + return expected<_Tp, _Up>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_move_constructible_v<_Tp> _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { + using _Up = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Up>(in_place, std::move(value())); + } + return expected<_Tp, _Up>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + // [expected.object.eq], equality operators template requires(!is_void_v<_T2>) @@ -626,6 +870,16 @@ _LIBCPP_NO_UNIQUE_ADDRESS union __union_t { _LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {} + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t( + __expected::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args) + : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t( + __expected::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args) + : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>) = default; @@ -759,6 +1013,19 @@ std::construct_at(std::addressof(__union_.__unex_), __il, std::forward<_Args>(__args)...); } +private: + template + constexpr explicit expected(__expected::__expected_construct_in_place_from_invoke_tag, _Func&& __f) + : __has_val_(true) { + std::invoke(std::forward<_Func>(__f)); + } + + template + constexpr explicit expected( + __expected::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args) + : __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(false) {} + +public: // [expected.void.dtor], destructor _LIBCPP_HIDE_FROM_ABI constexpr ~expected() @@ -926,6 +1193,221 @@ return std::move(__union_.__unex_); } + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __v) const& { + static_assert(is_copy_constructible_v<_Err>, "error_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + return __has_val_ ? static_cast<_Err>(std::forward<_Up>(__v)) : __union_.__unex_; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __v) && { + static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + return __has_val_ ? static_cast<_Err>(std::forward<_Up>(__v)) : std::move(__union_.__unex_); + } + + // [expected.void.monadic], monadic + template + requires is_copy_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, "result of f() must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t>::error_type must same as error_type"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, error()); + } + + template + requires is_copy_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, "result of f() must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t>::error_type must same as error_type"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, error()); + } + + template + requires is_move_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, "result of f() must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t>::error_type must same as error_type"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, std::move(error())); + } + + template + requires is_move_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, "result of f() must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t>::error_type must same as error_type"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_expected<_Up>::value, "result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t::value_type must same as value_type"); + if (has_value()) { + return _Up(); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_expected<_Up>::value, "result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t::value_type must same as value_type"); + if (has_value()) { + return _Up(); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, + "result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t::value_type must same as value_type"); + if (has_value()) { + return _Up(); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_expected<_Up>::value, + "result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "std::remove_cvref_t::value_type must same as value_type"); + if (has_value()) { + return _Up(); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_copy_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + using _Up = remove_cv_t>; + if (has_value()) { + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + return expected<_Up, _Err>(unexpect, error()); + } + + template + requires is_copy_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + using _Up = remove_cv_t>; + if (has_value()) { + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + return expected<_Up, _Err>(unexpect, error()); + } + + template + requires is_move_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + using _Up = remove_cv_t>; + if (has_value()) { + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + return expected<_Up, _Err>(unexpect, std::move(error())); + } + + template + requires is_move_constructible_v<_Err> _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + using _Up = remove_cv_t>; + if (has_value()) { + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + return expected<_Up, _Err>(unexpect, std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { + using _Up = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Up>(); + } + return expected<_Tp, _Up>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { + using _Up = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Up>(); + } + return expected<_Tp, _Up>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { + using _Up = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Up>(); + } + return expected<_Tp, _Up>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { + using _Up = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Up>(in_place); + } + return expected<_Tp, _Up>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + // [expected.void.eq], equality operators template requires is_void_v<_T2> @@ -948,6 +1430,11 @@ _LIBCPP_NO_UNIQUE_ADDRESS union __union_t { _LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {} + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t( + __expected::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args) + : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() requires(is_trivially_destructible_v<_Err>) = default; diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/and_then.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/and_then.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/and_then.pass.cpp @@ -0,0 +1,268 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template constexpr auto and_then(F&& f) &; +// template constexpr auto and_then(F&& f) const &; +// template constexpr auto and_then(F&& f) &&; +// template constexpr auto and_then(F&& f) const &&; + +#include +#include +#include + +struct LVal { + constexpr std::expected operator()(int&) { return 1; } + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct CLVal { + std::expected operator()(int&) = delete; + constexpr std::expected operator()(const int&) { return 1; } + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct RVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + constexpr std::expected operator()(int&&) { return 1; } + std::expected operator()(const int&&) = delete; +}; + +struct CRVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + constexpr std::expected operator()(const int&&) { return 1; } +}; + +struct RefQual { + constexpr std::expected operator()(int) & { return 1; } + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct CRefQual { + std::expected operator()(int) & = delete; + constexpr std::expected operator()(int) const& { return 1; } + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct RVRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + constexpr std::expected operator()(int) && { return 1; } + std::expected operator()(int) const&& = delete; +}; + +struct RVCRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + constexpr std::expected operator()(int) const&& { return 1; } +}; + +struct NOLVal { + constexpr std::expected operator()(int&) { return std::expected(std::unexpected(5)); } + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct NOCLVal { + std::expected operator()(int&) = delete; + constexpr std::expected operator()(const int&) { return std::expected(std::unexpected(5)); } + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct NORVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + constexpr std::expected operator()(int&&) { return std::expected(std::unexpected(5)); } + std::expected operator()(const int&&) = delete; +}; + +struct NOCRVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + constexpr std::expected operator()(const int&&) { return std::expected(std::unexpected(5)); } +}; + +struct NORefQual { + constexpr std::expected operator()(int) & { return std::expected(std::unexpected(5)); } + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct NOCRefQual { + std::expected operator()(int) & = delete; + constexpr std::expected operator()(int) const& { return std::expected(std::unexpected(5)); } + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct NORVRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + constexpr std::expected operator()(int) && { return std::expected(std::unexpected(5)); } + std::expected operator()(int) const&& = delete; +}; + +struct NORVCRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + constexpr std::expected operator()(int) const&& { return std::expected(std::unexpected(5)); } +}; + +struct NonCopy { + NonCopy() = default; + NonCopy(const NonCopy&) { assert(false); } + std::expected operator()(const NonCopy&&) { return 1; } +}; + +struct NonConst { + std::expected non_const() { return 1; } +}; + +// clang-format off +constexpr void test_val_types() { + // Test & overload + { + // Without &qualifier on F'soperator() + { + std::expected e{0}; + assert(e.and_then(LVal{}).value() == 1); + assert(e.and_then(NOLVal{}).error() == 5); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e{0}; + RefQual l{}; + assert(e.and_then(l) == 1); + NORefQual nl{}; + assert(e.and_then(nl).error() == 5); + static_assert(std::is_same_v>); + } + } + + // Test const& overload + { + // Without & qualifier on F's operator() + { + const std::expected e{0}; + assert(e.and_then(CLVal{}).value() == 1); + assert(e.and_then(NOCLVal{}).error() == 5); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + const std::expected e{0}; + const CRefQual l{}; + assert(e.and_then(l) == 1); + const NOCRefQual nl{}; + assert(e.and_then(nl).error() == 5); + static_assert(std::is_same_v>); + } + } + + // Test && overload + { + // Without & qualifier on F's operator() + { + std::expected e{0}; + assert(std::move(e).and_then(RVal{}) == 1); + assert(std::move(e).and_then(NORVal{}).error() == 5); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e{0}; + assert(e.and_then(RVRefQual{}) == 1); + assert(e.and_then(NORVRefQual{}).error() == 5); + static_assert(std::is_same_v>); + } + } + + // Test const&& overload + { + // Without & qualifier on F's operator() + { + const std::expected e{0}; + assert(std::move(e).and_then(CRVal{}) == 1); + assert(std::move(e).and_then(NOCRVal{}).error() == 5); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + const std::expected e{0}; + const RVCRefQual l{}; + assert(std::move(e).and_then(std::move(l)) == 1); + const NORVCRefQual nl{}; + assert(std::move(e).and_then(std::move(nl)).error() == 5); + static_assert(std::is_same_v>); + } + } +} +// clang-format on + +// check that the lambda body is not instantiated during overload resolution +constexpr void test_sfinae() { + std::expected e(std::unexpected(2)); + auto l = [](auto&& x) { return x.non_const(); }; + e.and_then(l); + std::move(e).and_then(l); +} + +constexpr bool test() { + test_sfinae(); + test_val_types(); + + std::expected e(std::unexpected(1)); + const auto& ce = e; + + const auto never_called = [](int) { + assert(false); + return std::expected(); + }; + + e.and_then(never_called); + std::move(e).and_then(never_called); + ce.and_then(never_called); + std::move(ce).and_then(never_called); + + std::expected nc(std::unexpect, 0); + const auto& cnc = nc; + std::move(nc).and_then(NonCopy{}); + std::move(cnc).and_then(NonCopy{}); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/or_else.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/or_else.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/or_else.pass.cpp @@ -0,0 +1,198 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template constexpr auto or_else(F&& f) &; +// template constexpr auto or_else(F&& f) const &; +// template constexpr auto or_else(F&& f) &&; +// template constexpr auto or_else(F&& f) const &&; + +#include +#include +#include + +struct LVal { + constexpr std::expected operator()(int&) { return 1; } + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct CLVal { + std::expected operator()(int&) = delete; + constexpr std::expected operator()(const int&) { return 1; } + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct RVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + constexpr std::expected operator()(int&&) { return 1; } + std::expected operator()(const int&&) = delete; +}; + +struct CRVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + constexpr std::expected operator()(const int&&) { return 1; } +}; + +struct RefQual { + constexpr std::expected operator()(int) & { return 1; } + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct CRefQual { + std::expected operator()(int) & = delete; + constexpr std::expected operator()(int) const& { return 1; } + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct RVRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + constexpr std::expected operator()(int) && { return 1; } + std::expected operator()(int) const&& = delete; +}; + +struct RVCRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + constexpr std::expected operator()(int) const&& { return 1; } +}; + +struct NonCopy { + NonCopy() = default; + NonCopy(const NonCopy&) { assert(false); } + std::expected operator()(const NonCopy&&) { return 1; } +}; + +// clang-format off +constexpr void test_val_types() { + // Test & overload + { + // Without & qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(e.or_else(LVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator + { + std::expected e(std::unexpected(0)); + RefQual l{}; + assert(e.or_else(l) == 1); + static_assert(std::is_same_v>); + } + } + + // Test const& overload + { + // Without const& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + assert(e.or_else(CLVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With const& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + const CRefQual l{}; + assert(e.or_else(l) == 1); + static_assert(std::is_same_v>); + } + } + + // Test && overload + { + // Without && qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(std::move(e).or_else(RVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With && qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(std::move(e).or_else(RVRefQual{}) == 1); + static_assert(std::is_same_v>); + } + } + + // Test const&& overload + { + // Without const&& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + assert(std::move(e).or_else(CRVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With const&& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + const RVCRefQual l{}; + assert(std::move(e).or_else(std::move(l)) == 1); + static_assert(std::is_same_v>); + } + } +} +// clang-format on + +struct NonConst { + std::expected non_const() { return std::expected(std::unexpect, 1); } +}; + +// check that the lambda body is not instantiated during overload resolution +constexpr void test_sfinae() { + std::expected e{1}; + auto l = [](auto&& x) { return x.non_const(); }; + e.or_else(l); + std::move(e).or_else(l); +} + +constexpr bool test() { + test_sfinae(); + test_val_types(); + + std::expected e(1); + const auto& ce = e; + + const auto never_called = [](int) { + assert(false); + return std::expected(); + }; + + e.or_else(never_called); + std::move(e).or_else(never_called); + ce.or_else(never_called); + std::move(ce).or_else(never_called); + + std::expected nc(0); + const auto& cnc = nc; + std::move(nc).or_else(NonCopy{}); + std::move(cnc).or_else(NonCopy{}); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp @@ -0,0 +1,234 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template constexpr auto transform(F&& f) &; +// template constexpr auto transform(F&& f) const &; +// template constexpr auto transform(F&& f) &&; +// template constexpr auto transform(F&& f) const &&; + +#include +#include +#include + +struct LVal { + constexpr int operator()(int&) { return 1; } + int operator()(const int&) = delete; + int operator()(int&&) = delete; + int operator()(const int&&) = delete; +}; + +struct CLVal { + int operator()(int&) = delete; + constexpr int operator()(const int&) { return 1; } + int operator()(int&&) = delete; + int operator()(const int&&) = delete; +}; + +struct RVal { + int operator()(int&) = delete; + int operator()(const int&) = delete; + constexpr int operator()(int&&) { return 1; } + int operator()(const int&&) = delete; +}; + +struct CRVal { + int operator()(int&) = delete; + int operator()(const int&) = delete; + int operator()(int&&) = delete; + constexpr int operator()(const int&&) { return 1; } +}; + +struct RefQual { + constexpr int operator()(int) & { return 1; } + int operator()(int) const& = delete; + int operator()(int) && = delete; + int operator()(int) const&& = delete; +}; + +struct CRefQual { + int operator()(int) & = delete; + constexpr int operator()(int) const& { return 1; } + int operator()(int) && = delete; + int operator()(int) const&& = delete; +}; + +struct RVRefQual { + int operator()(int) & = delete; + int operator()(int) const& = delete; + constexpr int operator()(int) && { return 1; } + int operator()(int) const&& = delete; +}; + +struct RVCRefQual { + int operator()(int) & = delete; + int operator()(int) const& = delete; + int operator()(int) && = delete; + constexpr int operator()(int) const&& { return 1; } +}; + +struct NonCopy { + int value; + constexpr explicit NonCopy(int val) : value(val) {} + NonCopy(const NonCopy&) = delete; +}; + +struct NonConst { + int non_const() { return 1; } +}; + +// clang-format off +constexpr void test_val_types() { + // Test & overload + { + // Without &qualifier on F'soperator() + { + std::expected e(0); + assert(e.transform(LVal{}).value() == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e(0); + RefQual l{}; + assert(e.transform(l) == 1); + static_assert(std::is_same_v>); + } + } + + // Test const& overload + { + // Without & qualifier on F's operator() + { + const std::expected e(0); + assert(e.transform(CLVal{}).value() == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + const std::expected e(0); + const CRefQual l{}; + assert(e.transform(l).value() == 1); + static_assert(std::is_same_v>); + } + } + + // Test && overload + { + // Without & qualifier on F's operator() + { + std::expected e(0); + assert(std::move(e).transform(RVal{}).value() == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e(0); + assert(e.transform(RVRefQual{}).value() == 1); + static_assert(std::is_same_v>); + } + } + + // Test const&& overload + { + // Without & qualifier on F's operator() + { + const std::expected e(0); + assert(std::move(e).transform(CRVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + const std::expected e(0); + const RVCRefQual l{}; + assert(e.transform(std::move(l)) == 1); + static_assert(std::is_same_v>); + } + } +} +// clang-format on + +constexpr void test_take_val_return_void() { + std::expected e(1); + int val = 0; + e.transform([&val](T&&) -> void { + static_assert(std::is_same_v); + assert(val == 0); + val = 1; + }); + assert(val == 1); + std::move(e).transform([&val](T&&) -> void { + static_assert(std::is_same_v); + assert(val == 1); + val = 2; + }); + + const auto& ce = e; + assert(val == 2); + ce.transform([&val](T&&) -> void { + static_assert(std::is_same_v); + assert(val == 2); + val = 3; + }); + assert(val == 3); + std::move(ce).transform([&val](T&&) -> void { + static_assert(std::is_same_v); + assert(val == 3); + val = 4; + }); + assert(val == 4); +} + +// check val member is direct-non-list-initialized with invoke(std::forward(f), value()) +constexpr void test_direct_non_list_init() { + auto xform = [](int i) { return NonCopy(i); }; + std::expected e(2); + std::expected n = e.transform(xform); + assert(n.value().value == 2); +} + +// check that the lambda body is not instantiated during overload resolution +constexpr void test_sfinae() { + std::expected e(std::unexpected(2)); + auto l = [](auto&& x) { return x.non_const(); }; + e.transform(l); + std::move(e).transform(l); + + std::expected e1(std::unexpected(1)); + const auto& ce1 = e1; + const auto never_called = [](int) { + assert(false); + return std::expected(); + }; + + e1.transform(never_called); + std::move(e1).transform(never_called); + ce1.and_then(never_called); + std::move(ce1).transform(never_called); +} + +constexpr bool test() { + test_sfinae(); + test_val_types(); + test_direct_non_list_init(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp @@ -0,0 +1,204 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template constexpr auto transform_error(F&& f) &; +// template constexpr auto transform_error(F&& f) const &; +// template constexpr auto transform_error(F&& f) &&; +// template constexpr auto transform_error(F&& f) const &&; + +#include +#include +#include + +struct LVal { + constexpr int operator()(int&) { return 1; } + int operator()(const int&) = delete; + int operator()(int&&) = delete; + int operator()(const int&&) = delete; +}; + +struct CLVal { + int operator()(int&) = delete; + constexpr int operator()(const int&) { return 1; } + int operator()(int&&) = delete; + int operator()(const int&&) = delete; +}; + +struct RVal { + int operator()(int&) = delete; + int operator()(const int&) = delete; + constexpr int operator()(int&&) { return 1; } + int operator()(const int&&) = delete; +}; + +struct CRVal { + int operator()(int&) = delete; + int operator()(const int&) = delete; + int operator()(int&&) = delete; + constexpr int operator()(const int&&) { return 1; } +}; + +struct RefQual { + constexpr int operator()(int) & { return 1; } + int operator()(int) const& = delete; + int operator()(int) && = delete; + int operator()(int) const&& = delete; +}; + +struct CRefQual { + int operator()(int) & = delete; + constexpr int operator()(int) const& { return 1; } + int operator()(int) && = delete; + int operator()(int) const&& = delete; +}; + +struct RVRefQual { + int operator()(int) & = delete; + int operator()(int) const& = delete; + constexpr int operator()(int) && { return 1; } + int operator()(int) const&& = delete; +}; + +struct RVCRefQual { + int operator()(int) & = delete; + int operator()(int) const& = delete; + int operator()(int) && = delete; + constexpr int operator()(int) const&& { return 1; } +}; + +struct NonCopy { + int value; + constexpr explicit NonCopy(int val) : value(val) {} + NonCopy(const NonCopy&) = delete; +}; + +struct NonConst { + int non_const() { return 1; } +}; + +// clang-format off +constexpr void test_val_types() { + // Test & overload + { + // Without & qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(e.transform_error(LVal{}).error() == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + RefQual l{}; + assert(e.transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + } + + // Test const& overload + { + // Without const& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + assert(e.transform_error(CLVal{}).error() == 1); + static_assert(std::is_same_v>); + } + + // With const& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + const CRefQual l{}; + assert(e.transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + } + + // Test && overload + { + // Without && qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(std::move(e).transform_error(RVal{}).error() == 1); + static_assert(std::is_same_v>); + } + + // With && qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(std::move(e).transform_error(RVRefQual{}).error() == 1); + static_assert(std::is_same_v>); + } + } + + // Test const&& overload + { + // Without const&& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + assert(std::move(e).transform_error(CRVal{}).error() == 1); + static_assert(std::is_same_v>); + } + + // With const&& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + const RVCRefQual l{}; + assert(std::move(e).transform_error(std::move(l)).error() == 1); + static_assert(std::is_same_v>); + } + } +} +// clang-format on + +// check unex member is direct-non-list-initialized with invoke(std::forward(f), error()) +constexpr void test_direct_non_list_init() { + auto xform = [](int i) { return NonCopy(i); }; + std::expected e(std::unexpected(2)); + std::expected n = e.transform_error(xform); + assert(n.error().value == 2); +} + +// check that the lambda body is not instantiated during overload resolution +constexpr void test_sfinae() { + std::expected e(2); + auto l = [](auto&& x) { return x.non_const(); }; + e.transform_error(l); + std::move(e).transform_error(l); + + std::expected e1; + const auto& ce1 = e1; + + const auto never_called = [](int) { + assert(false); + return 0; + }; + + e1.transform_error(never_called); + std::move(e1).transform_error(never_called); + ce1.transform_error(never_called); + std::move(ce1).transform_error(never_called); +} + +constexpr bool test() { + test_sfinae(); + test_val_types(); + test_direct_non_list_init(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/observers/error_or.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/observers/error_or.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/observers/error_or.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template constexpr E error_or(G&& e) const &; +// template constexpr E error_or(G&& e) &&; + +#include +#include +#include +#include +#include + +#include "MoveOnly.h" +#include "test_macros.h" + +constexpr bool test() { + // const &, has_value() + { + const std::expected e(5); + std::same_as decltype(auto) x = e.error_or(10); + assert(x == 10); + } + + // const &, !has_value() + { + const std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = e.error_or(10); + assert(x == 5); + } + + // &&, has_value() + { + std::expected e(5); + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x == 10); + } + + // &&, !has_value() + { + std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x == 5); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); +} diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/and_then.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/and_then.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/monadic/and_then.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template constexpr auto and_then(F&& f) &; +// template constexpr auto and_then(F&& f) const &; +// template constexpr auto and_then(F&& f) &&; +// template constexpr auto and_then(F&& f) const &&; + +#include +#include +#include + +constexpr void test_val_types() { + // Test & overload + { + auto l = [] -> std::expected { return 2; }; + std::expected v; + assert(v.and_then(l).value() == 2); + static_assert(std::is_same_v< decltype(v.and_then(l)), std::expected>); + } + + // Test const& overload + { + auto l = [] -> std::expected { return 2; }; + const std::expected v; + assert(v.and_then(l).value() == 2); + static_assert(std::is_same_v< decltype(v.and_then(l)), std::expected>); + } + + // Test && overload + { + auto l = [] -> std::expected { return 2; }; + std::expected v; + assert(std::move(v).and_then(l).value() == 2); + static_assert(std::is_same_v< decltype(std::move(v).and_then(l)), std::expected>); + } + + // Test const&& overload + { + auto l = [] -> std::expected { return 2; }; + const std::expected v; + assert(std::move(v).and_then(l).value() == 2); + static_assert(std::is_same_v< decltype(std::move(v).and_then(l)), std::expected>); + } +} + +constexpr void test_fail() { + // Test & overload + { + auto f = [] -> std::expected { throw 1; }; + std::expected v(std::unexpected(2)); + assert(v.and_then(f).error() == 2); + static_assert(std::is_same_v< decltype(v.and_then(f)), std::expected>); + } + + // Test const& overload + { + auto f = [] -> std::expected { throw 1; }; + const std::expected v(std::unexpected(2)); + assert(v.and_then(f).error() == 2); + static_assert(std::is_same_v< decltype(v.and_then(f)), std::expected>); + } + + // Test && overload + { + auto f = [] -> std::expected { throw 1; }; + std::expected v(std::unexpected(2)); + assert(std::move(v).and_then(f).error() == 2); + static_assert(std::is_same_v< decltype(std::move(v).and_then(f)), std::expected>); + } + + // Test const&& overload + { + auto f = [] -> std::expected { throw 1; }; + const std::expected v(std::unexpected(2)); + assert(std::move(v).and_then(f).error() == 2); + static_assert(std::is_same_v< decltype(std::move(v).and_then(f)), std::expected>); + } +} + +constexpr bool test() { + test_fail(); + test_val_types(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/or_else.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/or_else.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/monadic/or_else.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template constexpr auto or_else(F&& f) &; +// template constexpr auto or_else(F&& f) const &; +// template constexpr auto or_else(F&& f) &&; +// template constexpr auto or_else(F&& f) const &&; + +#include +#include +#include + +constexpr void test_val_types() { + // Test & overload + { + auto l = [](auto) -> std::expected { return {}; }; + std::expected v(std::unexpected(1)); + assert(v.or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [](auto) -> std::expected { return {}; }; + const std::expected v(std::unexpected(1)); + assert(v.or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [](auto) -> std::expected { return {}; }; + std::expected v(std::unexpected(1)); + assert(std::move(v).or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [](auto) -> std::expected { return {}; }; + const std::expected v(std::unexpected(1)); + assert(std::move(v).or_else(l).has_value()); + static_assert(std::is_same_v>); + } +} + +constexpr void test_fail() { + // Test & overload + { + auto l = [](auto) -> std::expected { throw 1; }; + std::expected v; + assert(v.or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [](auto) -> std::expected { throw 1; }; + const std::expected v; + assert(v.or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [](auto) -> std::expected { throw 1; }; + std::expected v; + assert(std::move(v).or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [](auto) -> std::expected { throw 1; }; + const std::expected v; + assert(std::move(v).or_else(l).has_value()); + static_assert(std::is_same_v>); + } +} + +constexpr bool test() { + test_fail(); + test_val_types(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/transform.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/transform.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/monadic/transform.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template constexpr auto transform_error(F&& f) &; +// template constexpr auto transform_error(F&& f) const &; +// template constexpr auto transform_error(F&& f) &&; +// template constexpr auto transform_error(F&& f) const &&; + +#include +#include +#include + +constexpr void test_val_types() { + // Test & overload + { + auto l = [] -> int { return 1; }; + std::expected v; + assert(v.transform(l).value() == 1); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [] -> int { return 1; }; + const std::expected v; + assert(v.transform(l).value() == 1); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [] -> int { return 1; }; + std::expected v; + assert(std::move(v).transform(l).value() == 1); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [] -> int { return 1; }; + const std::expected v; + assert(std::move(v).transform(l).value() == 1); + static_assert(std::is_same_v>); + } +} + +constexpr void test_fail() { + // Test & overload + { + auto l = [] -> int { throw 1; }; + std::expected v(std::unexpected(5)); + assert(v.transform(l).error() == 5); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [] -> int { throw 1; }; + const std::expected v(std::unexpected(5)); + assert(v.transform(l).error() == 5); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [] -> int { throw 1; }; + std::expected v(std::unexpected(5)); + assert(std::move(v).transform(l).error() == 5); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [] -> int { throw 1; }; + const std::expected v(std::unexpected(5)); + assert(std::move(v).transform(l).error() == 5); + static_assert(std::is_same_v>); + } +} + +constexpr bool test() { + test_fail(); + test_val_types(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions + +// + +// template constexpr auto transform_error(F&& f) &; +// template constexpr auto transform_error(F&& f) const &; +// template constexpr auto transform_error(F&& f) &&; +// template constexpr auto transform_error(F&& f) const &&; + +#include +#include +#include + +struct NonCopy { + int value; + constexpr explicit NonCopy(int val) : value(val) {} + NonCopy(const NonCopy&) = delete; +}; + +constexpr void test_val_types() { + // Test & overload + { + auto l = [](auto) -> int { return 1; }; + std::expected v(std::unexpected(2)); + assert(v.transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [](auto) -> int { return 1; }; + const std::expected v(std::unexpected(2)); + assert(v.transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [](auto) -> int { return 1; }; + std::expected v(std::unexpected(2)); + assert(std::move(v).transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [](auto) -> int { return 1; }; + const std::expected v(std::unexpected(2)); + assert(std::move(v).transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } +} + +constexpr void test_fail() { + // Test & overload + { + auto l = [](auto) -> int { throw 1; }; + std::expected v; + assert(v.transform_error(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [](auto) -> int { throw 1; }; + const std::expected v; + assert(v.transform_error(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [](auto) -> int { throw 1; }; + std::expected v; + assert(std::move(v).transform_error(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [](auto) -> int { throw 1; }; + const std::expected v; + assert(std::move(v).transform_error(l).has_value()); + static_assert(std::is_same_v>); + } +} + +// check unex member is direct-non-list-initialized with invoke(std::forward(f)) +constexpr void test_direct_non_list_init() { + auto x = [](int i) { return NonCopy(i); }; + std::expected v(std::unexpected(2)); + std::expected nv = v.transform_error(x); + assert(nv.error().value == 2); +} + +constexpr bool test() { + test_fail(); + test_val_types(); + test_direct_non_list_init(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/error_or.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/error_or.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/observers/error_or.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template constexpr E error_or(G&& e) const &; +// template constexpr E error_or(G&& e) &&; + +#include +#include +#include +#include +#include + +#include "test_macros.h" + +constexpr bool test() { + // const &, has_value() + { + const std::expected e; + std::same_as decltype(auto) x = e.error_or(10); + assert(x == 10); + } + + // const &, !has_value() + { + const std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = e.error_or(10); + assert(x == 5); + } + + // &&, has_value() + { + std::expected e; + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x == 10); + } + + // &&, !has_value() + { + std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x == 5); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); +}