diff --git a/.clangd b/.clangd index 403cab3d..57b56447 100644 --- a/.clangd +++ b/.clangd @@ -1,6 +1,6 @@ CompileFlags: Add: [-Wall, -Wextra, -Wpedantic, -Wno-missing-braces, -Wno-c2y-extensions] - Remove: -W* + Remove: [-W*, -funreachable-traps] Compiler: clang++ Diagnostics: ClangTidy: diff --git a/BUILD.bazel b/BUILD.bazel index 2eecec27..f9475f38 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -13,6 +13,5 @@ cc_library( name = "fn", hdrs = glob(["include/fn/**/*.hpp"]), includes = ["include"], - # TODO uncomment once fn is reimplemented in terms of pfn. - # deps = [":pfn"], + deps = [":pfn"], ) diff --git a/CLAUDE.md b/CLAUDE.md index 7f99648c..8375aa61 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ Conventions for AI agents in this repo (you are the primary reader — keep this ## Commits -- Trailer `Assisted-by: Claude:` (Linux-kernel convention), e.g. `claude-opus-4-7`. No `Co-Authored-By:`. +- Trailer `Assisted-by: Claude:` (Linux-kernel convention), e.g. `claude-opus-4-8`. No `Co-Authored-By:`. - Offer commits; never commit without confirmation. Terse messages: imperative topic, body only if needed. - Never `git push` or sign commits — the user signs (GPG) and pushes. diff --git a/examples/polygon/polygon.hpp b/examples/polygon/polygon.hpp index 41483f2d..83c7fd22 100644 --- a/examples/polygon/polygon.hpp +++ b/examples/polygon/polygon.hpp @@ -66,19 +66,19 @@ struct parameters { std::string_view const program_name = (args.size() >= 1 && !args[0].empty()) // ? args[0] : std::string_view{""}; - return std::unexpected(too_few_parameters{program_name}); + return ::pfn::unexpected(too_few_parameters{program_name}); } parameters params; params.characters = args[1]; if (params.characters.size() < 3) { - return std::unexpected(too_few_characters{}); + return ::pfn::unexpected(too_few_characters{}); } params.required = static_cast(params.characters[0]); for (char c : params.characters) { if (static_cast(c) > 0x7F) { - return std::unexpected(non_ascii_characters{}); + return ::pfn::unexpected(non_ascii_characters{}); } } @@ -185,12 +185,12 @@ struct inputs { ec == std::errc::no_such_file_or_directory // || ec == std::errc::not_a_directory // || type == std::filesystem::file_type::not_found) { - return std::unexpected(file_not_found{{.path = std::move(path), .ec = ec}}); + return ::pfn::unexpected(file_not_found{{.path = std::move(path), .ec = ec}}); } if (ec == std::errc::permission_denied) { - return std::unexpected(permission_denied{{.path = std::move(path), .ec = ec}}); + return ::pfn::unexpected(permission_denied{{.path = std::move(path), .ec = ec}}); } - return std::unexpected( + return ::pfn::unexpected( io_error{{.path = std::move(path), .ec = (ec ? ec : std::make_error_code(std::io_errc::stream))}}); }; @@ -254,7 +254,7 @@ constexpr inline struct algorithm_t { if (source.in->eof() && !source.in->bad()) { continue; } - return std::unexpected(read_error{{.path = source.path, .ec = std::make_error_code(std::io_errc::stream)}}); + return ::pfn::unexpected(read_error{{.path = source.path, .ec = std::make_error_code(std::io_errc::stream)}}); } return 0; diff --git a/examples/simple/main.cpp b/examples/simple/main.cpp index 1b3806bc..a3d8ae4c 100644 --- a/examples/simple/main.cpp +++ b/examples/simple/main.cpp @@ -83,7 +83,7 @@ TEST_CASE("Minimal expected", "[expected][and_then]") } { // example-expected-and_then-error - fn::expected ex = std::unexpected{"Not good"}; + fn::expected ex = ::pfn::unexpected{"Not good"}; auto oops = ex | fn::and_then([](auto&& v) -> fn::expected { @@ -139,14 +139,14 @@ TEST_CASE("Demo expected", "[expected][pack][and_then][discard][transform_error] if (std::from_chars(str.begin(), end, tmp).ptr == end) { return {tmp}; } - return std::unexpected{"Failed to parse " + std::string(str)}; + return ::pfn::unexpected{"Failed to parse " + std::string(str)}; }; // Immovable operations must be captured as lvalues, and functor will store // reference to them rather than make a copy constexpr auto fn1 = [j = ImmovableValue{-1}](int i) noexcept -> fn::expected { if (i < j.value) { - return std::unexpected{"Too small"}; + return ::pfn::unexpected{"Too small"}; } return {i + 0.5}; }; @@ -199,12 +199,12 @@ TEST_CASE("Demo expected", "[expected][pack][and_then][discard][transform_error] if (std::from_chars(str.begin(), end, tmp).ptr == end) { return {tmp}; } - return std::unexpected{"Failed to parse " + std::string(str)}; + return ::pfn::unexpected{"Failed to parse " + std::string(str)}; }; constexpr auto parse_twelve = [](std::string str) noexcept -> fn::expected { if (str != "12") - return std::unexpected{"Not 12"}; + return ::pfn::unexpected{"Not 12"}; return {12.}; }; @@ -235,7 +235,7 @@ TEST_CASE("Demo expected", "[expected][pack][and_then][discard][transform_error] | fn::inspect_error([](Error) noexcept { CHECK(false); }) // | fn::discard(); - fn::expected{std::unexpected{"discarded"}} // + fn::expected{::pfn::unexpected{"discarded"}} // | fn::inspect([](int) noexcept { CHECK(false); }) // | fn::inspect_error([](Error e) noexcept { REQUIRE(e.what == "discarded"); }) // | fn::discard(); @@ -506,7 +506,7 @@ TEST_CASE("Demo choice and graded monad", "[choice][and_then][inspect][transform if constexpr (std::is_same_v, T>) { return {FWD(v)}; } else - return std::unexpected{InvalidType}; + return ::pfn::unexpected{InvalidType}; }); }; @@ -523,7 +523,7 @@ TEST_CASE("Demo choice and graded monad", "[choice][and_then][inspect][transform else if (configuration == "test") return type{std::in_place, fn::sum{fn::pack{std::type_identity{}, std::move(test_name)}}}; else - return type{std::unexpect, InvalidConfiguration}; + return type{::pfn::unexpect, InvalidConfiguration}; })(configuration, test_name) // & convert(std::in_place_type, hostname) // & convert(std::in_place_type, port) // @@ -550,24 +550,24 @@ TEST_CASE("Demo choice and graded monad", "[choice][and_then][inspect][transform || config.hostname.find_first_not_of("abcdefghijklmnopqrstuvwxyz0123456789.") != std::string_view::npos || config.hostname.find("..") != std::string_view::npos) - return std::unexpected(InvalidHostname); + return ::pfn::unexpected(InvalidHostname); else if (config.port < 1 || config.port > 0xffff) - return std::unexpected(InvalidPort); + return ::pfn::unexpected(InvalidPort); else if (config.filename.size() < 1 || config.filename.size() > 254) - return std::unexpected(InvalidFilename); + return ::pfn::unexpected(InvalidFilename); else if (config.threshold < 0 || config.threshold > 1) - return std::unexpected(InvalidThreshold); + return ::pfn::unexpected(InvalidThreshold); if constexpr (std::is_same_v, ConfigTest>) { if (config.test_name != "foo") - return std::unexpected(InvalidTest); + return ::pfn::unexpected(InvalidTest); } return FWD(config); }) | fn::and_then([](auto const &config) -> fn::expected { if (config.port < 1024) - return std::unexpected(ConnectError); + return ::pfn::unexpected(ConnectError); if constexpr (std::is_same_v) return {0x50eda7a}; // dummy result else diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index fce6e6dc..481d1355 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -107,8 +107,7 @@ if(NOT DISABLE_CXX23) $ $) set_target_properties(include_fn PROPERTIES EXPORT_NAME fn) - # TODO uncomment once fn is reimplemented in terms of pfn. - # target_link_libraries(include_fn INTERFACE include_pfn) + target_link_libraries(include_fn INTERFACE include_pfn) target_compile_features(include_fn INTERFACE cxx_std_23) install(TARGETS include_fn diff --git a/include/fn/concepts.hpp b/include/fn/concepts.hpp index 6ca38035..8e1febfb 100644 --- a/include/fn/concepts.hpp +++ b/include/fn/concepts.hpp @@ -76,7 +76,7 @@ concept same_monadic_type_as = same_kind && same_value_kind; */ template concept convertible_to_unexpected - = requires { static_cast>>(std::declval()); }; + = requires { static_cast<::pfn::unexpected>>(std::declval()); }; /** * @brief TODO diff --git a/include/fn/expected.hpp b/include/fn/expected.hpp index f14a2ba3..a8decb3c 100644 --- a/include/fn/expected.hpp +++ b/include/fn/expected.hpp @@ -6,11 +6,12 @@ #ifndef INCLUDE_FN_EXPECTED #define INCLUDE_FN_EXPECTED +#include + +#include #include #include -#include -#include #include #include @@ -29,15 +30,530 @@ concept some_expected_void = // some_expected // && std::is_same_v::value_type>; -template struct expected final : std::expected { - using value_type = std::expected::value_type; - using error_type = std::expected::error_type; - using unexpected_type = std::unexpected; - static_assert(not std::is_same_v>); +namespace detail { + +struct expected_policy { + template using type = ::fn::expected; + template static constexpr bool is_specialization = _is_some_expected; +}; + +// Storage layer for ::fn::expected. Inherits the standard-conformant base from +// pfn, then hides the four monadic static helpers with sum-widening variants +// that materialise their result via `expected_policy::template type`. +template struct _storage : ::pfn::detail::_storage { + using _pfn_base = ::pfn::detail::_storage; + using _pfn_base::_pfn_base; + + // and_then, non-void value type + template + static constexpr auto _and_then(Self &&self, Fn &&fn) + requires(not ::std::is_void_v) && ::fn::detail::_is_invocable::value + && ::std::is_constructible_v + { + using type = typename ::fn::detail::_invoke_result::type; + static_assert(_is_some_expected); + static_assert(::std::is_same_v || some_sum); + if constexpr (::std::is_same_v) { + if (self.has_value()) + return ::fn::detail::_invoke(FWD(fn), _pfn_base::_value(FWD(self))); + else + return type(::pfn::unexpect, _pfn_base::_error(FWD(self))); + } else { + using new_error_type = sum_for; + using new_type = ::fn::expected; + if (self.has_value()) { + auto t = ::fn::detail::_invoke(FWD(fn), _pfn_base::_value(FWD(self))); + if (t.has_value()) + if constexpr (not ::std::is_void_v) + return new_type{::std::in_place, ::std::move(t).value()}; + else + return new_type{::std::in_place}; + else + return new_type{::pfn::unexpect, ::std::move(t).error()}; + } else { + if constexpr (not ::std::is_same_v>) + return new_type(::pfn::unexpect, _pfn_base::_error(FWD(self))); + else + ::std::unreachable(); + } + } + } + + // and_then, void value type + template + static constexpr auto _and_then(Self &&self, Fn &&fn) + requires(::std::is_void_v) && ::fn::detail::_is_invocable::value + && ::std::is_constructible_v + { + using type = typename ::fn::detail::_invoke_result::type; + static_assert(_is_some_expected); + static_assert(::std::is_same_v || some_sum); + if constexpr (::std::is_same_v) { + if (self.has_value()) + return ::fn::detail::_invoke(FWD(fn)); + else + return type(::pfn::unexpect, _pfn_base::_error(FWD(self))); + } else { + using new_error_type = sum_for; + using new_type = ::fn::expected; + if (self.has_value()) { + auto t = ::fn::detail::_invoke(FWD(fn)); + if (t.has_value()) + if constexpr (not ::std::is_void_v) + return new_type{::std::in_place, ::std::move(t).value()}; + else + return new_type{::std::in_place}; + else + return new_type{::pfn::unexpect, ::std::move(t).error()}; + } else { + if constexpr (not ::std::is_same_v>) + return new_type(::pfn::unexpect, _pfn_base::_error(FWD(self))); + else + ::std::unreachable(); + } + } + } + + // or_else, covers both void and non-void value type + template + static constexpr auto _or_else(Self &&self, Fn &&fn) + requires ::fn::detail::_is_invocable::value + && (::std::is_void_v || ::std::is_constructible_v) + { + using type = typename ::fn::detail::_invoke_result::type; + static_assert(_is_some_expected); + static_assert(::std::is_same_v || some_sum); + if constexpr (::std::is_same_v) { + if (self.has_value()) + if constexpr (not ::std::is_void_v) + return type(::std::in_place, _pfn_base::_value(FWD(self))); + else { + static_assert(::std::is_void_v); +#if defined(__clang__) && __clang_major__ <= 18 + // clang 15-18 miscompile the prvalue return below for three of the four Self ref-qualifier + // instantiations (&, const &, const &&) at -O1/-O2: the value-state result is observed with + // set_ == false (storage-poison). The workaround dodges the buggy mandatory copy-elision. + return ::std::move(type{::std::in_place}); +#else + return type{::std::in_place}; +#endif + } + else + return ::fn::detail::_invoke(FWD(fn), _pfn_base::_error(FWD(self))); + } else { + static_assert(not ::std::is_void_v); + using new_value_type = sum_for; + using new_type = ::fn::expected; + if (self.has_value()) + return new_type{::std::in_place, _pfn_base::_value(FWD(self))}; + else { + auto t = ::fn::detail::_invoke(FWD(fn), _pfn_base::_error(FWD(self))); + if (t.has_value()) + return new_type{::std::in_place, ::std::move(t).value()}; + else + return new_type{::pfn::unexpect, ::std::move(t).error()}; + } + } + } + + // transform, non-void value type, not a sum + template + static constexpr auto _transform(Self &&self, Fn &&fn) + requires(not ::std::is_void_v) && (not some_sum) + && ::fn::detail::_is_invocable::value + && ::std::is_constructible_v + { + using new_value_type = typename ::fn::detail::_invoke_result::type; + using type = ::fn::expected; + if (self.has_value()) + if constexpr (::std::is_void_v) { + ::fn::detail::_invoke(FWD(fn), _pfn_base::_value(FWD(self))); + return type(); + } else + return type(::std::in_place, ::fn::detail::_invoke(FWD(fn), _pfn_base::_value(FWD(self)))); + else + return type(::pfn::unexpect, _pfn_base::_error(FWD(self))); + } + + // transform, value type is a sum (delegates to sum::transform) + template + static constexpr auto _transform(Self &&self, Fn &&fn) + requires some_sum + { + using new_value_type = decltype(_pfn_base::_value(FWD(self)).transform(FWD(fn))); + using type = ::fn::expected; + if (self.has_value()) + if constexpr (::std::is_void_v) { + _pfn_base::_value(FWD(self)).transform(FWD(fn)); + return type(); + } else + return type(::std::in_place, _pfn_base::_value(FWD(self)).transform(FWD(fn))); + else + return type(::pfn::unexpect, _pfn_base::_error(FWD(self))); + } + + // transform, void value type + template + static constexpr auto _transform(Self &&self, Fn &&fn) + requires(::std::is_void_v) && ::fn::detail::_is_invocable::value + { + using new_value_type = typename ::fn::detail::_invoke_result::type; + using type = ::fn::expected; + if (self.has_value()) + if constexpr (::std::is_void_v) { + ::fn::detail::_invoke(FWD(fn)); + return type(); + } else + return type(::std::in_place, ::fn::detail::_invoke(FWD(fn))); + else + return type(::pfn::unexpect, _pfn_base::_error(FWD(self))); + } - using std::expected::expected; + // transform_error, error type is not a sum + template + static constexpr auto _transform_error(Self &&self, Fn &&fn) + requires(not some_sum) && ::fn::detail::_is_invocable::value + { + using new_error_type = typename ::fn::detail::_invoke_result::type; + using type = ::fn::expected; + if (self.has_value()) + if constexpr (not ::std::is_void_v) + return type(::std::in_place, _pfn_base::_value(FWD(self))); + else + return type(); + else + return type(::pfn::unexpect, ::fn::detail::_invoke(FWD(fn), _pfn_base::_error(FWD(self)))); + } - // convert to graded monad + // transform_error, error type is a sum (delegates to sum::transform) + template + static constexpr auto _transform_error(Self &&self, Fn &&fn) + requires some_sum + { + using new_error_type = decltype(_pfn_base::_error(FWD(self)).transform(FWD(fn))); + using type = ::fn::expected; + if (self.has_value()) + if constexpr (not ::std::is_void_v) + return type(::std::in_place, _pfn_base::_value(FWD(self))); + else + return type(); + else + return type(::pfn::unexpect, _pfn_base::_error(FWD(self)).transform(FWD(fn))); + } +}; + +} // namespace detail + +// Primary template - non-void value type +template struct expected : private detail::_storage { + using _base = detail::_storage; + using value_type = T; + using error_type = Err; + using unexpected_type = ::pfn::unexpected; + static_assert(not ::std::is_same_v>); + + template using rebind = expected; + + // Allow sibling _storage instantiations to downcast into the private base. + template friend struct ::pfn::detail::_storage; + template friend struct ::fn::detail::_storage; + + // Constructors. Explicit forwarders to the base mirror pfn::expected. + constexpr expected() noexcept(::std::is_nothrow_default_constructible_v) + requires ::std::is_default_constructible_v + : _base(::std::in_place) + { + } + + template + constexpr explicit(not ::std::is_convertible_v || not ::std::is_convertible_v) + expected(expected const &s) // + noexcept(::std::is_nothrow_constructible_v && ::std::is_nothrow_constructible_v) + requires(_base::template _can_copy_convert::value) + : _base(s) + { + } + template + constexpr explicit(not ::std::is_convertible_v || not ::std::is_convertible_v) + expected(expected &&s) // + noexcept(::std::is_nothrow_constructible_v && ::std::is_nothrow_constructible_v) + requires(_base::template _can_move_convert::value) + : _base(::std::move(s)) + { + } + template > + constexpr explicit(not ::std::is_convertible_v) expected(U &&v) // + noexcept(::std::is_nothrow_constructible_v) + requires(_base::template _can_convert::value) + : _base(::std::in_place, FWD(v)) + { + } + + template + constexpr explicit(not ::std::is_convertible_v) expected(::pfn::unexpected const &g) // + noexcept(::std::is_nothrow_constructible_v) + requires(::std::is_constructible_v) + : _base(::pfn::unexpect, ::std::forward(g.error())) + { + } + template + constexpr explicit(not ::std::is_convertible_v) expected(::pfn::unexpected &&g) // + noexcept(::std::is_nothrow_constructible_v) + requires(::std::is_constructible_v) + : _base(::pfn::unexpect, ::std::forward(g.error())) + { + } + + template + constexpr explicit expected(::std::in_place_t, Args &&...a) // + noexcept(::std::is_nothrow_constructible_v) + requires ::std::is_constructible_v + : _base(::std::in_place, FWD(a)...) + { + } + template + constexpr explicit expected(::std::in_place_t, ::std::initializer_list il, Args &&...a) // + noexcept(::std::is_nothrow_constructible_v &, Args...>) + requires ::std::is_constructible_v &, Args...> + : _base(::std::in_place, il, FWD(a)...) + { + } + template + constexpr explicit expected(::pfn::unexpect_t, Args &&...a) // + noexcept(::std::is_nothrow_constructible_v) // + requires ::std::is_constructible_v + : _base(::pfn::unexpect, FWD(a)...) + { + } + template + constexpr explicit expected(::pfn::unexpect_t, ::std::initializer_list il, Args &&...a) // + noexcept(::std::is_nothrow_constructible_v &, Args...>) + requires ::std::is_constructible_v &, Args...> + : _base(::pfn::unexpect, il, FWD(a)...) + { + } + + constexpr expected(expected const &) = delete; + constexpr expected(expected const &s) // + noexcept(::std::is_nothrow_copy_constructible_v && ::std::is_nothrow_copy_constructible_v) + requires(::std::is_copy_constructible_v && ::std::is_copy_constructible_v + && ::std::is_trivially_copy_constructible_v && ::std::is_trivially_copy_constructible_v) + = default; + constexpr expected(expected const &s) // + noexcept(::std::is_nothrow_copy_constructible_v && ::std::is_nothrow_copy_constructible_v) + requires(::std::is_copy_constructible_v && ::std::is_copy_constructible_v + && (not ::std::is_trivially_copy_constructible_v || not ::std::is_trivially_copy_constructible_v)) + : _base(s.set_, FWD(s).storage_) + { + } + constexpr expected(expected &&s) + requires(::std::is_move_constructible_v && ::std::is_move_constructible_v + && ::std::is_trivially_move_constructible_v && ::std::is_trivially_move_constructible_v) + = default; + constexpr expected(expected &&s) // + noexcept(::std::is_nothrow_move_constructible_v && ::std::is_nothrow_move_constructible_v) + requires(::std::is_move_constructible_v && ::std::is_move_constructible_v + && (not ::std::is_trivially_move_constructible_v || not ::std::is_trivially_move_constructible_v)) + : _base(s.set_, FWD(s).storage_) + { + } + + constexpr ~expected() = default; + + // Assignment. Explicit forwarders mirror pfn::expected to avoid an MSVC bug. + template + constexpr expected &operator=(U &&s) // + noexcept(::std::is_nothrow_assignable_v && ::std::is_nothrow_constructible_v) + requires(_base::template _can_convert_assign::value) + { + this->_assign_value(FWD(s)); + return *this; + } + template + constexpr expected &operator=(::pfn::unexpected const &s) // + noexcept(::std::is_nothrow_assignable_v && ::std::is_nothrow_constructible_v) + requires(::std::is_constructible_v && ::std::is_assignable_v + && (::std::is_nothrow_constructible_v || ::std::is_nothrow_move_constructible_v + || ::std::is_nothrow_move_constructible_v)) + { + this->_assign_unexpected(s); + return *this; + } + template + constexpr expected &operator=(::pfn::unexpected &&s) // + noexcept(::std::is_nothrow_assignable_v && ::std::is_nothrow_constructible_v) + requires(::std::is_constructible_v && ::std::is_assignable_v + && (::std::is_nothrow_constructible_v || ::std::is_nothrow_move_constructible_v + || ::std::is_nothrow_move_constructible_v)) + { + this->_assign_unexpected(::std::move(s)); + return *this; + } + constexpr expected &operator=(expected const &) = delete; + constexpr expected &operator=(expected const &s) // + noexcept(::std::is_nothrow_copy_assignable_v && ::std::is_nothrow_copy_constructible_v + && ::std::is_nothrow_copy_assignable_v && ::std::is_nothrow_copy_constructible_v) + requires(::std::is_copy_assignable_v && ::std::is_copy_constructible_v && ::std::is_copy_assignable_v + && ::std::is_copy_constructible_v + && (::std::is_nothrow_move_constructible_v || ::std::is_nothrow_move_constructible_v)) + { + this->_assign(static_cast<_base const &>(s)); + return *this; + } + constexpr expected &operator=(expected &&s) // + noexcept(::std::is_nothrow_move_assignable_v && ::std::is_nothrow_move_constructible_v + && ::std::is_nothrow_move_assignable_v && ::std::is_nothrow_move_constructible_v) + requires(::std::is_move_constructible_v && ::std::is_move_assignable_v && ::std::is_move_constructible_v + && ::std::is_move_assignable_v + && (::std::is_nothrow_move_constructible_v || ::std::is_nothrow_move_constructible_v)) + { + this->_assign(static_cast<_base &&>(s)); + return *this; + } + + // Observers inherited from _storage + using _base::operator*; + using _base::operator->; + using _base::operator bool; + using _base::error; + using _base::error_or; + using _base::has_error; + using _base::has_value; + using _base::value; + using _base::value_or; + + // Emplace inherited from _storage + using _base::emplace; + + // Swap; body delegates to _storage helper + constexpr void + swap(expected &rhs) noexcept(::std::is_nothrow_move_constructible_v && ::std::is_nothrow_swappable_v + && ::std::is_nothrow_move_constructible_v && ::std::is_nothrow_swappable_v) + requires(::std::is_swappable_v && ::std::is_swappable_v && ::std::is_move_constructible_v + && ::std::is_move_constructible_v + && (::std::is_nothrow_move_constructible_v || ::std::is_nothrow_move_constructible_v)) + { + this->_swap_with(rhs); + } + + // Monadic operations. Bodies delegate to _storage static helpers, which perform sum-widening. + template + constexpr auto and_then(F &&f) & // + noexcept(noexcept(_base::_and_then(*this, FWD(f)))) // extension + -> decltype(_base::_and_then(*this, FWD(f))) + { + return _base::_and_then(*this, FWD(f)); + } + template + constexpr auto and_then(F &&f) && // + noexcept(noexcept(_base::_and_then(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_and_then(::std::move(*this), FWD(f))) + { + return _base::_and_then(::std::move(*this), FWD(f)); + } + template + constexpr auto and_then(F &&f) const & // + noexcept(noexcept(_base::_and_then(*this, FWD(f)))) // extension + -> decltype(_base::_and_then(*this, FWD(f))) + { + return _base::_and_then(*this, FWD(f)); + } + template + constexpr auto and_then(F &&f) const && // + noexcept(noexcept(_base::_and_then(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_and_then(::std::move(*this), FWD(f))) + { + return _base::_and_then(::std::move(*this), FWD(f)); + } + + template + constexpr auto or_else(F &&f) & // + noexcept(noexcept(_base::_or_else(*this, FWD(f)))) // extension + -> decltype(_base::_or_else(*this, FWD(f))) + { + return _base::_or_else(*this, FWD(f)); + } + template + constexpr auto or_else(F &&f) && // + noexcept(noexcept(_base::_or_else(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_or_else(::std::move(*this), FWD(f))) + { + return _base::_or_else(::std::move(*this), FWD(f)); + } + template + constexpr auto or_else(F &&f) const & // + noexcept(noexcept(_base::_or_else(*this, FWD(f)))) // extension + -> decltype(_base::_or_else(*this, FWD(f))) + { + return _base::_or_else(*this, FWD(f)); + } + template + constexpr auto or_else(F &&f) const && // + noexcept(noexcept(_base::_or_else(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_or_else(::std::move(*this), FWD(f))) + { + return _base::_or_else(::std::move(*this), FWD(f)); + } + + template + constexpr auto transform(F &&f) & // + noexcept(noexcept(_base::_transform(*this, FWD(f)))) // extension + -> decltype(_base::_transform(*this, FWD(f))) + { + return _base::_transform(*this, FWD(f)); + } + template + constexpr auto transform(F &&f) && // + noexcept(noexcept(_base::_transform(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_transform(::std::move(*this), FWD(f))) + { + return _base::_transform(::std::move(*this), FWD(f)); + } + template + constexpr auto transform(F &&f) const & // + noexcept(noexcept(_base::_transform(*this, FWD(f)))) // extension + -> decltype(_base::_transform(*this, FWD(f))) + { + return _base::_transform(*this, FWD(f)); + } + template + constexpr auto transform(F &&f) const && // + noexcept(noexcept(_base::_transform(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_transform(::std::move(*this), FWD(f))) + { + return _base::_transform(::std::move(*this), FWD(f)); + } + + template + constexpr auto transform_error(F &&f) & // + noexcept(noexcept(_base::_transform_error(*this, FWD(f)))) // extension + -> decltype(_base::_transform_error(*this, FWD(f))) + { + return _base::_transform_error(*this, FWD(f)); + } + template + constexpr auto transform_error(F &&f) && // + noexcept(noexcept(_base::_transform_error(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_transform_error(::std::move(*this), FWD(f))) + { + return _base::_transform_error(::std::move(*this), FWD(f)); + } + template + constexpr auto transform_error(F &&f) const & // + noexcept(noexcept(_base::_transform_error(*this, FWD(f)))) // extension + -> decltype(_base::_transform_error(*this, FWD(f))) + { + return _base::_transform_error(*this, FWD(f)); + } + template + constexpr auto transform_error(F &&f) const && // + noexcept(noexcept(_base::_transform_error(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_transform_error(::std::move(*this), FWD(f))) + { + return _base::_transform_error(::std::move(*this), FWD(f)); + } + + // Convert to graded monad auto sum_error() const & -> expected> requires(not some_sum) { @@ -45,9 +561,8 @@ template struct expected final : std::expectedhas_value()) return type{std::in_place, this->value()}; else - return type{std::unexpect, sum(this->error())}; + return type{::pfn::unexpect, sum(this->error())}; } - auto sum_error() && -> expected> requires(not some_sum) { @@ -55,27 +570,23 @@ template struct expected final : std::expectedhas_value()) return type{std::in_place, std::move(*this).value()}; else - return type{std::unexpect, sum(std::move(*this).error())}; + return type{::pfn::unexpect, sum(std::move(*this).error())}; } - auto sum_error() & -> decltype(auto) requires(some_sum) { return *this; } - auto sum_error() const & -> decltype(auto) requires(some_sum) { return *this; } - auto sum_error() && -> decltype(auto) requires(some_sum) { return std::move(*this); } - auto sum_error() const && -> decltype(auto) requires(some_sum) { @@ -83,758 +594,292 @@ template struct expected final : std::expected expected, error_type> - requires(not std::is_same_v) && (not some_sum) + requires(not some_sum) { using type = expected, error_type>; if (this->has_value()) return type{std::in_place, sum(this->value())}; else - return type{std::unexpect, this->error()}; + return type{::pfn::unexpect, this->error()}; } - auto sum_value() && -> expected, error_type> - requires(not std::is_same_v) && (not some_sum) + requires(not some_sum) { using type = expected, error_type>; if (this->has_value()) return type{std::in_place, sum(std::move(*this).value())}; else - return type{std::unexpect, std::move(*this).error()}; + return type{::pfn::unexpect, std::move(*this).error()}; } - auto sum_value() & -> decltype(auto) requires(some_sum) { return *this; } - auto sum_value() const & -> decltype(auto) requires(some_sum) { return *this; } - auto sum_value() && -> decltype(auto) requires(some_sum) { return std::move(*this); } - auto sum_value() const && -> decltype(auto) requires(some_sum) { return std::move(*this); } +}; - // and_then non void - template - constexpr auto and_then(Fn &&fn) & - requires std::is_constructible_v && (not std::is_same_v) - { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - return ::fn::detail::_invoke(FWD(fn), this->value()); - else - return type(std::unexpect, this->error()); - } else { - using new_error_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) { - auto t = ::fn::detail::_invoke(FWD(fn), this->value()); - if (t.has_value()) - if constexpr (not std::is_same_v) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::in_place}; - else - return new_type{std::unexpect, std::move(t).error()}; - } else { - if constexpr (not std::is_same_v>) - return new_type(std::unexpect, this->error()); - else - std::unreachable(); - } - } - } +template struct expected : private detail::_storage { + using _base = detail::_storage; + using value_type = void; + using error_type = Err; + using unexpected_type = ::pfn::unexpected; - template - constexpr auto and_then(Fn &&fn) const & - requires std::is_constructible_v && (not std::is_same_v) - { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - return ::fn::detail::_invoke(FWD(fn), this->value()); - else - return type(std::unexpect, this->error()); - } else { - using new_error_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) { - auto t = ::fn::detail::_invoke(FWD(fn), this->value()); - if (t.has_value()) - if constexpr (not std::is_same_v) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::in_place}; - else - return new_type{std::unexpect, std::move(t).error()}; - } else { - if constexpr (not std::is_same_v>) - return new_type(std::unexpect, this->error()); - else - std::unreachable(); - } - } - } + template using rebind = expected; - template - constexpr auto and_then(Fn &&fn) && - requires std::is_constructible_v && (not std::is_same_v) - { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - return ::fn::detail::_invoke(FWD(fn), std::move(*this).value()); - else - return type(std::unexpect, std::move(*this).error()); - } else { - using new_error_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) { - auto t = ::fn::detail::_invoke(FWD(fn), std::move(*this).value()); - if (t.has_value()) - if constexpr (not std::is_same_v) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::in_place}; - else - return new_type{std::unexpect, std::move(t).error()}; - } else { - if constexpr (not std::is_same_v>) - return new_type(std::unexpect, std::move(*this).error()); - else - std::unreachable(); - } - } - } + template friend struct ::pfn::detail::_storage; + template friend struct ::fn::detail::_storage; - template - constexpr auto and_then(Fn &&fn) const && - requires std::is_constructible_v && (not std::is_same_v) + constexpr expected() noexcept : _base(::std::in_place) {} + + template + constexpr explicit(not ::std::is_convertible_v) expected(expected const &s) // + noexcept(::std::is_nothrow_constructible_v) + requires(_base::template _can_copy_convert::value) + : _base(s) { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - return ::fn::detail::_invoke(FWD(fn), std::move(*this).value()); - else - return type(std::unexpect, std::move(*this).error()); - } else { - using new_error_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) { - auto t = ::fn::detail::_invoke(FWD(fn), std::move(*this).value()); - if (t.has_value()) - if constexpr (not std::is_same_v) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::in_place}; - else - return new_type{std::unexpect, std::move(t).error()}; - } else { - if constexpr (not std::is_same_v>) - return new_type(std::unexpect, std::move(*this).error()); - else - std::unreachable(); - } - } } - - // and_then void - template - constexpr auto and_then(Fn &&fn) & - requires std::is_constructible_v && std::is_same_v + template + constexpr explicit(not ::std::is_convertible_v) expected(expected &&s) // + noexcept(::std::is_nothrow_constructible_v) + requires(_base::template _can_move_convert::value) + : _base(::std::move(s)) { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - return ::fn::detail::_invoke(FWD(fn)); - else - return type(std::unexpect, this->error()); - } else { - using new_error_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) { - auto t = ::fn::detail::_invoke(FWD(fn)); - if (t.has_value()) - if constexpr (not std::is_same_v) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::in_place}; - else - return new_type{std::unexpect, std::move(t).error()}; - } else { - if constexpr (not std::is_same_v>) - return new_type(std::unexpect, this->error()); - else - std::unreachable(); - } - } } - - template - constexpr auto and_then(Fn &&fn) const & - requires std::is_constructible_v && std::is_same_v + template + constexpr explicit(not ::std::is_convertible_v) expected(::pfn::unexpected const &g) // + noexcept(::std::is_nothrow_constructible_v) + requires(::std::is_constructible_v) + : _base(::pfn::unexpect, ::std::forward(g.error())) { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - return ::fn::detail::_invoke(FWD(fn)); - else - return type(std::unexpect, this->error()); - } else { - using new_error_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) { - auto t = ::fn::detail::_invoke(FWD(fn)); - if (t.has_value()) - if constexpr (not std::is_same_v) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::in_place}; - else - return new_type{std::unexpect, std::move(t).error()}; - } else { - if constexpr (not std::is_same_v>) - return new_type(std::unexpect, this->error()); - else - std::unreachable(); - } - } } - - template - constexpr auto and_then(Fn &&fn) && - requires std::is_constructible_v && std::is_same_v + template + constexpr explicit(not ::std::is_convertible_v) expected(::pfn::unexpected &&g) // + noexcept(::std::is_nothrow_constructible_v) + requires(::std::is_constructible_v) + : _base(::pfn::unexpect, ::std::forward(g.error())) { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - return ::fn::detail::_invoke(FWD(fn)); - else - return type(std::unexpect, std::move(*this).error()); - } else { - using new_error_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) { - auto t = ::fn::detail::_invoke(FWD(fn)); - if (t.has_value()) - if constexpr (not std::is_same_v) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::in_place}; - else - return new_type{std::unexpect, std::move(t).error()}; - } else { - if constexpr (not std::is_same_v>) - return new_type(std::unexpect, std::move(*this).error()); - else - std::unreachable(); - } - } } - template - constexpr auto and_then(Fn &&fn) const && - requires std::is_constructible_v && std::is_same_v + constexpr explicit expected(::std::in_place_t) noexcept : _base(::std::in_place) {} + + template + constexpr explicit expected(::pfn::unexpect_t, Args &&...a) // + noexcept(::std::is_nothrow_constructible_v) // + requires ::std::is_constructible_v + : _base(::pfn::unexpect, FWD(a)...) { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - return ::fn::detail::_invoke(FWD(fn)); - else - return type(std::unexpect, std::move(*this).error()); - } else { - using new_error_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) { - auto t = ::fn::detail::_invoke(FWD(fn)); - if (t.has_value()) - if constexpr (not std::is_same_v) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::in_place}; - else - return new_type{std::unexpect, std::move(t).error()}; - } else { - if constexpr (not std::is_same_v>) - return new_type(std::unexpect, std::move(*this).error()); - else - std::unreachable(); - } - } } - - // or_else - template - constexpr auto or_else(Fn &&fn) & - requires(std::is_constructible_v || std::same_as) + template + constexpr explicit expected(::pfn::unexpect_t, ::std::initializer_list il, Args &&...a) // + noexcept(::std::is_nothrow_constructible_v &, Args...>) + requires ::std::is_constructible_v &, Args...> + : _base(::pfn::unexpect, il, FWD(a)...) { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, this->value()); - else - return type(); - else - return ::fn::detail::_invoke(FWD(fn), this->error()); - } else { - static_assert(not std::is_same_v); - using new_value_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) - return new_type{std::in_place, this->value()}; - else { - auto t = ::fn::detail::_invoke(FWD(fn), this->error()); - if (t.has_value()) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::unexpect, std::move(t).error()}; - } - } } - template - constexpr auto or_else(Fn &&fn) const & - requires(std::is_constructible_v || std::same_as) + constexpr expected(expected const &) = delete; + constexpr expected(expected const &) + requires(::std::is_copy_constructible_v && ::std::is_trivially_copy_constructible_v) + = default; + constexpr expected(expected const &s) // + noexcept(::std::is_nothrow_copy_constructible_v) + requires(::std::is_copy_constructible_v && not ::std::is_trivially_copy_constructible_v) + : _base(s.set_, FWD(s).storage_) { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, this->value()); - else - return type(); - else - return ::fn::detail::_invoke(FWD(fn), this->error()); - } else { - static_assert(not std::is_same_v); - using new_value_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) - return new_type{std::in_place, this->value()}; - else { - auto t = ::fn::detail::_invoke(FWD(fn), this->error()); - if (t.has_value()) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::unexpect, std::move(t).error()}; - } - } } - - template - constexpr auto or_else(Fn &&fn) && - requires(std::is_constructible_v || std::same_as) + constexpr expected(expected &&s) + requires(::std::is_move_constructible_v && ::std::is_trivially_move_constructible_v) + = default; + constexpr expected(expected &&s) // + noexcept(::std::is_nothrow_move_constructible_v) + requires(::std::is_move_constructible_v && not ::std::is_trivially_move_constructible_v) + : _base(s.set_, FWD(s).storage_) { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, std::move(*this).value()); - else - return type(); - else - return ::fn::detail::_invoke(FWD(fn), std::move(*this).error()); - } else { - static_assert(not std::is_same_v); - using new_value_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) - return new_type{std::in_place, std::move(*this).value()}; - else { - auto t = ::fn::detail::_invoke(FWD(fn), std::move(*this).error()); - if (t.has_value()) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::unexpect, std::move(t).error()}; - } - } } - template - constexpr auto or_else(Fn &&fn) const && - requires(std::is_constructible_v || std::same_as) + constexpr ~expected() = default; + + template + constexpr expected &operator=(::pfn::unexpected const &s) // + noexcept(::std::is_nothrow_assignable_v && ::std::is_nothrow_constructible_v) + requires(::std::is_constructible_v && ::std::is_assignable_v) { - using type = ::fn::detail::_invoke_result::type; - static_assert(some_expected); - static_assert(std::is_same_v || some_sum); - if constexpr (std::is_same_v) { - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, std::move(*this).value()); - else - return type(); - else - return ::fn::detail::_invoke(FWD(fn), std::move(*this).error()); - } else { - static_assert(not std::is_same_v); - using new_value_type = sum_for; - using new_type = ::fn::expected; - if (this->has_value()) - return new_type{std::in_place, std::move(*this).value()}; - else { - auto t = ::fn::detail::_invoke(FWD(fn), std::move(*this).error()); - if (t.has_value()) - return new_type{std::in_place, std::move(t).value()}; - else - return new_type{std::unexpect, std::move(t).error()}; - } - } + this->_assign_unexpected(s); + return *this; } - - // transform not void, not sum - template - constexpr auto transform(Fn &&fn) & - requires(not std::is_same_v) && (not some_sum) + template + constexpr expected &operator=(::pfn::unexpected &&s) // + noexcept(::std::is_nothrow_assignable_v && ::std::is_nothrow_constructible_v) + requires(::std::is_constructible_v && ::std::is_assignable_v) { - using new_value_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - ::fn::detail::_invoke(FWD(fn), this->value()); - return type(); - } else - return type(std::in_place, ::fn::detail::_invoke(FWD(fn), this->value())); - else - return type(std::unexpect, this->error()); + this->_assign_unexpected(::std::move(s)); + return *this; } - - template - constexpr auto transform(Fn &&fn) const & - requires(not std::is_same_v) && (not some_sum) + constexpr expected &operator=(expected const &) = delete; + constexpr expected &operator=(expected const &s) // + noexcept(::std::is_nothrow_copy_assignable_v && ::std::is_nothrow_copy_constructible_v) + requires(::std::is_copy_assignable_v && ::std::is_copy_constructible_v) { - using new_value_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - ::fn::detail::_invoke(FWD(fn), this->value()); - return type(); - } else - return type(std::in_place, ::fn::detail::_invoke(FWD(fn), this->value())); - else - return type(std::unexpect, this->error()); + this->_assign(static_cast<_base const &>(s)); + return *this; } - - template - constexpr auto transform(Fn &&fn) && - requires(not std::is_same_v) && (not some_sum) + constexpr expected &operator=(expected &&s) // + noexcept(::std::is_nothrow_move_assignable_v && ::std::is_nothrow_move_constructible_v) + requires(::std::is_move_constructible_v && ::std::is_move_assignable_v) { - using new_value_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - ::fn::detail::_invoke(FWD(fn), std::move(*this).value()); - return type(); - } else - return type(std::in_place, ::fn::detail::_invoke(FWD(fn), std::move(*this).value())); - else - return type(std::unexpect, std::move(*this).error()); + this->_assign(static_cast<_base &&>(s)); + return *this; } - template - constexpr auto transform(Fn &&fn) const && - requires(not std::is_same_v) && (not some_sum) + using _base::emplace; + + constexpr void swap(expected &rhs) // + noexcept(::std::is_nothrow_move_constructible_v && ::std::is_nothrow_swappable_v) + requires(::std::is_swappable_v && ::std::is_move_constructible_v) { - using new_value_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - ::fn::detail::_invoke(FWD(fn), std::move(*this).value()); - return type(); - } else - return type(std::in_place, ::fn::detail::_invoke(FWD(fn), std::move(*this).value())); - else - return type(std::unexpect, std::move(*this).error()); + this->_swap_with(rhs); } - // transform sum - template - constexpr auto transform(Fn &&fn) & - requires some_sum + using _base::operator*; + using _base::operator bool; + using _base::error; + using _base::error_or; + using _base::has_error; + using _base::has_value; + using _base::value; + + // Monadic operations. Bodies delegate to _storage static helpers, which perform sum-widening. + template + constexpr auto and_then(F &&f) & // + noexcept(noexcept(_base::_and_then(*this, FWD(f)))) // extension + -> decltype(_base::_and_then(*this, FWD(f))) { - using new_value_type = decltype(this->value().transform(FWD(fn))); - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - this->value().transform(FWD(fn)); - return type(); - } else - return type(std::in_place, this->value().transform(FWD(fn))); - else - return type(std::unexpect, this->error()); + return _base::_and_then(*this, FWD(f)); } - - template - constexpr auto transform(Fn &&fn) const & - requires some_sum + template + constexpr auto and_then(F &&f) && // + noexcept(noexcept(_base::_and_then(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_and_then(::std::move(*this), FWD(f))) { - using new_value_type = decltype(this->value().transform(FWD(fn))); - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - this->value().transform(FWD(fn)); - return type(); - } else - return type(std::in_place, this->value().transform(FWD(fn))); - else - return type(std::unexpect, this->error()); + return _base::_and_then(::std::move(*this), FWD(f)); } - - template - constexpr auto transform(Fn &&fn) && - requires some_sum + template + constexpr auto and_then(F &&f) const & // + noexcept(noexcept(_base::_and_then(*this, FWD(f)))) // extension + -> decltype(_base::_and_then(*this, FWD(f))) { - using new_value_type = decltype(std::move(*this).value().transform(FWD(fn))); - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - std::move(*this).value().transform(FWD(fn)); - return type(); - } else - return type(std::in_place, std::move(*this).value().transform(FWD(fn))); - else - return type(std::unexpect, std::move(*this).error()); + return _base::_and_then(*this, FWD(f)); } - - template - constexpr auto transform(Fn &&fn) const && - requires some_sum + template + constexpr auto and_then(F &&f) const && // + noexcept(noexcept(_base::_and_then(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_and_then(::std::move(*this), FWD(f))) { - using new_value_type = decltype(std::move(*this).value().transform(FWD(fn))); - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - std::move(*this).value().transform(FWD(fn)); - return type(); - } else - return type(std::in_place, std::move(*this).value().transform(FWD(fn))); - else - return type(std::unexpect, std::move(*this).error()); + return _base::_and_then(::std::move(*this), FWD(f)); } - // transform void - template - constexpr auto transform(Fn &&fn) & - requires std::is_same_v + template + constexpr auto or_else(F &&f) & // + noexcept(noexcept(_base::_or_else(*this, FWD(f)))) // extension + -> decltype(_base::_or_else(*this, FWD(f))) { - using new_value_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - ::fn::detail::_invoke(FWD(fn)); - return type(); - } else - return type(std::in_place, ::fn::detail::_invoke(FWD(fn))); - else - return type(std::unexpect, this->error()); + return _base::_or_else(*this, FWD(f)); } - - template - constexpr auto transform(Fn &&fn) const & - requires std::is_same_v + template + constexpr auto or_else(F &&f) && // + noexcept(noexcept(_base::_or_else(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_or_else(::std::move(*this), FWD(f))) { - using new_value_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - ::fn::detail::_invoke(FWD(fn)); - return type(); - } else - return type(std::in_place, ::fn::detail::_invoke(FWD(fn))); - else - return type(std::unexpect, this->error()); + return _base::_or_else(::std::move(*this), FWD(f)); } - - template - constexpr auto transform(Fn &&fn) && - requires std::is_same_v + template + constexpr auto or_else(F &&f) const & // + noexcept(noexcept(_base::_or_else(*this, FWD(f)))) // extension + -> decltype(_base::_or_else(*this, FWD(f))) { - using new_value_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - ::fn::detail::_invoke(FWD(fn)); - return type(); - } else - return type(std::in_place, ::fn::detail::_invoke(FWD(fn))); - else - return type(std::unexpect, std::move(*this).error()); + return _base::_or_else(*this, FWD(f)); } - - template - constexpr auto transform(Fn &&fn) const && - requires std::is_same_v + template + constexpr auto or_else(F &&f) const && // + noexcept(noexcept(_base::_or_else(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_or_else(::std::move(*this), FWD(f))) { - using new_value_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (std::is_same_v) { - ::fn::detail::_invoke(FWD(fn)); - return type(); - } else - return type(std::in_place, ::fn::detail::_invoke(FWD(fn))); - else - return type(std::unexpect, std::move(*this).error()); + return _base::_or_else(::std::move(*this), FWD(f)); } - // transform_error not sum - template - constexpr auto transform_error(Fn &&fn) & - requires(not some_sum) + template + constexpr auto transform(F &&f) & // + noexcept(noexcept(_base::_transform(*this, FWD(f)))) // extension + -> decltype(_base::_transform(*this, FWD(f))) { - using new_error_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, this->value()); - else - return type(); - else - return type(std::unexpect, ::fn::detail::_invoke(FWD(fn), this->error())); + return _base::_transform(*this, FWD(f)); } - - template - constexpr auto transform_error(Fn &&fn) const & - requires(not some_sum) + template + constexpr auto transform(F &&f) && // + noexcept(noexcept(_base::_transform(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_transform(::std::move(*this), FWD(f))) { - using new_error_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, this->value()); - else - return type(); - else - return type(std::unexpect, ::fn::detail::_invoke(FWD(fn), this->error())); + return _base::_transform(::std::move(*this), FWD(f)); } - - template - constexpr auto transform_error(Fn &&fn) && - requires(not some_sum) + template + constexpr auto transform(F &&f) const & // + noexcept(noexcept(_base::_transform(*this, FWD(f)))) // extension + -> decltype(_base::_transform(*this, FWD(f))) { - using new_error_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, std::move(*this).value()); - else - return type(); - else - return type(std::unexpect, ::fn::detail::_invoke(FWD(fn), std::move(*this).error())); + return _base::_transform(*this, FWD(f)); } - - template - constexpr auto transform_error(Fn &&fn) const && - requires(not some_sum) + template + constexpr auto transform(F &&f) const && // + noexcept(noexcept(_base::_transform(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_transform(::std::move(*this), FWD(f))) { - using new_error_type = detail::_invoke_result::type; - using type = expected; - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, std::move(*this).value()); - else - return type(); - else - return type(std::unexpect, ::fn::detail::_invoke(FWD(fn), std::move(*this).error())); + return _base::_transform(::std::move(*this), FWD(f)); } - // transform_error sum - template - constexpr auto transform_error(Fn &&fn) & - requires some_sum + template + constexpr auto transform_error(F &&f) & // + noexcept(noexcept(_base::_transform_error(*this, FWD(f)))) // extension + -> decltype(_base::_transform_error(*this, FWD(f))) { - using new_error_type = decltype(this->error().transform(FWD(fn))); - using type = expected; - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, this->value()); - else - return type(); - else - return type(std::unexpect, this->error().transform(FWD(fn))); + return _base::_transform_error(*this, FWD(f)); } - - template - constexpr auto transform_error(Fn &&fn) const & - requires some_sum + template + constexpr auto transform_error(F &&f) && // + noexcept(noexcept(_base::_transform_error(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_transform_error(::std::move(*this), FWD(f))) { - using new_error_type = decltype(this->error().transform(FWD(fn))); - using type = expected; - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, this->value()); - else - return type(); - else - return type(std::unexpect, this->error().transform(FWD(fn))); + return _base::_transform_error(::std::move(*this), FWD(f)); } - - template - constexpr auto transform_error(Fn &&fn) && - requires some_sum + template + constexpr auto transform_error(F &&f) const & // + noexcept(noexcept(_base::_transform_error(*this, FWD(f)))) // extension + -> decltype(_base::_transform_error(*this, FWD(f))) { - using new_error_type = decltype(std::move(*this).error().transform(FWD(fn))); - using type = expected; - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, std::move(*this).value()); - else - return type(); - else - return type(std::unexpect, std::move(*this).error().transform(FWD(fn))); + return _base::_transform_error(*this, FWD(f)); } - - template - constexpr auto transform_error(Fn &&fn) const && - requires some_sum + template + constexpr auto transform_error(F &&f) const && // + noexcept(noexcept(_base::_transform_error(::std::move(*this), FWD(f)))) // extension + -> decltype(_base::_transform_error(::std::move(*this), FWD(f))) { - using new_error_type = decltype(std::move(*this).error().transform(FWD(fn))); - using type = expected; - if (this->has_value()) - if constexpr (not std::is_same_v) - return type(std::in_place, std::move(*this).value()); - else - return type(); - else - return type(std::unexpect, std::move(*this).error().transform(FWD(fn))); + return _base::_transform_error(::std::move(*this), FWD(f)); } }; - // Lifts for sum transformation functions [[nodiscard]] constexpr auto sum_value(some_expected auto &&src) -> decltype(auto) { return FWD(src).sum_value(); } [[nodiscard]] constexpr auto sum_error(some_expected auto &&src) -> decltype(auto) { return FWD(src).sum_error(); } @@ -852,9 +897,9 @@ template if (lh.has_value() && rh.has_value()) return type{std::in_place, FWD(rh).value()}; else if (not lh.has_value()) - return type{std::unexpect, FWD(lh).error()}; + return type{::pfn::unexpect, FWD(lh).error()}; else - return type{std::unexpect, FWD(rh).error()}; + return type{::pfn::unexpect, FWD(rh).error()}; } template @@ -873,12 +918,12 @@ template return type{std::in_place, FWD(rh).value()}; else if (not lh.has_value()) { if constexpr (not std::is_same_v::error_type, sum<>>) - return type{std::unexpect, new_error_type{FWD(lh).error()}}; + return type{::pfn::unexpect, new_error_type{FWD(lh).error()}}; else std::unreachable(); } else { if constexpr (not std::is_same_v::error_type, sum<>>) - return type{std::unexpect, new_error_type{FWD(rh).error()}}; + return type{::pfn::unexpect, new_error_type{FWD(rh).error()}}; else std::unreachable(); } @@ -895,9 +940,9 @@ template if (lh.has_value() && rh.has_value()) return type{std::in_place, FWD(lh).value()}; else if (not lh.has_value()) - return type{std::unexpect, FWD(lh).error()}; + return type{::pfn::unexpect, FWD(lh).error()}; else - return type{std::unexpect, FWD(rh).error()}; + return type{::pfn::unexpect, FWD(rh).error()}; } template @@ -916,12 +961,12 @@ template return type{std::in_place, FWD(lh).value()}; else if (not lh.has_value()) { if constexpr (not std::is_same_v::error_type, sum<>>) - return type{std::unexpect, new_error_type{FWD(lh).error()}}; + return type{::pfn::unexpect, new_error_type{FWD(lh).error()}}; else std::unreachable(); } else { if constexpr (not std::is_same_v::error_type, sum<>>) - return type{std::unexpect, new_error_type{FWD(rh).error()}}; + return type{::pfn::unexpect, new_error_type{FWD(rh).error()}}; else std::unreachable(); } @@ -937,9 +982,9 @@ template if (lh.has_value() && rh.has_value()) return type{std::in_place}; else if (not lh.has_value()) - return type{std::unexpect, FWD(lh).error()}; + return type{::pfn::unexpect, FWD(lh).error()}; else - return type{std::unexpect, FWD(rh).error()}; + return type{::pfn::unexpect, FWD(rh).error()}; } template @@ -957,12 +1002,12 @@ template return type{std::in_place}; else if (not lh.has_value()) { if constexpr (not std::is_same_v::error_type, sum<>>) - return type{std::unexpect, new_error_type{FWD(lh).error()}}; + return type{::pfn::unexpect, new_error_type{FWD(lh).error()}}; else std::unreachable(); } else { if constexpr (not std::is_same_v::error_type, sum<>>) - return type{std::unexpect, new_error_type{FWD(rh).error()}}; + return type{::pfn::unexpect, new_error_type{FWD(rh).error()}}; else std::unreachable(); } @@ -982,7 +1027,7 @@ template [[nodiscard]] constexpr auto operator&(Lh &&lh, Rh &&rh) noexcept { using error_type = std::remove_cvref_t::error_type; - static constexpr auto efn = [](auto &&v) { return std::unexpected(FWD(v).error()); }; + static constexpr auto efn = [](auto &&v) { return ::pfn::unexpected(FWD(v).error()); }; return ::fn::detail::_join::template type>(FWD(lh), FWD(rh), efn); } @@ -998,7 +1043,7 @@ template = sum_for::error_type, typename std::remove_cvref_t::error_type>; static constexpr auto efn = [](auto &&v) { if constexpr (not std::is_same_v::error_type, sum<>>) { - return std::unexpected(FWD(v).error()); + return ::pfn::unexpected(FWD(v).error()); } else { std::unreachable(); } diff --git a/include/fn/fail.hpp b/include/fn/fail.hpp index 60bed02f..8d60c228 100644 --- a/include/fn/fail.hpp +++ b/include/fn/fail.hpp @@ -60,9 +60,9 @@ struct fail_t::apply final { { using type = std::remove_cvref_t; if (v.has_value()) { - return type{std::unexpect, ::fn::invoke(FWD(fn), FWD(v).value())}; + return type{::pfn::unexpect, ::fn::invoke(FWD(fn), FWD(v).value())}; } - return type{std::unexpect, FWD(v).error()}; + return type{::pfn::unexpect, FWD(v).error()}; } /** @@ -78,9 +78,9 @@ struct fail_t::apply final { { using type = std::remove_cvref_t; if (v.has_value()) { - return type{std::unexpect, ::fn::invoke(FWD(fn))}; + return type{::pfn::unexpect, ::fn::invoke(FWD(fn))}; } - return type{std::unexpect, FWD(v).error()}; + return type{::pfn::unexpect, FWD(v).error()}; } /** diff --git a/include/fn/filter.hpp b/include/fn/filter.hpp index c26b4cf0..7720e1fa 100644 --- a/include/fn/filter.hpp +++ b/include/fn/filter.hpp @@ -89,7 +89,7 @@ struct filter_t::apply final { if (std::as_const(v).has_value()) { bool const keep = ::fn::invoke(FWD(pred), std::as_const(v).value()); return (keep ? type{std::in_place, FWD(v).value()} - : type{std::unexpect, ::fn::invoke(FWD(on_err), FWD(v).value())}); + : type{::pfn::unexpect, ::fn::invoke(FWD(on_err), FWD(v).value())}); } return FWD(v); } @@ -110,7 +110,7 @@ struct filter_t::apply final { if (std::as_const(v).has_value()) { bool const keep = ::fn::invoke(FWD(pred)); return (keep ? type{std::in_place} // - : type{std::unexpect, ::fn::invoke(FWD(on_err))}); + : type{::pfn::unexpect, ::fn::invoke(FWD(on_err))}); } return FWD(v); } diff --git a/include/pfn/expected.hpp b/include/pfn/expected.hpp index f9cf4c19..79cf7181 100644 --- a/include/pfn/expected.hpp +++ b/include/pfn/expected.hpp @@ -1118,7 +1118,7 @@ template class expected : private detail::_storage> - constexpr explicit(not ::std::is_convertible_v) expected(U &&v) // + constexpr explicit(not ::std::is_convertible_v) expected(U &&v) // NOSONAR cpp:S6458 _can_convert excludes self noexcept(::std::is_nothrow_constructible_v) // extension requires(_base::template _can_convert::value) : _base(::std::in_place, FWD(v)) @@ -1128,7 +1128,7 @@ template class expected : private detail::_storage) expected(unexpected const &g) // noexcept(::std::is_nothrow_constructible_v) // extension requires(::std::is_constructible_v) - : _base(unexpect, ::std::forward(g.error())) + : _base(unexpect, ::std::forward(g.error())) // NOSONAR cpp:S6031 forward per the standard { } template @@ -1181,7 +1181,7 @@ template class expected : private detail::_storage && ::std::is_move_constructible_v && ::std::is_trivially_move_constructible_v && ::std::is_trivially_move_constructible_v) = default; @@ -1239,7 +1239,7 @@ template class expected : private detail::_storage && ::std::is_nothrow_move_constructible_v && ::std::is_nothrow_move_assignable_v && ::std::is_nothrow_move_constructible_v) // required requires(::std::is_move_constructible_v && ::std::is_move_assignable_v && ::std::is_move_constructible_v @@ -1254,9 +1254,9 @@ template class expected : private detail::_storage && ::std::is_nothrow_swappable_v - && ::std::is_nothrow_move_constructible_v && ::std::is_nothrow_swappable_v) + constexpr void swap(expected &rhs) // NOSONAR cpp:S5018 standard mandated `noexcept` spec. + noexcept(::std::is_nothrow_move_constructible_v && ::std::is_nothrow_swappable_v + && ::std::is_nothrow_move_constructible_v && ::std::is_nothrow_swappable_v) requires(::std::is_swappable_v && ::std::is_swappable_v && ::std::is_move_constructible_v && ::std::is_move_constructible_v && (::std::is_nothrow_move_constructible_v || ::std::is_nothrow_move_constructible_v)) @@ -1432,7 +1432,7 @@ template class expected : private detail::_storage) expected(unexpected const &g) // noexcept(::std::is_nothrow_constructible_v) // extension requires(::std::is_constructible_v) - : _base(unexpect, ::std::forward(g.error())) + : _base(unexpect, ::std::forward(g.error())) // NOSONAR cpp:S6031 forward per the standard { } template @@ -1470,7 +1470,7 @@ template class expected : private detail::_storage && ::std::is_trivially_move_constructible_v) // = default; constexpr expected(expected &&s) // @@ -1511,7 +1511,7 @@ template class expected : private detail::_storage && ::std::is_nothrow_move_constructible_v) // required requires(::std::is_move_constructible_v && ::std::is_move_assignable_v) { @@ -1523,7 +1523,7 @@ template class expected : private detail::_storage && ::std::is_nothrow_swappable_v) requires(::std::is_swappable_v && ::std::is_move_constructible_v) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ca091137..7f221667 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -122,6 +122,7 @@ set(TESTS_FN_SOURCES fn/concepts.cpp fn/discard.cpp fn/expected.cpp + fn/expected_polyfill.cpp fn/fail.cpp fn/filter.cpp fn/functional.cpp diff --git a/tests/fn/and_then.cpp b/tests/fn/and_then.cpp index 2f6d1a97..d20fecae 100644 --- a/tests/fn/and_then.cpp +++ b/tests/fn/and_then.cpp @@ -339,7 +339,7 @@ TEST_CASE("and_then", "[and_then][expected][expected_value][pack]") constexpr auto fnValue = [](int i) -> operand_t { return {i + 1}; }; constexpr auto wrong = [](int) -> operand_t { throw 0; }; - constexpr auto fnFail = [](int i) -> operand_t { return std::unexpected("Got " + std::to_string(i)); }; + constexpr auto fnFail = [](int i) -> operand_t { return ::pfn::unexpected("Got " + std::to_string(i)); }; constexpr auto fnXabs = [](int i) -> fn::expected { return {{std::abs(8 - i)}}; }; static_assert(is::invocable_with_any(fnValue)); @@ -387,7 +387,7 @@ TEST_CASE("and_then", "[and_then][expected][expected_value][pack]") WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | and_then(wrong)); static_assert(std::is_same_v); REQUIRE((a // @@ -411,7 +411,7 @@ TEST_CASE("and_then", "[and_then][expected][expected_value][pack]") WHEN("fail") { constexpr auto fnFail = [](int i, double d) constexpr -> fn::expected { - return std::unexpected("Got " + std::to_string(i) + " and " + std::to_string(d)); + return ::pfn::unexpected("Got " + std::to_string(i) + " and " + std::to_string(d)); }; using T = decltype(a | and_then(fnFail)); static_assert(std::is_same_v>); @@ -422,7 +422,7 @@ TEST_CASE("and_then", "[and_then][expected][expected_value][pack]") WHEN("operand is error") { constexpr auto wrong = [](auto...) -> operand_t { throw 0; }; - REQUIRE((operand_t{std::unexpect, Error{"Not good"}} | and_then(wrong)).error().what == "Not good"); + REQUIRE((operand_t{::pfn::unexpect, Error{"Not good"}} | and_then(wrong)).error().what == "Not good"); } } } @@ -451,9 +451,9 @@ TEST_CASE("and_then", "[and_then][expected][expected_value][pack]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | and_then(wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | and_then(wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | and_then(wrong)) .error() .what @@ -478,7 +478,7 @@ TEST_CASE("and_then", "[and_then][expected][expected_void]") }; constexpr auto wrong = []() -> operand_t { throw 0; }; - auto fnFail = [&count]() -> operand_t { return std::unexpected("Got " + std::to_string(++count)); }; + auto fnFail = [&count]() -> operand_t { return ::pfn::unexpected("Got " + std::to_string(++count)); }; auto fnXabs = [&count]() -> fn::expected { return {{++count}}; }; static_assert(is::invocable_with_any(fnValue)); @@ -514,7 +514,7 @@ TEST_CASE("and_then", "[and_then][expected][expected_void]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | and_then(wrong)); static_assert(std::is_same_v); REQUIRE((a // @@ -550,9 +550,9 @@ TEST_CASE("and_then", "[and_then][expected][expected_void]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | and_then(wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | and_then(wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | and_then(wrong)) .error() .what @@ -765,7 +765,7 @@ TEST_CASE("constexpr and_then expected", "[and_then][constexpr][expected]") constexpr auto fn = [](int i) constexpr noexcept -> T { if (i < 3) return {i + 1}; - return std::unexpected{Error::ThresholdExceeded}; + return ::pfn::unexpected{Error::ThresholdExceeded}; }; constexpr auto r1 = T{0} | fn::and_then(fn); static_assert(r1.value() == 1); @@ -781,7 +781,7 @@ TEST_CASE("constexpr and_then expected", "[and_then][constexpr][expected]") return {true}; if (i == 0) return {false}; - return std::unexpected{Error::SomethingElse}; + return ::pfn::unexpected{Error::SomethingElse}; }; constexpr auto r1 = T{1} | fn::and_then(fn); static_assert(std::is_same_v const>); @@ -805,7 +805,7 @@ TEST_CASE("constexpr and_then expected with sum", "[and_then][constexpr][expecte constexpr auto fn = fn::overload{[](int i) constexpr noexcept -> T { if (i < 3) return {i + 1}; - return std::unexpected{Error::ThresholdExceeded}; + return ::pfn::unexpected{Error::ThresholdExceeded}; }, [](Xint v) constexpr noexcept -> T { return v; }}; constexpr auto r1 = T{0} | fn::and_then(fn); @@ -823,9 +823,9 @@ TEST_CASE("constexpr and_then expected with sum", "[and_then][constexpr][expecte return {true}; if (i == 0) return {false}; - return std::unexpected{Error::SomethingElse}; + return ::pfn::unexpected{Error::SomethingElse}; }, - [](Xint) constexpr noexcept -> T1 { return std::unexpected{Error::UnexpectedType}; }}; + [](Xint) constexpr noexcept -> T1 { return ::pfn::unexpected{Error::UnexpectedType}; }}; constexpr auto r1 = T{1} | fn::and_then(fn); static_assert(std::is_same_v const>); static_assert(r1.value() == true); @@ -848,7 +848,7 @@ TEST_CASE("constexpr and_then graded monad", "[and_then][constexpr][expected][gr constexpr auto fn1 = [](int i) -> fn::expected { if (i < 2) return {i + 1}; - return std::unexpected{i}; + return ::pfn::unexpected{i}; }; constexpr auto r1 = T{0} | fn::and_then(fn1); @@ -866,7 +866,7 @@ TEST_CASE("constexpr and_then graded monad", "[and_then][constexpr][expected][gr { constexpr auto fn2 = [](int i) -> fn::expected { if (i < 0 || i > 1) - return std::unexpected{Error::InvalidValue}; + return ::pfn::unexpected{Error::InvalidValue}; return {i == 1}; }; diff --git a/tests/fn/discard.cpp b/tests/fn/discard.cpp index a11b3e8a..89dbc5e7 100644 --- a/tests/fn/discard.cpp +++ b/tests/fn/discard.cpp @@ -50,7 +50,7 @@ TEST_CASE("discard", "[discard][expected][expected_value]") WHEN("operand is error") { - operand_t a{std::unexpect, Error{"Not good"}}; + operand_t a{::pfn::unexpect, Error{"Not good"}}; a | discard(); REQUIRE(a.error().what == "Not good"); @@ -67,7 +67,7 @@ TEST_CASE("discard", "[discard][expected][expected_value]") WHEN("operand is error") { - operand_t{std::unexpect, Error{"Not good"}} | discard(); + operand_t{::pfn::unexpect, Error{"Not good"}} | discard(); SUCCEED(); } } @@ -91,7 +91,7 @@ TEST_CASE("discard with pack", "[discard][expected][expected_value][pack]") WHEN("operand is error") { - operand_t b{std::unexpect, Error{"Pack error"}}; + operand_t b{::pfn::unexpect, Error{"Pack error"}}; b | discard(); REQUIRE(b.error().what == "Pack error"); @@ -121,7 +121,7 @@ TEST_CASE("discard", "[discard][expected][expected_void]") WHEN("operand is error") { - operand_t a{std::unexpect, Error{"Not good"}}; + operand_t a{::pfn::unexpect, Error{"Not good"}}; a | discard(); REQUIRE(a.error().what == "Not good"); @@ -138,7 +138,7 @@ TEST_CASE("discard", "[discard][expected][expected_void]") WHEN("operand is error") { - operand_t{std::unexpect, Error{"Not good"}} | discard(); + operand_t{::pfn::unexpect, Error{"Not good"}} | discard(); SUCCEED(); } } @@ -198,7 +198,7 @@ TEST_CASE("constexpr discard expected", "[discard][constexpr][expected]") using T = fn::expected; constexpr auto a = T{42}; - constexpr auto b = T{std::unexpect, Error::ThresholdExceeded}; + constexpr auto b = T{::pfn::unexpect, Error::ThresholdExceeded}; constexpr auto test = [](T v) { v | discard(); diff --git a/tests/fn/expected.cpp b/tests/fn/expected.cpp index 59622f0f..b0d6c65f 100644 --- a/tests/fn/expected.cpp +++ b/tests/fn/expected.cpp @@ -46,7 +46,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("and_then to error") { - constexpr auto fn = []() -> fn::expected { return std::unexpected(FileNotFound); }; + constexpr auto fn = []() -> fn::expected { return ::pfn::unexpected(FileNotFound); }; constexpr auto a = unit.and_then(fn); static_assert(std::is_same_v> const>); static_assert(a.error() == fn::sum{FileNotFound}); @@ -81,7 +81,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("and_then to error") { - constexpr auto fn = []() -> fn::expected { return std::unexpected(FileNotFound); }; + constexpr auto fn = []() -> fn::expected { return ::pfn::unexpected(FileNotFound); }; auto a = unit.and_then(fn); static_assert(std::is_same_v>>); CHECK(a.error() == fn::sum{FileNotFound}); @@ -114,7 +114,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] } WHEN("error") { - T s{std::unexpect, Unknown}; + T s{::pfn::unexpect, Unknown}; CHECK(s.sum_error().error() == fn::sum{Unknown}); CHECK(std::as_const(s).sum_error().error() == fn::sum{Unknown}); CHECK(std::move(std::as_const(s)).sum_error().error() == fn::sum{Unknown}); @@ -141,7 +141,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] } WHEN("error") { - T s{std::unexpect, Unknown}; + T s{::pfn::unexpect, Unknown}; CHECK(s.sum_error().error() == fn::sum{Unknown}); CHECK(std::as_const(s).sum_error().error() == fn::sum{Unknown}); CHECK(std::move(std::as_const(s)).sum_error().error() == fn::sum{Unknown}); @@ -168,7 +168,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] } WHEN("error") { - T s{std::unexpect, Unknown}; + T s{::pfn::unexpect, Unknown}; CHECK(s.sum_value().error() == Unknown); CHECK(std::as_const(s).sum_value().error() == Unknown); CHECK(std::move(std::as_const(s)).sum_value().error() == Unknown); @@ -195,7 +195,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] } WHEN("error") { - T s{std::unexpect, Unknown}; + T s{::pfn::unexpect, Unknown}; CHECK(s.sum_value().error() == Unknown); CHECK(std::as_const(s).sum_value().error() == Unknown); CHECK(std::move(std::as_const(s)).sum_value().error() == Unknown); @@ -240,7 +240,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("value to error") { - constexpr auto fn = [](int i) -> fn::expected { return std::unexpected(i >= 1); }; + constexpr auto fn = [](int i) -> fn::expected { return ::pfn::unexpected(i >= 1); }; static_assert(std::is_same_v>>); CHECK(s.and_then(fn).error() == fn::sum{true}); CHECK(std::as_const(s).and_then(fn).error() == fn::sum{true}); @@ -250,7 +250,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("error") { - fn::expected> s{std::unexpect, fn::sum{FileNotFound}}; + fn::expected> s{::pfn::unexpect, fn::sum{FileNotFound}}; constexpr auto fn = [](int) -> fn::expected { throw 0; }; static_assert(std::is_same_v>>); CHECK(s.and_then(fn).error() == fn::sum{FileNotFound}); @@ -293,7 +293,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("value to error") { - constexpr auto fn = []() -> fn::expected { return std::unexpected(true); }; + constexpr auto fn = []() -> fn::expected { return ::pfn::unexpected(true); }; static_assert(std::is_same_v>>); CHECK(s.and_then(fn).error() == fn::sum{true}); CHECK(std::as_const(s).and_then(fn).error() == fn::sum{true}); @@ -303,7 +303,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("error") { - fn::expected> s{std::unexpect, fn::sum{FileNotFound}}; + fn::expected> s{::pfn::unexpect, fn::sum{FileNotFound}}; constexpr auto fn = []() -> fn::expected { throw 0; }; static_assert(std::is_same_v>>); CHECK(s.and_then(fn).error() == fn::sum{FileNotFound}); @@ -346,7 +346,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("value to error") { - constexpr auto fn = [](int i) -> fn::expected { return std::unexpected(i >= 1); }; + constexpr auto fn = [](int i) -> fn::expected { return ::pfn::unexpected(i >= 1); }; static_assert(std::is_same_v>>); CHECK(s.and_then(fn).error() == fn::sum{true}); CHECK(std::as_const(s).and_then(fn).error() == fn::sum{true}); @@ -356,7 +356,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("error") { - fn::expected> s{std::unexpect, fn::sum{FileNotFound}}; + fn::expected> s{::pfn::unexpect, fn::sum{FileNotFound}}; constexpr auto fn = [](int) -> fn::expected { throw 0; }; static_assert(std::is_same_v>>); CHECK(s.and_then(fn).error() == fn::sum{FileNotFound}); @@ -399,7 +399,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("value to error") { - constexpr auto fn = []() -> fn::expected { return std::unexpected(true); }; + constexpr auto fn = []() -> fn::expected { return ::pfn::unexpected(true); }; static_assert(std::is_same_v>>); CHECK(s.and_then(fn).error() == fn::sum{true}); CHECK(std::as_const(s).and_then(fn).error() == fn::sum{true}); @@ -409,7 +409,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("error") { - fn::expected> s{std::unexpect, fn::sum{FileNotFound}}; + fn::expected> s{::pfn::unexpect, fn::sum{FileNotFound}}; constexpr auto fn = []() -> fn::expected { throw 0; }; static_assert(std::is_same_v>>); CHECK(s.and_then(fn).error() == fn::sum{FileNotFound}); @@ -424,7 +424,7 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("or_else") { - fn::expected, Error> s{std::unexpect, FileNotFound}; + fn::expected, Error> s{::pfn::unexpect, FileNotFound}; constexpr auto fn1 = [](int) -> fn::expected { throw 0; }; static_assert(std::is_same_v, Error>>); @@ -455,7 +455,8 @@ TEST_CASE("graded monad", "[expected][sum][graded][and_then][or_else][sum_value] WHEN("error to error") { - constexpr auto fn = [](Error) -> fn::expected { return std::unexpected("Boo"); }; + constexpr auto fn + = [](Error) -> fn::expected { return ::pfn::unexpected("Boo"); }; static_assert(std::is_same_v, std::string>>); CHECK(s.or_else(fn).error() == "Boo"); CHECK(std::as_const(s).or_else(fn).error() == "Boo"); @@ -488,7 +489,7 @@ TEST_CASE("graded monad constexpr and runtime", "[constexpr][and_then][or_else][ constexpr auto fn1 = [](int i) -> fn::expected { if (i < 2) return {i + 1}; - return std::unexpected{i}; + return ::pfn::unexpected{i}; }; constexpr auto r1 = T{0}.and_then(fn1); @@ -508,7 +509,7 @@ TEST_CASE("graded monad constexpr and runtime", "[constexpr][and_then][or_else][ { constexpr auto fn2 = [](int i) -> fn::expected { if (i < 0 || i > 1) - return std::unexpected{Error::InvalidValue}; + return ::pfn::unexpected{Error::InvalidValue}; return {i == 1}; }; @@ -540,7 +541,7 @@ TEST_CASE("graded monad constexpr and runtime", "[constexpr][and_then][or_else][ constexpr auto fn1 = [](int i) -> fn::expected { if (i < 2) return {i + 1}; - return std::unexpected{i}; + return ::pfn::unexpected{i}; }; auto const r1 = T{0}.and_then(fn1); @@ -558,7 +559,7 @@ TEST_CASE("graded monad constexpr and runtime", "[constexpr][and_then][or_else][ { constexpr auto fn2 = [](int i) -> fn::expected { if (i < 0 || i > 1) - return std::unexpected{Error::InvalidValue}; + return ::pfn::unexpected{Error::InvalidValue}; return {i == 1}; }; @@ -584,15 +585,15 @@ TEST_CASE("graded monad constexpr and runtime", "[constexpr][and_then][or_else][ constexpr auto fn1 = [](Error i) -> fn::expected { if (i == Error::Unknown) return {0}; - return std::unexpected{(int)i}; + return ::pfn::unexpected{(int)i}; }; constexpr auto r1 = T{14}.or_else(fn1); static_assert(std::is_same_v, int> const>); static_assert(r1.value() == fn::sum{14}); - constexpr auto r2 = T{std::unexpect, Error::InvalidValue}.or_else(fn1); + constexpr auto r2 = T{::pfn::unexpect, Error::InvalidValue}.or_else(fn1); static_assert(r2.error() == 1); - constexpr auto r3 = T{std::unexpect, Error::Unknown}.or_else(fn1); + constexpr auto r3 = T{::pfn::unexpect, Error::Unknown}.or_else(fn1); static_assert(r3.value() == fn::sum{0}); SUCCEED(); @@ -605,15 +606,15 @@ TEST_CASE("graded monad constexpr and runtime", "[constexpr][and_then][or_else][ constexpr auto fn1 = [](Error i) -> fn::expected { if (i == Error::Unknown) return {0}; - return std::unexpected{(int)i}; + return ::pfn::unexpected{(int)i}; }; auto const r1 = T{14}.or_else(fn1); static_assert(std::is_same_v, int> const>); CHECK(r1.value() == fn::sum{14}); - auto const r2 = T{std::unexpect, Error::InvalidValue}.or_else(fn1); + auto const r2 = T{::pfn::unexpect, Error::InvalidValue}.or_else(fn1); CHECK(r2.error() == 1); - auto const r3 = T{std::unexpect, Error::Unknown}.or_else(fn1); + auto const r3 = T{::pfn::unexpect, Error::Unknown}.or_else(fn1); CHECK(r3.value() == fn::sum{0}); } } @@ -658,7 +659,7 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat WHEN("error") { - fn::expected, Error> s{std::unexpect, FileNotFound}; + fn::expected, Error> s{::pfn::unexpect, FileNotFound}; CHECK(s.and_then( // [](auto...) -> fn::expected { throw 0; }) .error() @@ -749,10 +750,10 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat WHEN("error") { - fn::expected, Error> s{std::unexpect, FileNotFound}; + fn::expected, Error> s{::pfn::unexpect, FileNotFound}; CHECK(s.transform([](auto...) -> bool { throw 0; }).error() == FileNotFound); CHECK(std::as_const(s).transform([](auto...) -> bool { throw 0; }).error() == FileNotFound); - CHECK(fn::expected, Error>{std::unexpect, FileNotFound} + CHECK(fn::expected, Error>{::pfn::unexpect, FileNotFound} .transform([](auto...) -> bool { throw 0; }) .error() == FileNotFound); @@ -774,16 +775,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{}) .value() == 42); - CHECK((fn::expected{std::unexpect, FileNotFound} // + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // & fn::expected{}) .error() == FileNotFound); CHECK((fn::expected{42} // - & fn::expected{std::unexpect, Unknown}) + & fn::expected{::pfn::unexpect, Unknown}) .error() == Unknown); - CHECK((fn::expected{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, Unknown}) + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, Unknown}) .error() == FileNotFound); } @@ -798,16 +799,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{12}) .value() == 12); - CHECK((fn::expected{std::unexpect, FileNotFound} // + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // & fn::expected{12}) .error() == FileNotFound); CHECK((fn::expected{} // - & fn::expected{std::unexpect, Unknown}) + & fn::expected{::pfn::unexpect, Unknown}) .error() == Unknown); - CHECK((fn::expected{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, Unknown}) + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, Unknown}) .error() == FileNotFound); } @@ -821,16 +822,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat CHECK((fn::expected{} // & fn::expected{}) .has_value()); - CHECK((fn::expected{std::unexpect, FileNotFound} // + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // & fn::expected{}) .error() == FileNotFound); CHECK((fn::expected{} // - & fn::expected{std::unexpect, Unknown}) + & fn::expected{::pfn::unexpect, Unknown}) .error() == Unknown); - CHECK((fn::expected{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, Unknown}) + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, Unknown}) .error() == FileNotFound); } @@ -845,16 +846,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{12}) .transform([](double d, int i) constexpr -> bool { return d == 0.5 && i == 12; }) .value()); - CHECK((fn::expected{std::unexpect, FileNotFound} // + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // & fn::expected{12}) .error() == FileNotFound); CHECK((fn::expected{} // - & fn::expected{std::unexpect, Unknown}) + & fn::expected{::pfn::unexpect, Unknown}) .error() == Unknown); - CHECK((fn::expected{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, Unknown}) + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, Unknown}) .error() == FileNotFound); } @@ -869,16 +870,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected, Error>{std::in_place, fn::pack{true, 12}}) .transform([](double d, bool b, int i) constexpr -> bool { return d == 0.5 && b && i == 12; }) .value()); - CHECK((fn::expected{std::unexpect, FileNotFound} // + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // & fn::expected, Error>{std::in_place, fn::pack{true, 12}}) .error() == FileNotFound); CHECK((fn::expected{} // - & fn::expected, Error>{std::unexpect, Unknown}) + & fn::expected, Error>{::pfn::unexpect, Unknown}) .error() == Unknown); - CHECK((fn::expected{std::unexpect, FileNotFound} // - & fn::expected, Error>{std::unexpect, Unknown}) + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // + & fn::expected, Error>{::pfn::unexpect, Unknown}) .error() == FileNotFound); } @@ -893,16 +894,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{12}) .transform([](double d, bool b, int i) constexpr -> bool { return d == 0.5 && b && i == 12; }) .value()); - CHECK((fn::expected, Error>{std::unexpect, FileNotFound} // + CHECK((fn::expected, Error>{::pfn::unexpect, FileNotFound} // & fn::expected{12}) .error() == FileNotFound); CHECK((fn::expected, Error>{std::in_place, fn::pack{0.5, true}} // - & fn::expected{std::unexpect, Unknown}) + & fn::expected{::pfn::unexpect, Unknown}) .error() == Unknown); - CHECK((fn::expected, Error>{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, Unknown}) + CHECK((fn::expected, Error>{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, Unknown}) .error() == FileNotFound); } @@ -919,16 +920,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat return d == 0.5 && b1 && b2 && i == 12; }) .value()); - CHECK((fn::expected, Error>{std::unexpect, FileNotFound} // + CHECK((fn::expected, Error>{::pfn::unexpect, FileNotFound} // & fn::expected, Error>{std::in_place, fn::pack{true, 12}}) .error() == FileNotFound); CHECK((fn::expected, Error>{std::in_place, fn::pack{0.5, true}} // - & fn::expected, Error>{std::unexpect, Unknown}) + & fn::expected, Error>{::pfn::unexpect, Unknown}) .error() == Unknown); - CHECK((fn::expected, Error>{std::unexpect, FileNotFound} // - & fn::expected, Error>{std::unexpect, Unknown}) + CHECK((fn::expected, Error>{::pfn::unexpect, FileNotFound} // + & fn::expected, Error>{::pfn::unexpect, Unknown}) .error() == FileNotFound); } @@ -943,16 +944,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{}) .transform([](double d, bool b) constexpr -> bool { return d == 0.5 && b; }) .value()); - CHECK((fn::expected, Error>{std::unexpect, FileNotFound} // + CHECK((fn::expected, Error>{::pfn::unexpect, FileNotFound} // & fn::expected{}) .error() == FileNotFound); CHECK((fn::expected, Error>{std::in_place, fn::pack{0.5, true}} // - & fn::expected{std::unexpect, Unknown}) + & fn::expected{::pfn::unexpect, Unknown}) .error() == Unknown); - CHECK((fn::expected, Error>{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, Unknown}) + CHECK((fn::expected, Error>{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, Unknown}) .error() == FileNotFound); } @@ -967,16 +968,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected, Error>{std::in_place, fn::pack{0.5, true}}) .transform([](double d, bool b) constexpr -> bool { return d == 0.5 && b; }) .value()); - CHECK((fn::expected{std::unexpect, FileNotFound} // + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // & fn::expected, Error>{std::in_place, fn::pack{0.5, true}}) .error() == FileNotFound); CHECK((fn::expected{} // - & fn::expected, Error>{std::unexpect, Unknown}) + & fn::expected, Error>{::pfn::unexpect, Unknown}) .error() == Unknown); - CHECK((fn::expected{std::unexpect, FileNotFound} // - & fn::expected, Error>{std::unexpect, Unknown}) + CHECK((fn::expected{::pfn::unexpect, FileNotFound} // + & fn::expected, Error>{::pfn::unexpect, Unknown}) .error() == FileNotFound); } @@ -997,9 +998,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == FileNotFound); - CHECK((Lh{fn::sum{0.5}} & Rh{std::unexpect, Unknown}).error() == Unknown); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, Unknown}).error() == FileNotFound); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == FileNotFound); + CHECK((Lh{fn::sum{0.5}} & Rh{::pfn::unexpect, Unknown}).error() == Unknown); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, Unknown}).error() == FileNotFound); WHEN("sum of packs on left") { @@ -1016,9 +1017,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == FileNotFound); - CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{std::unexpect, Unknown}).error() == Unknown); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, Unknown}).error() == FileNotFound); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == FileNotFound); + CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{::pfn::unexpect, Unknown}).error() == Unknown); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, Unknown}).error() == FileNotFound); } WHEN("sum of packs on right") @@ -1036,9 +1037,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{fn::pack{0.5, 3}}}).error() == FileNotFound); - CHECK((Lh{fn::sum{12}} & Rh{std::unexpect, Unknown}).error() == Unknown); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, Unknown}).error() == FileNotFound); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{fn::pack{0.5, 3}}}).error() == FileNotFound); + CHECK((Lh{fn::sum{12}} & Rh{::pfn::unexpect, Unknown}).error() == Unknown); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, Unknown}).error() == FileNotFound); } } @@ -1057,9 +1058,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{12}).error() == FileNotFound); - CHECK((Lh{fn::sum{0.5}} & Rh{std::unexpect, Unknown}).error() == Unknown); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, Unknown}).error() == FileNotFound); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{12}).error() == FileNotFound); + CHECK((Lh{fn::sum{0.5}} & Rh{::pfn::unexpect, Unknown}).error() == Unknown); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, Unknown}).error() == FileNotFound); WHEN("sum of packs on left") { @@ -1075,9 +1076,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{12}).error() == FileNotFound); - CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{std::unexpect, Unknown}).error() == Unknown); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, Unknown}).error() == FileNotFound); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{12}).error() == FileNotFound); + CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{::pfn::unexpect, Unknown}).error() == Unknown); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, Unknown}).error() == FileNotFound); } WHEN("pack on right") @@ -1094,9 +1095,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::in_place, fn::pack{0.5, true}}).error() == FileNotFound); - CHECK((Lh{fn::sum{1.5}} & Rh{std::unexpect, Unknown}).error() == Unknown); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, Unknown}).error() == FileNotFound); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{std::in_place, fn::pack{0.5, true}}).error() == FileNotFound); + CHECK((Lh{fn::sum{1.5}} & Rh{::pfn::unexpect, Unknown}).error() == Unknown); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, Unknown}).error() == FileNotFound); } } @@ -1115,9 +1116,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == FileNotFound); - CHECK((Lh{0.5} & Rh{std::unexpect, Unknown}).error() == Unknown); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, Unknown}).error() == FileNotFound); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == FileNotFound); + CHECK((Lh{0.5} & Rh{::pfn::unexpect, Unknown}).error() == Unknown); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, Unknown}).error() == FileNotFound); WHEN("pack on left") { @@ -1133,9 +1134,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == FileNotFound); - CHECK((Lh{fn::pack{0.5, 3}} & Rh{std::unexpect, Unknown}).error() == Unknown); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, Unknown}).error() == FileNotFound); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == FileNotFound); + CHECK((Lh{fn::pack{0.5, 3}} & Rh{::pfn::unexpect, Unknown}).error() == Unknown); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, Unknown}).error() == FileNotFound); } } } @@ -1172,16 +1173,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{}) .value() == 42); - CHECK((fn::expected>{std::unexpect, fn::sum{FileNotFound}} // + CHECK((fn::expected>{::pfn::unexpect, fn::sum{FileNotFound}} // & fn::expected{}) .error() == fn::sum{FileNotFound}); CHECK((fn::expected>{42} // - & fn::expected{std::unexpect, 13}) + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{13}); - CHECK((fn::expected>{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, 13}) + CHECK((fn::expected>{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{FileNotFound}); } @@ -1196,16 +1197,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{12}) .value() == 12); - CHECK((fn::expected>{std::unexpect, FileNotFound} // + CHECK((fn::expected>{::pfn::unexpect, FileNotFound} // & fn::expected{12}) .error() == fn::sum{FileNotFound}); CHECK((fn::expected>{} // - & fn::expected{std::unexpect, 13}) + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{13}); - CHECK((fn::expected>{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, 13}) + CHECK((fn::expected>{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{FileNotFound}); } @@ -1219,16 +1220,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat CHECK((fn::expected>{} // & fn::expected{}) .has_value()); - CHECK((fn::expected>{std::unexpect, FileNotFound} // + CHECK((fn::expected>{::pfn::unexpect, FileNotFound} // & fn::expected{}) .error() == fn::sum{FileNotFound}); CHECK((fn::expected>{} // - & fn::expected{std::unexpect, 13}) + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{13}); - CHECK((fn::expected>{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, 13}) + CHECK((fn::expected>{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{FileNotFound}); } @@ -1243,16 +1244,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{12}) .transform([](double d, int i) constexpr -> bool { return d == 0.5 && i == 12; }) .value()); - CHECK((fn::expected>{std::unexpect, FileNotFound} // + CHECK((fn::expected>{::pfn::unexpect, FileNotFound} // & fn::expected{12}) .error() == fn::sum{FileNotFound}); CHECK((fn::expected>{} // - & fn::expected{std::unexpect, 13}) + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{13}); - CHECK((fn::expected>{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, 13}) + CHECK((fn::expected>{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{FileNotFound}); } @@ -1267,16 +1268,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{12}) .transform([](double d, bool b, int i) constexpr -> bool { return d == 0.5 && b && i == 12; }) .value()); - CHECK((fn::expected, fn::sum>{std::unexpect, FileNotFound} // + CHECK((fn::expected, fn::sum>{::pfn::unexpect, FileNotFound} // & fn::expected{12}) .error() == fn::sum{FileNotFound}); CHECK((fn::expected, fn::sum>{std::in_place, fn::pack{0.5, true}} // - & fn::expected{std::unexpect, 13}) + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{13}); - CHECK((fn::expected, fn::sum>{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, 13}) + CHECK((fn::expected, fn::sum>{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{FileNotFound}); } @@ -1291,16 +1292,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected{}) .transform([](double d, bool b) constexpr -> bool { return d == 0.5 && b; }) .value()); - CHECK((fn::expected, fn::sum>{std::unexpect, FileNotFound} // + CHECK((fn::expected, fn::sum>{::pfn::unexpect, FileNotFound} // & fn::expected{}) .error() == fn::sum{FileNotFound}); CHECK((fn::expected, fn::sum>{std::in_place, fn::pack{0.5, true}} // - & fn::expected{std::unexpect, 13}) + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{13}); - CHECK((fn::expected, fn::sum>{std::unexpect, FileNotFound} // - & fn::expected{std::unexpect, 13}) + CHECK((fn::expected, fn::sum>{::pfn::unexpect, FileNotFound} // + & fn::expected{::pfn::unexpect, 13}) .error() == fn::sum{FileNotFound}); } @@ -1315,16 +1316,16 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected, int>{std::in_place, fn::pack{0.5, true}}) .transform([](double d, bool b) constexpr -> bool { return d == 0.5 && b; }) .value()); - CHECK((fn::expected>{std::unexpect, FileNotFound} // + CHECK((fn::expected>{::pfn::unexpect, FileNotFound} // & fn::expected, int>{std::in_place, fn::pack{0.5, true}}) .error() == fn::sum{FileNotFound}); CHECK((fn::expected>{} // - & fn::expected, int>{std::unexpect, 13}) + & fn::expected, int>{::pfn::unexpect, 13}) .error() == fn::sum{13}); - CHECK((fn::expected>{std::unexpect, FileNotFound} // - & fn::expected, int>{std::unexpect, 13}) + CHECK((fn::expected>{::pfn::unexpect, FileNotFound} // + & fn::expected, int>{::pfn::unexpect, 13}) .error() == fn::sum{FileNotFound}); } @@ -1345,9 +1346,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{0.5}} & Rh{std::unexpect, 13}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, 13}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{0.5}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{FileNotFound}); WHEN("sum of packs on left") { @@ -1364,9 +1365,10 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{std::unexpect, 13}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, 13}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, 13}).error() + == fn::sum{FileNotFound}); } } @@ -1385,9 +1387,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{12}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{0.5}} & Rh{std::unexpect, 13}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, 13}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{12}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{0.5}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{FileNotFound}); WHEN("sum of packs on left") { @@ -1403,9 +1405,10 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{12}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{std::unexpect, 13}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, 13}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{12}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, 13}).error() + == fn::sum{FileNotFound}); } } @@ -1424,9 +1427,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{0.5} & Rh{std::unexpect, 13}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, 13}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{0.5} & Rh{::pfn::unexpect, 13}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{FileNotFound}); WHEN("pack on left") { @@ -1442,9 +1445,10 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::pack{0.5, 3}} & Rh{std::unexpect, 13}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, 13}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::pack{0.5, 3}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, 13}).error() + == fn::sum{FileNotFound}); } } } @@ -1482,15 +1486,15 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat .value() == 12); CHECK((fn::expected{12} // - & fn::expected>{std::unexpect, FileNotFound}) + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{FileNotFound}); - CHECK((fn::expected{std::unexpect, 13} // + CHECK((fn::expected{::pfn::unexpect, 13} // & fn::expected>{}) .error() == fn::sum{13}); - CHECK((fn::expected{std::unexpect, 13} // - & fn::expected>{std::unexpect, FileNotFound}) + CHECK((fn::expected{::pfn::unexpect, 13} // + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{13}); } @@ -1506,15 +1510,15 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat .value() == 42); CHECK((fn::expected{} // - & fn::expected>{std::unexpect, fn::sum{FileNotFound}}) + & fn::expected>{::pfn::unexpect, fn::sum{FileNotFound}}) .error() == fn::sum{FileNotFound}); - CHECK((fn::expected{std::unexpect, 13} // + CHECK((fn::expected{::pfn::unexpect, 13} // & fn::expected>{42}) .error() == fn::sum{13}); - CHECK((fn::expected{std::unexpect, 13} // - & fn::expected>{std::unexpect, FileNotFound}) + CHECK((fn::expected{::pfn::unexpect, 13} // + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{13}); } @@ -1529,15 +1533,15 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat & fn::expected>{}) .has_value()); CHECK((fn::expected{} // - & fn::expected>{std::unexpect, FileNotFound}) + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{FileNotFound}); - CHECK((fn::expected{std::unexpect, 13} // + CHECK((fn::expected{::pfn::unexpect, 13} // & fn::expected>{}) .error() == fn::sum{13}); - CHECK((fn::expected{std::unexpect, 13} // - & fn::expected>{std::unexpect, FileNotFound}) + CHECK((fn::expected{::pfn::unexpect, 13} // + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{13}); } @@ -1553,15 +1557,15 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat .transform([](double d, int i) constexpr -> bool { return d == 0.5 && i == 12; }) .value()); CHECK((fn::expected{0.5} // - & fn::expected>{std::unexpect, FileNotFound}) + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{FileNotFound}); - CHECK((fn::expected{std::unexpect, 13} // + CHECK((fn::expected{::pfn::unexpect, 13} // & fn::expected>{12}) .error() == fn::sum{13}); - CHECK((fn::expected{std::unexpect, 13} // - & fn::expected>{std::unexpect, FileNotFound}) + CHECK((fn::expected{::pfn::unexpect, 13} // + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{13}); } @@ -1577,15 +1581,15 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat .transform([](double d, bool b, int i) constexpr -> bool { return d == 0.5 && b && i == 12; }) .value()); CHECK((fn::expected, int>{std::in_place, fn::pack{0.5, true}} // - & fn::expected>{std::unexpect, FileNotFound}) + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{FileNotFound}); - CHECK((fn::expected, int>{std::unexpect, 13} // + CHECK((fn::expected, int>{::pfn::unexpect, 13} // & fn::expected>{12}) .error() == fn::sum{13}); - CHECK((fn::expected, int>{std::unexpect, 13} // - & fn::expected>{std::unexpect, FileNotFound}) + CHECK((fn::expected, int>{::pfn::unexpect, 13} // + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{13}); } @@ -1601,15 +1605,15 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat .transform([](double d, bool b) constexpr -> bool { return d == 0.5 && b; }) .value()); CHECK((fn::expected, int>{std::in_place, fn::pack{0.5, true}} // - & fn::expected>{std::unexpect, FileNotFound}) + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{FileNotFound}); - CHECK((fn::expected, int>{std::unexpect, 13} // + CHECK((fn::expected, int>{::pfn::unexpect, 13} // & fn::expected>{}) .error() == fn::sum{13}); - CHECK((fn::expected, int>{std::unexpect, 13} // - & fn::expected>{std::unexpect, FileNotFound}) + CHECK((fn::expected, int>{::pfn::unexpect, 13} // + & fn::expected>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{13}); } @@ -1625,15 +1629,15 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat .transform([](double d, bool b) constexpr -> bool { return d == 0.5 && b; }) .value()); CHECK((fn::expected{} // - & fn::expected, fn::sum>{std::unexpect, FileNotFound}) + & fn::expected, fn::sum>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{FileNotFound}); - CHECK((fn::expected{std::unexpect, 13} // + CHECK((fn::expected{::pfn::unexpect, 13} // & fn::expected, fn::sum>{std::in_place, fn::pack{0.5, true}}) .error() == fn::sum{13}); - CHECK((fn::expected{std::unexpect, 13} // - & fn::expected, fn::sum>{std::unexpect, FileNotFound}) + CHECK((fn::expected{::pfn::unexpect, 13} // + & fn::expected, fn::sum>{::pfn::unexpect, FileNotFound}) .error() == fn::sum{13}); } @@ -1654,9 +1658,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{0.5}} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{0.5}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); WHEN("sum of packs on left") { @@ -1673,9 +1677,10 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, fn::sum{13}}).error() + == fn::sum{FileNotFound}); } } @@ -1694,9 +1699,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{12}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{0.5}} & Rh{std::unexpect, 13}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, 13}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{12}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{0.5}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, 13}).error() == fn::sum{FileNotFound}); WHEN("sum of packs on left") { @@ -1712,9 +1717,10 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{12}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{12}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, fn::sum{13}}).error() + == fn::sum{FileNotFound}); } } @@ -1733,9 +1739,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{0.5} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{0.5} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); WHEN("pack on left") { @@ -1751,9 +1757,10 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::pack{0.5, 3}} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::pack{0.5, 3}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, fn::sum{13}}).error() + == fn::sum{FileNotFound}); } } } @@ -1772,9 +1779,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat fn::expected>>); CHECK((Lh{12} & Rh{}).value() == 12); - CHECK((Lh{12} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); + CHECK((Lh{12} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); } WHEN("void & value yield value") @@ -1785,9 +1792,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat fn::expected>>); CHECK((Lh{} & Rh{42}).value() == 42); - CHECK((Lh{} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{42}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); + CHECK((Lh{} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{42}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); } WHEN("void & void yield void") @@ -1798,9 +1805,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat fn::expected>>); CHECK((Lh{} & Rh{}).has_value()); - CHECK((Lh{} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); + CHECK((Lh{} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); } WHEN("value & value yield pack") @@ -1813,9 +1820,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat CHECK((Lh{0.5} & Rh{12}) .transform([](double d, int i) constexpr -> bool { return d == 0.5 && i == 12; }) .value()); - CHECK((Lh{0.5} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{12}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); + CHECK((Lh{0.5} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{12}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); } WHEN("pack & value yield pack") @@ -1830,15 +1837,15 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat .transform([](double d, bool b, int i) constexpr -> bool { return d == 0.5 && b && i == 12; }) .value()); CHECK((Lh{std::in_place, fn::pack{0.5, true}} // - & Rh{std::unexpect, fn::sum{FileNotFound}}) + & Rh{::pfn::unexpect, fn::sum{FileNotFound}}) .error() == fn::sum{FileNotFound}); - CHECK((Lh{std::unexpect, fn::sum{13}} // + CHECK((Lh{::pfn::unexpect, fn::sum{13}} // & Rh{12}) .error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{13}} // - & Rh{std::unexpect, fn::sum{FileNotFound}}) + CHECK((Lh{::pfn::unexpect, fn::sum{13}} // + & Rh{::pfn::unexpect, fn::sum{FileNotFound}}) .error() == fn::sum{13}); } @@ -1853,10 +1860,11 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat CHECK((Lh{std::in_place, fn::pack{0.5, true}} & Rh{}) .transform([](double d, bool b) constexpr -> bool { return d == 0.5 && b; }) .value()); - CHECK((Lh{std::in_place, fn::pack{0.5, true}} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() - == fn::sum{FileNotFound}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); + CHECK( + (Lh{std::in_place, fn::pack{0.5, true}} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() + == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); } WHEN("void & pack yield pack") @@ -1869,10 +1877,10 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat CHECK((Lh{} & Rh{std::in_place, fn::pack{0.5, true}}) .transform([](double d, bool b) constexpr -> bool { return d == 0.5 && b; }) .value()); - CHECK((Lh{} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{std::in_place, fn::pack{0.5, true}}).error() + CHECK((Lh{} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{std::in_place, fn::pack{0.5, true}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{13}} & Rh{std::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{13}} & Rh{::pfn::unexpect, fn::sum{FileNotFound}}).error() == fn::sum{13}); } WHEN("sum on both sides") @@ -1891,9 +1899,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{0.5}} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, fn::sum{13}}).error() + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{0.5}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); WHEN("sum of packs on left") @@ -1917,9 +1925,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, fn::sum{13}}).error() + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); } } @@ -1939,9 +1947,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{12}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{0.5}} & Rh{std::unexpect, 13}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, 13}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{12}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{0.5}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, 13}).error() == fn::sum{FileNotFound}); WHEN("sum of packs on left") { @@ -1963,9 +1971,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{12}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, fn::sum{13}}).error() + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{12}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::sum{fn::pack{0.5, 3}}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); } } @@ -1985,9 +1993,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{0.5} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, FileNotFound} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{0.5} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, FileNotFound} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); WHEN("pack on left") { @@ -2009,9 +2017,9 @@ TEST_CASE("expected pack support", "[expected][pack][and_then][transform][operat }) .value() == fn::sum{true}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); - CHECK((Lh{fn::pack{0.5, 3}} & Rh{std::unexpect, fn::sum{13}}).error() == fn::sum{13}); - CHECK((Lh{std::unexpect, fn::sum{FileNotFound}} & Rh{std::unexpect, fn::sum{13}}).error() + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{fn::sum{12}}).error() == fn::sum{FileNotFound}); + CHECK((Lh{fn::pack{0.5, 3}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{13}); + CHECK((Lh{::pfn::unexpect, fn::sum{FileNotFound}} & Rh{::pfn::unexpect, fn::sum{13}}).error() == fn::sum{FileNotFound}); } } @@ -2075,7 +2083,7 @@ TEST_CASE("expected sum support and_then", "[expected][sum][and_then]") WHEN("error") { - fn::expected, Error> s{std::unexpect, FileNotFound}; + fn::expected, Error> s{::pfn::unexpect, FileNotFound}; CHECK(s.and_then( // [](auto...) -> fn::expected { return {true}; }) .error() @@ -2085,7 +2093,7 @@ TEST_CASE("expected sum support and_then", "[expected][sum][and_then]") [](auto...) -> fn::expected { return {true}; }) .error() == FileNotFound); - CHECK(fn::expected, Error>{std::unexpect, FileNotFound} + CHECK(fn::expected, Error>{::pfn::unexpect, FileNotFound} .and_then( // [](auto...) -> fn::expected { return {true}; }) .error() @@ -2117,7 +2125,7 @@ TEST_CASE("expected sum support or_else", "[expected][sum][or_else]") { WHEN("value") { - fn::expected> s{std::unexpect, fn::sum{12}}; + fn::expected> s{::pfn::unexpect, fn::sum{12}}; CHECK(s.or_else( // fn::overload([](int &i) -> fn::expected { return {i}; }, @@ -2204,7 +2212,7 @@ TEST_CASE("expected sum support or_else", "[expected][sum][or_else]") [](std::string_view const &) -> fn::expected { throw 0; }, [](std::string_view &&) -> fn::expected { throw 0; }, [](std::string_view const &&) -> fn::expected { throw 0; }); - constexpr fn::expected> a{std::unexpect, fn::sum{42}}; + constexpr fn::expected> a{::pfn::unexpect, fn::sum{42}}; static_assert(std::is_same_v>); static_assert(a.or_else(fn).value() == 42); } @@ -2212,10 +2220,10 @@ TEST_CASE("expected sum support or_else", "[expected][sum][or_else]") WHEN("void") { - fn::expected> s{std::unexpect, fn::sum{12}}; + fn::expected> s{::pfn::unexpect, fn::sum{12}}; CHECK(s.or_else( // - fn::overload([](int &) -> fn::expected { return std::unexpected{FileNotFound}; }, + fn::overload([](int &) -> fn::expected { return ::pfn::unexpected{FileNotFound}; }, [](int const &) -> fn::expected { throw 0; }, [](int &&) -> fn::expected { throw 0; }, [](int const &&) -> fn::expected { throw 0; }, @@ -2230,7 +2238,7 @@ TEST_CASE("expected sum support or_else", "[expected][sum][or_else]") .or_else( // fn::overload( [](int &) -> fn::expected { throw 0; }, - [](int const &) -> fn::expected { return std::unexpected{FileNotFound}; }, + [](int const &) -> fn::expected { return ::pfn::unexpected{FileNotFound}; }, [](int &&) -> fn::expected { throw 0; }, [](int const &&) -> fn::expected { throw 0; }, [](std::string_view &) -> fn::expected { throw 0; }, @@ -2246,7 +2254,7 @@ TEST_CASE("expected sum support or_else", "[expected][sum][or_else]") [](int &) -> fn::expected { throw 0; }, [](int const &) -> fn::expected { throw 0; }, [](int &&) -> fn::expected { throw 0; }, - [](int const &&) -> fn::expected { return std::unexpected{FileNotFound}; }, + [](int const &&) -> fn::expected { return ::pfn::unexpected{FileNotFound}; }, [](std::string_view &) -> fn::expected { throw 0; }, [](std::string_view const &) -> fn::expected { throw 0; }, [](std::string_view &&) -> fn::expected { throw 0; }, @@ -2254,18 +2262,19 @@ TEST_CASE("expected sum support or_else", "[expected][sum][or_else]") .error() == FileNotFound); - CHECK(std::move(s) - .or_else( // - fn::overload([](int &) -> fn::expected { throw 0; }, - [](int const &) -> fn::expected { throw 0; }, - [](int &&) -> fn::expected { return std::unexpected{FileNotFound}; }, - [](int const &&) -> fn::expected { throw 0; }, - [](std::string_view &) -> fn::expected { throw 0; }, - [](std::string_view const &) -> fn::expected { throw 0; }, - [](std::string_view &&) -> fn::expected { throw 0; }, - [](std::string_view const &&) -> fn::expected { throw 0; })) - .error() - == FileNotFound); + CHECK( + std::move(s) + .or_else( // + fn::overload([](int &) -> fn::expected { throw 0; }, + [](int const &) -> fn::expected { throw 0; }, + [](int &&) -> fn::expected { return ::pfn::unexpected{FileNotFound}; }, + [](int const &&) -> fn::expected { throw 0; }, + [](std::string_view &) -> fn::expected { throw 0; }, + [](std::string_view const &) -> fn::expected { throw 0; }, + [](std::string_view &&) -> fn::expected { throw 0; }, + [](std::string_view const &&) -> fn::expected { throw 0; })) + .error() + == FileNotFound); WHEN("value") { @@ -2289,16 +2298,16 @@ TEST_CASE("expected sum support or_else", "[expected][sum][or_else]") WHEN("constexpr") { - constexpr auto fn - = fn::overload([](int &) -> fn::expected { throw 0; }, - [](int const &) -> fn::expected { return std::unexpected{FileNotFound}; }, - [](int &&) -> fn::expected { throw 0; }, - [](int const &&) -> fn::expected { throw 0; }, - [](std::string_view &) -> fn::expected { throw 0; }, - [](std::string_view const &) -> fn::expected { throw 0; }, - [](std::string_view &&) -> fn::expected { throw 0; }, - [](std::string_view const &&) -> fn::expected { throw 0; }); - constexpr fn::expected> a{std::unexpect, fn::sum{42}}; + constexpr auto fn = fn::overload( + [](int &) -> fn::expected { throw 0; }, + [](int const &) -> fn::expected { return ::pfn::unexpected{FileNotFound}; }, + [](int &&) -> fn::expected { throw 0; }, + [](int const &&) -> fn::expected { throw 0; }, + [](std::string_view &) -> fn::expected { throw 0; }, + [](std::string_view const &) -> fn::expected { throw 0; }, + [](std::string_view &&) -> fn::expected { throw 0; }, + [](std::string_view const &&) -> fn::expected { throw 0; }); + constexpr fn::expected> a{::pfn::unexpect, fn::sum{42}}; static_assert(std::is_same_v>); static_assert(a.or_else(fn).error() == FileNotFound); } @@ -2353,7 +2362,7 @@ TEST_CASE("expected sum support transform", "[expected][sum][transform]") WHEN("error") { - fn::expected, Error> s{std::unexpect, FileNotFound}; + fn::expected, Error> s{::pfn::unexpect, FileNotFound}; CHECK(s.transform( // [](auto...) -> std::monostate { throw 0; }) .error() @@ -2393,7 +2402,7 @@ TEST_CASE("expected sum support transform_error", "[expected][sum][transform_err { WHEN("value") { - fn::expected> s{std::unexpect, fn::sum{12}}; + fn::expected> s{::pfn::unexpect, fn::sum{12}}; CHECK(s.transform_error( // fn::overload( @@ -2465,7 +2474,7 @@ TEST_CASE("expected sum support transform_error", "[expected][sum][transform_err [](int const &&) -> bool { throw 0; }, [](std::string_view &) -> int { throw 0; }, [](std::string_view const &) -> int { throw 0; }, [](std::string_view &&) -> int { throw 0; }, [](std::string_view const &&) -> int { throw 0; }); - constexpr fn::expected> a{std::unexpect, fn::sum{42}}; + constexpr fn::expected> a{::pfn::unexpect, fn::sum{42}}; static_assert(std::is_same_v>>); static_assert(a.transform_error(fn).error() == fn::sum{true}); } @@ -2473,7 +2482,7 @@ TEST_CASE("expected sum support transform_error", "[expected][sum][transform_err WHEN("void") { - fn::expected> s{std::unexpect, fn::sum{12}}; + fn::expected> s{::pfn::unexpect, fn::sum{12}}; CHECK(s.transform_error( // fn::overload( @@ -2541,450 +2550,133 @@ TEST_CASE("expected sum support transform_error", "[expected][sum][transform_err [](int const &&) -> int { throw 0; }, [](std::string_view &) -> int { throw 0; }, [](std::string_view const &) -> int { throw 0; }, [](std::string_view &&) -> int { throw 0; }, [](std::string_view const &&) -> int { throw 0; }); - constexpr fn::expected> a{std::unexpect, fn::sum{42}}; + constexpr fn::expected> a{::pfn::unexpect, fn::sum{42}}; static_assert(std::is_same_v>>); static_assert(a.transform_error(fn).error() == fn::sum{42}); } } } -TEST_CASE("expected polyfills and_then", "[expected][polyfill][and_then]") +TEST_CASE("expected pack support or_else", "[expected][or_else][pack]") { WHEN("value") { - fn::expected s{12}; - CHECK(s.and_then( // - fn::overload([](int &i) -> fn::expected { return i == 12; }, - [](int const &) -> fn::expected { throw 0; }, - [](int &&) -> fn::expected { throw 0; }, - [](int const &&) -> fn::expected { throw 0; })) // + fn::expected> s{::pfn::unexpect, fn::pack{12, FileNotFound}}; + CHECK(s.or_else( // + fn::overload([](int, Error &e) -> fn::expected { return e == FileNotFound; }, + [](int, Error const &) -> fn::expected { throw 0; }, + [](int, Error &&) -> fn::expected { throw 0; }, + [](int, Error const &&) -> fn::expected { throw 0; })) // .value()); CHECK(std::as_const(s) - .and_then( // - fn::overload([](int &) -> fn::expected { throw 0; }, - [](int const &i) -> fn::expected { return i == 12; }, - [](int &&) -> fn::expected { throw 0; }, - [](int const &&) -> fn::expected { throw 0; })) // + .or_else( // + fn::overload([](int, Error &) -> fn::expected { throw 0; }, + [](int, Error const &e) -> fn::expected { return e == FileNotFound; }, + [](int, Error &&) -> fn::expected { throw 0; }, + [](int, Error const &&) -> fn::expected { throw 0; })) // .value()); CHECK(std::move(std::as_const(s)) - .and_then( // - fn::overload([](int &) -> fn::expected { throw 0; }, - [](int const &) -> fn::expected { throw 0; }, - [](int &&) -> fn::expected { throw 0; }, - [](int const &&i) -> fn::expected { return i == 12; })) // + .or_else( // + fn::overload([](int, Error &) -> fn::expected { throw 0; }, + [](int, Error const &) -> fn::expected { throw 0; }, + [](int, Error &&) -> fn::expected { throw 0; }, + [](int, Error const &&e) -> fn::expected { return e == FileNotFound; })) // .value()); CHECK(std::move(s) - .and_then( // - fn::overload([](int &) -> fn::expected { throw 0; }, - [](int const &) -> fn::expected { throw 0; }, - [](int &&i) -> fn::expected { return i == 12; }, - [](int const &&) -> fn::expected { throw 0; })) // + .or_else( // + fn::overload([](int, Error &) -> fn::expected { throw 0; }, + [](int, Error const &) -> fn::expected { throw 0; }, + [](int, Error &&e) -> fn::expected { return e == FileNotFound; }, + [](int, Error const &&) -> fn::expected { throw 0; })) // .value()); - - WHEN("error") - { - fn::expected s{std::unexpect, Unknown}; - CHECK(s.and_then( // - [](auto) -> fn::expected { throw 0; }) - .error() - == Unknown); - CHECK(std::as_const(s) - .and_then( // - [](auto) -> fn::expected { throw 0; }) - .error() - == Unknown); - CHECK(std::move(std::as_const(s)) - .and_then( // - [](auto) -> fn::expected { throw 0; }) - .error() - == Unknown); - CHECK(std::move(s) - .and_then( // - [](auto) -> fn::expected { throw 0; }) - .error() - == Unknown); - } } WHEN("void") { - fn::expected s{}; - CHECK(s.and_then([]() -> fn::expected { return true; }).value()); - CHECK(std::as_const(s).and_then([]() -> fn::expected { return true; }).value()); - CHECK(fn::expected{}.and_then([]() -> fn::expected { return true; }).value()); - CHECK(std::move(std::as_const(s)).and_then([]() -> fn::expected { return true; }).value()); - - WHEN("error") - { - fn::expected s{std::unexpect, Unknown}; - CHECK(s.and_then([]() -> fn::expected { throw 0; }).error() == Unknown); - CHECK(std::as_const(s).and_then([]() -> fn::expected { throw 0; }).error() == Unknown); - CHECK(std::move(std::as_const(s)).and_then([]() -> fn::expected { throw 0; }).error() == Unknown); - CHECK(std::move(s).and_then([]() -> fn::expected { throw 0; }).error() == Unknown); - } - } -} - -TEST_CASE("expected polyfills or_else", "[expected][polyfill][or_else][pack]") -{ - WHEN("value") - { - fn::expected s{1}; - CHECK(s.or_else([](auto) -> fn::expected { throw 0; }).value()); - CHECK(std::as_const(s).or_else([](auto) -> fn::expected { throw 0; }).value()); - CHECK(fn::expected{1}.or_else([](auto) -> fn::expected { throw 0; }).value()); - CHECK(std::move(std::as_const(s)).or_else([](auto) -> fn::expected { throw 0; }).value()); - - WHEN("error") - { - fn::expected s{std::unexpect, FileNotFound}; - CHECK(s.or_else( // - fn::overload([](Error &e) -> fn::expected { return e == FileNotFound; }, - [](Error const &) -> fn::expected { throw 0; }, - [](Error &&) -> fn::expected { throw 0; }, - [](Error const &&) -> fn::expected { throw 0; })) // - .value()); - CHECK(std::as_const(s) - .or_else( // - fn::overload([](Error &) -> fn::expected { throw 0; }, - [](Error const &e) -> fn::expected { return e == FileNotFound; }, - [](Error &&) -> fn::expected { throw 0; }, - [](Error const &&) -> fn::expected { throw 0; })) // - .value()); - CHECK(std::move(std::as_const(s)) - .or_else( // - fn::overload([](Error &) -> fn::expected { throw 0; }, - [](Error const &) -> fn::expected { throw 0; }, - [](Error &&) -> fn::expected { throw 0; }, - [](Error const &&e) -> fn::expected { return e == FileNotFound; })) // - .value()); - CHECK(std::move(s) - .or_else( // - fn::overload([](Error &) -> fn::expected { throw 0; }, - [](Error const &) -> fn::expected { throw 0; }, - [](Error &&e) -> fn::expected { return e == FileNotFound; }, - [](Error const &&) -> fn::expected { throw 0; })) // - .value()); - } - - WHEN("pack error") - { - fn::expected> s{std::unexpect, fn::pack{12, FileNotFound}}; - CHECK(s.or_else( // - fn::overload([](int, Error &e) -> fn::expected { return e == FileNotFound; }, - [](int, Error const &) -> fn::expected { throw 0; }, - [](int, Error &&) -> fn::expected { throw 0; }, - [](int, Error const &&) -> fn::expected { throw 0; })) // - .value()); - CHECK(std::as_const(s) - .or_else( // - fn::overload([](int, Error &) -> fn::expected { throw 0; }, - [](int, Error const &e) -> fn::expected { return e == FileNotFound; }, - [](int, Error &&) -> fn::expected { throw 0; }, - [](int, Error const &&) -> fn::expected { throw 0; })) // - .value()); - CHECK(std::move(std::as_const(s)) - .or_else( // - fn::overload([](int, Error &) -> fn::expected { throw 0; }, - [](int, Error const &) -> fn::expected { throw 0; }, - [](int, Error &&) -> fn::expected { throw 0; }, - [](int, Error const &&e) -> fn::expected { return e == FileNotFound; })) // - .value()); - CHECK(std::move(s) - .or_else( // - fn::overload([](int, Error &) -> fn::expected { throw 0; }, - [](int, Error const &) -> fn::expected { throw 0; }, - [](int, Error &&e) -> fn::expected { return e == FileNotFound; }, - [](int, Error const &&) -> fn::expected { throw 0; })) // - .value()); - } - } - - WHEN("void") - { - fn::expected s{}; - CHECK(s.or_else([](auto) -> fn::expected { throw 0; }).has_value()); - CHECK(std::as_const(s).or_else([](auto) -> fn::expected { throw 0; }).has_value()); - CHECK(fn::expected{}.or_else([](auto) -> fn::expected { throw 0; }).has_value()); - CHECK(std::move(std::as_const(s)).or_else([](auto) -> fn::expected { throw 0; }).has_value()); - - WHEN("error") - { - fn::expected s{std::unexpect, FileNotFound}; - CHECK(s.or_else( // - fn::overload([](Error &) -> fn::expected { return {}; }, - [](Error const &) -> fn::expected { throw 0; }, - [](Error &&) -> fn::expected { throw 0; }, - [](Error const &&) -> fn::expected { throw 0; })) - .has_value()); - CHECK(std::as_const(s) - .or_else( // - fn::overload([](Error &) -> fn::expected { throw 0; }, - [](Error const &) -> fn::expected { return {}; }, - [](Error &&) -> fn::expected { throw 0; }, - [](Error const &&) -> fn::expected { throw 0; })) - .has_value()); - CHECK(std::move(std::as_const(s)) - .or_else( // - fn::overload([](Error &) -> fn::expected { throw 0; }, - [](Error const &) -> fn::expected { throw 0; }, - [](Error &&) -> fn::expected { throw 0; }, - [](Error const &&) -> fn::expected { return {}; })) - .has_value()); - CHECK(std::move(s) - .or_else( // - fn::overload([](Error &) -> fn::expected { throw 0; }, - [](Error const &) -> fn::expected { throw 0; }, - [](Error &&) -> fn::expected { return {}; }, - [](Error const &&) -> fn::expected { throw 0; })) - .has_value()); - } - - WHEN("pack error") - { - fn::expected> s{std::unexpect, fn::pack{12, FileNotFound}}; - CHECK(s.or_else( // - fn::overload([](int, Error &) -> fn::expected { return {}; }, - [](int, Error const &) -> fn::expected { throw 0; }, - [](int, Error &&) -> fn::expected { throw 0; }, - [](int, Error const &&) -> fn::expected { throw 0; })) - .has_value()); - CHECK(std::as_const(s) - .or_else( // - fn::overload([](int, Error &) -> fn::expected { throw 0; }, - [](int, Error const &) -> fn::expected { return {}; }, - [](int, Error &&) -> fn::expected { throw 0; }, - [](int, Error const &&) -> fn::expected { throw 0; })) - .has_value()); - CHECK(std::move(std::as_const(s)) - .or_else( // - fn::overload([](int, Error &) -> fn::expected { throw 0; }, - [](int, Error const &) -> fn::expected { throw 0; }, - [](int, Error &&) -> fn::expected { throw 0; }, - [](int, Error const &&) -> fn::expected { return {}; })) - .has_value()); - CHECK(std::move(s) - .or_else( // - fn::overload([](int, Error &) -> fn::expected { throw 0; }, - [](int, Error const &) -> fn::expected { throw 0; }, - [](int, Error &&) -> fn::expected { return {}; }, - [](int, Error const &&) -> fn::expected { throw 0; })) - .has_value()); - } - } -} - -TEST_CASE("expected polyfills transform", "[expected][polyfill][transform]") -{ - WHEN("value") - { - fn::expected s{12}; - CHECK(s.transform( // - fn::overload([](int &i) -> bool { return i == 12; }, [](int const &) -> bool { throw 0; }, - [](int &&) -> bool { throw 0; }, [](int const &&) -> bool { throw 0; })) // - .value()); + fn::expected> s{::pfn::unexpect, fn::pack{12, FileNotFound}}; + CHECK(s.or_else( // + fn::overload([](int, Error &) -> fn::expected { return {}; }, + [](int, Error const &) -> fn::expected { throw 0; }, + [](int, Error &&) -> fn::expected { throw 0; }, + [](int, Error const &&) -> fn::expected { throw 0; })) + .has_value()); CHECK(std::as_const(s) - .transform( // - fn::overload([](int &) -> bool { throw 0; }, [](int const &i) -> bool { return i == 12; }, - [](int &&) -> bool { throw 0; }, [](int const &&) -> bool { throw 0; })) // - .value()); + .or_else( // + fn::overload([](int, Error &) -> fn::expected { throw 0; }, + [](int, Error const &) -> fn::expected { return {}; }, + [](int, Error &&) -> fn::expected { throw 0; }, + [](int, Error const &&) -> fn::expected { throw 0; })) + .has_value()); CHECK(std::move(std::as_const(s)) - .transform( // - fn::overload([](int &) -> bool { throw 0; }, [](int const &) -> bool { throw 0; }, - [](int &&) -> bool { throw 0; }, [](int const &&i) -> bool { return i == 12; })) // - .value()); + .or_else( // + fn::overload([](int, Error &) -> fn::expected { throw 0; }, + [](int, Error const &) -> fn::expected { throw 0; }, + [](int, Error &&) -> fn::expected { throw 0; }, + [](int, Error const &&) -> fn::expected { return {}; })) + .has_value()); CHECK(std::move(s) - .transform( // - fn::overload([](int &) -> bool { throw 0; }, [](int const &) -> bool { throw 0; }, - [](int &&i) -> bool { return i == 12; }, [](int const &&) -> bool { throw 0; })) // - .value()); - - WHEN("void result") - { - fn::expected s{12}; - CHECK(s.transform( // - fn::overload([](int &) -> void {}, [](int const &) -> void { throw 0; }, - [](int &&) -> void { throw 0; }, [](int const &&) -> void { throw 0; })) // - .has_value()); - CHECK(std::as_const(s) - .transform( // - fn::overload([](int &) -> void { throw 0; }, [](int const &) -> void {}, - [](int &&) -> void { throw 0; }, [](int const &&) -> void { throw 0; })) // - .has_value()); - CHECK(std::move(std::as_const(s)) - .transform( // - fn::overload([](int &) -> void { throw 0; }, [](int const &) -> void { throw 0; }, - [](int &&) -> void { throw 0; }, [](int const &&) -> void {})) // - .has_value()); - CHECK(std::move(s) - .transform( // - fn::overload([](int &) -> void { throw 0; }, [](int const &) -> void { throw 0; }, - [](int &&) -> void {}, [](int const &&) -> void { throw 0; })) // - .has_value()); - } - - WHEN("error") - { - fn::expected s{std::unexpect, Unknown}; - CHECK(s.transform([](auto) -> bool { throw 0; }).error() == Unknown); - CHECK(std::as_const(s).transform([](auto) -> bool { throw 0; }).error() == Unknown); - CHECK(std::move(std::as_const(s)).transform([](auto) -> bool { throw 0; }).error() == Unknown); - CHECK(std::move(s).transform([](auto) -> bool { throw 0; }).error() == Unknown); - } - } - - WHEN("void") - { - fn::expected s{}; - CHECK(s.transform([]() -> bool { return true; }).value()); - CHECK(std::as_const(s).transform([]() -> bool { return true; }).value()); - CHECK(std::move(std::as_const(s)).transform([]() -> bool { return true; }).value()); - CHECK(std::move(s).transform([]() -> bool { return true; }).value()); - - WHEN("void result") - { - fn::expected s{}; - CHECK(s.transform([]() -> void {}).has_value()); - CHECK(std::as_const(s).transform([]() -> void {}).has_value()); - CHECK(std::move(std::as_const(s)).transform([]() -> void {}).has_value()); - CHECK(std::move(s).transform([]() -> void {}).has_value()); - } - - WHEN("error") - { - fn::expected s{std::unexpect, Unknown}; - CHECK(s.transform([]() -> bool { throw 0; }).error() == Unknown); - CHECK(std::as_const(s).transform([]() -> bool { throw 0; }).error() == Unknown); - CHECK(std::move(std::as_const(s)).transform([]() -> bool { throw 0; }).error() == Unknown); - CHECK(std::move(s).transform([]() -> bool { throw 0; }).error() == Unknown); - } + .or_else( // + fn::overload([](int, Error &) -> fn::expected { throw 0; }, + [](int, Error const &) -> fn::expected { throw 0; }, + [](int, Error &&) -> fn::expected { return {}; }, + [](int, Error const &&) -> fn::expected { throw 0; })) + .has_value()); } } -TEST_CASE("expected polyfills transform_error", "[expected][polyfill][transform_error][pack]") +TEST_CASE("expected pack support transform_error", "[expected][transform_error][pack]") { WHEN("value") { - fn::expected s{12}; - CHECK(s.transform_error([](Error) -> bool { throw 0; }).value() == 12); - CHECK(std::as_const(s).transform_error([](Error) -> bool { throw 0; }).value() == 12); - CHECK(fn::expected{12}.transform_error([](Error) -> bool { throw 0; }).value() == 12); - CHECK(std::move(std::as_const(s)).transform_error([](Error) -> bool { throw 0; }).value() == 12); - - WHEN("error") - { - fn::expected s{std::unexpect, FileNotFound}; - CHECK( - s.transform_error( // - fn::overload([](Error &e) -> bool { return e == FileNotFound; }, [](Error const &) -> bool { throw 0; }, - [](Error &&) -> bool { throw 0; }, [](Error const &&) -> bool { throw 0; })) // + fn::expected> s{::pfn::unexpect, fn::pack{12, FileNotFound}}; + CHECK(s.transform_error( // + fn::overload([](int, Error &e) -> bool { return e == FileNotFound; }, + [](int, Error const &) -> bool { throw 0; }, [](int, Error &&) -> bool { throw 0; }, + [](int, Error const &&) -> bool { throw 0; })) // .error()); - CHECK(std::as_const(s) - .transform_error( // - fn::overload([](Error &) -> bool { throw 0; }, - [](Error const &e) -> bool { return e == FileNotFound; }, - [](Error &&) -> bool { throw 0; }, [](Error const &&) -> bool { throw 0; })) // - .error()); - CHECK(std::move(std::as_const(s)) - .transform_error( // - fn::overload([](Error &) -> bool { throw 0; }, [](Error const &) -> bool { throw 0; }, - [](Error &&) -> bool { throw 0; }, - [](Error const &&e) -> bool { return e == FileNotFound; })) // - .error()); - CHECK(std::move(s) - .transform_error( // - fn::overload([](Error &) -> bool { throw 0; }, [](Error const &) -> bool { throw 0; }, - [](Error &&e) -> bool { return e == FileNotFound; }, - [](Error const &&) -> bool { throw 0; })) // - .error()); - } - - WHEN("pack error") - { - fn::expected> s{std::unexpect, fn::pack{12, FileNotFound}}; - CHECK(s.transform_error( // - fn::overload([](int, Error &e) -> bool { return e == FileNotFound; }, - [](int, Error const &) -> bool { throw 0; }, [](int, Error &&) -> bool { throw 0; }, - [](int, Error const &&) -> bool { throw 0; })) // - .error()); - CHECK( - std::as_const(s) + CHECK(std::as_const(s) .transform_error( // fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &e) -> bool { return e == FileNotFound; }, [](int, Error &&) -> bool { throw 0; }, [](int, Error const &&) -> bool { throw 0; })) // .error()); - CHECK(std::move(std::as_const(s)) - .transform_error( // - fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { throw 0; }, - [](int, Error &&) -> bool { throw 0; }, - [](int, Error const &&e) -> bool { return e == FileNotFound; })) // - .error()); - CHECK(std::move(s) - .transform_error( // - fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { throw 0; }, - [](int, Error &&e) -> bool { return e == FileNotFound; }, - [](int, Error const &&) -> bool { throw 0; })) // - .error()); - } + CHECK(std::move(std::as_const(s)) + .transform_error( // + fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { throw 0; }, + [](int, Error &&) -> bool { throw 0; }, + [](int, Error const &&e) -> bool { return e == FileNotFound; })) // + .error()); + CHECK(std::move(s) + .transform_error( // + fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { throw 0; }, + [](int, Error &&e) -> bool { return e == FileNotFound; }, + [](int, Error const &&) -> bool { throw 0; })) // + .error()); } WHEN("void") { - fn::expected s{}; - CHECK(s.transform_error([](auto) -> bool { throw 0; }).has_value()); - CHECK(std::as_const(s).transform_error([](auto) -> bool { throw 0; }).has_value()); - CHECK(fn::expected{}.transform_error([](auto) -> bool { throw 0; }).has_value()); - CHECK(std::move(std::as_const(s)).transform_error([](auto) -> bool { throw 0; }).has_value()); - - WHEN("error") - { - fn::expected s{std::unexpect, FileNotFound}; - CHECK(s.transform_error( // - fn::overload([](Error &) -> bool { return true; }, [](Error const &) -> bool { throw 0; }, - [](Error &&) -> bool { throw 0; }, [](Error const &&) -> bool { throw 0; })) - .error()); - CHECK(std::as_const(s) - .transform_error( // - fn::overload([](Error &) -> bool { throw 0; }, [](Error const &) -> bool { return true; }, - [](Error &&) -> bool { throw 0; }, [](Error const &&) -> bool { throw 0; })) - .error()); - CHECK(std::move(std::as_const(s)) - .transform_error( // - fn::overload([](Error &) -> bool { throw 0; }, [](Error const &) -> bool { throw 0; }, - [](Error &&) -> bool { throw 0; }, [](Error const &&) -> bool { return true; })) - .error()); - CHECK(std::move(s) - .transform_error( // - fn::overload([](Error &) -> bool { throw 0; }, [](Error const &) -> bool { throw 0; }, - [](Error &&) -> bool { return true; }, [](Error const &&) -> bool { throw 0; })) - .error()); - } - - WHEN("pack error") - { - fn::expected> s{std::unexpect, fn::pack{12, FileNotFound}}; - CHECK(s.transform_error( // - fn::overload([](int, Error &) -> bool { return true; }, [](int, Error const &) -> bool { throw 0; }, - [](int, Error &&) -> bool { throw 0; }, [](int, Error const &&) -> bool { throw 0; })) - .error()); - CHECK(std::as_const(s) - .transform_error( // - fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { return true; }, - [](int, Error &&) -> bool { throw 0; }, [](int, Error const &&) -> bool { throw 0; })) - .error()); - CHECK(std::move(std::as_const(s)) - .transform_error( // - fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { throw 0; }, - [](int, Error &&) -> bool { throw 0; }, - [](int, Error const &&) -> bool { return true; })) - .error()); - CHECK(std::move(s) - .transform_error( // - fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { throw 0; }, - [](int, Error &&) -> bool { return true; }, - [](int, Error const &&) -> bool { throw 0; })) - .error()); - } + fn::expected> s{::pfn::unexpect, fn::pack{12, FileNotFound}}; + CHECK(s.transform_error( // + fn::overload([](int, Error &) -> bool { return true; }, [](int, Error const &) -> bool { throw 0; }, + [](int, Error &&) -> bool { throw 0; }, [](int, Error const &&) -> bool { throw 0; })) + .error()); + CHECK(std::as_const(s) + .transform_error( // + fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { return true; }, + [](int, Error &&) -> bool { throw 0; }, [](int, Error const &&) -> bool { throw 0; })) + .error()); + CHECK( + std::move(std::as_const(s)) + .transform_error( // + fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { throw 0; }, + [](int, Error &&) -> bool { throw 0; }, [](int, Error const &&) -> bool { return true; })) + .error()); + CHECK( + std::move(s) + .transform_error( // + fn::overload([](int, Error &) -> bool { throw 0; }, [](int, Error const &) -> bool { throw 0; }, + [](int, Error &&) -> bool { return true; }, [](int, Error const &&) -> bool { throw 0; })) + .error()); } } diff --git a/tests/fn/expected_polyfill.cpp b/tests/fn/expected_polyfill.cpp new file mode 100644 index 00000000..1a8ad3f3 --- /dev/null +++ b/tests/fn/expected_polyfill.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2026 Bronek Kozicki +// +// Distributed under the ISC License. See accompanying file LICENSE.md +// or copy at https://opensource.org/licenses/ISC + +// Run the whole pfn polyfill conformance suite against fn::expected. Bring the +// subject-under-test aliases into the global namespace, then include pfn/expected.cpp. +// The fn::expected sum/graded/pack behaviour is covered in fn/expected.cpp. + +#define LIBFN_ASSERT(...) +#include + +using fn::expected; +using pfn::bad_expected_access; +using pfn::unexpect; +using pfn::unexpect_t; +using pfn::unexpected; + +#define PFN_TEST_NESTED +#include "pfn/expected.cpp" diff --git a/tests/fn/fail.cpp b/tests/fn/fail.cpp index e5f7c783..f02be3ad 100644 --- a/tests/fn/fail.cpp +++ b/tests/fn/fail.cpp @@ -77,7 +77,7 @@ TEST_CASE("fail", "[fail][expected][expected_value][pack]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | fail(wrong)); static_assert(std::is_same_v); REQUIRE((a // @@ -113,7 +113,7 @@ TEST_CASE("fail", "[fail][expected][expected_value][pack]") WHEN("operand is error") { constexpr auto wrong = [](auto...) -> Error { throw 0; }; - REQUIRE((operand_t{std::unexpect, Error{"Not good"}} | fail(wrong)).error().what == "Not good"); + REQUIRE((operand_t{::pfn::unexpect, Error{"Not good"}} | fail(wrong)).error().what == "Not good"); } } @@ -127,9 +127,9 @@ TEST_CASE("fail", "[fail][expected][expected_value][pack]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | fail(wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | fail(wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | fail(wrong)) .error() .what @@ -181,7 +181,7 @@ TEST_CASE("fail", "[fail][expected][expected_void]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | fail(wrong)); static_assert(std::is_same_v); REQUIRE((a // @@ -202,9 +202,9 @@ TEST_CASE("fail", "[fail][expected][expected_void]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | fail(wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | fail(wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | fail(wrong)) .error() .what @@ -351,7 +351,7 @@ TEST_CASE("constexpr fail expected with sum", "[fail][constexpr][expected][sum]" static_assert(r2.error() == Error::SomethingElse); constexpr auto r3 = T{3} | fn::fail(fn); static_assert(r3.error() == Error::ThresholdExceeded); - constexpr auto r4 = T{std::unexpect, Error::Reserved} | fn::fail(fn); + constexpr auto r4 = T{::pfn::unexpect, Error::Reserved} | fn::fail(fn); static_assert(r4.error() == Error::Reserved); SUCCEED(); diff --git a/tests/fn/filter.cpp b/tests/fn/filter.cpp index ca0a4c54..84366379 100644 --- a/tests/fn/filter.cpp +++ b/tests/fn/filter.cpp @@ -86,7 +86,7 @@ TEST_CASE("filter", "[filter][expected][expected_value]") WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | filter(truePred, wrong)); static_assert(std::is_same_v); @@ -121,10 +121,10 @@ TEST_CASE("filter", "[filter][expected][expected_value]") WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | filter(truePred, wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | filter(truePred, wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | filter(truePred, wrong)) .error() .what @@ -230,13 +230,13 @@ TEST_CASE("filter member function", "[filter][expected][expected_value][member_f WHEN("operand is error") { - REQUIRE((operand_t{std::unexpect, Error{"Not good"}} | filter(predPack, errPack)).error().what == "Not good"); + REQUIRE((operand_t{::pfn::unexpect, Error{"Not good"}} | filter(predPack, errPack)).error().what == "Not good"); } } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | filter(predicate, wrong)); static_assert(std::is_same_v); @@ -273,10 +273,10 @@ TEST_CASE("filter member function", "[filter][expected][expected_value][member_f WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | filter(predicate, wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | filter(predicate, wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | filter(predicate, wrong)) .error() .what @@ -333,7 +333,7 @@ TEST_CASE("filter", "[filter][expected][expected_void]") WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | filter(truePred, wrong)); static_assert(std::is_same_v); @@ -368,10 +368,10 @@ TEST_CASE("filter", "[filter][expected][expected_void]") WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | filter(truePred, wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | filter(truePred, wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | filter(truePred, wrong)) .error() .what diff --git a/tests/fn/inspect.cpp b/tests/fn/inspect.cpp index 57dc6d09..d37e87a2 100644 --- a/tests/fn/inspect.cpp +++ b/tests/fn/inspect.cpp @@ -70,7 +70,7 @@ TEST_CASE("inspect expected", "[inspect][expected][expected_value][pack]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | inspect(wrong)); static_assert(std::is_same_v); REQUIRE((a // @@ -108,7 +108,7 @@ TEST_CASE("inspect expected", "[inspect][expected][expected_value][pack]") WHEN("operand is error") { using operand_t = fn::expected, Error>; - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; constexpr auto wrong = [](auto...) { throw 0; }; using T = decltype(a | inspect(wrong)); static_assert(std::is_same_v); @@ -131,9 +131,9 @@ TEST_CASE("inspect expected", "[inspect][expected][expected_value][pack]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | inspect(wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | inspect(wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | inspect(wrong)) .error() .what @@ -180,7 +180,7 @@ TEST_CASE("inspect void expected", "[inspect][expected][expected_void]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | inspect(wrong)); static_assert(std::is_same_v); REQUIRE((a // @@ -202,9 +202,9 @@ TEST_CASE("inspect void expected", "[inspect][expected][expected_void]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | inspect(wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | inspect(wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | inspect(wrong)) .error() .what @@ -383,7 +383,7 @@ TEST_CASE("constexpr inspect expected", "[inspect][constexpr][expected]") constexpr auto fn = [](int) constexpr noexcept -> void {}; constexpr auto r1 = T{0} | fn::inspect(fn); static_assert(r1.value() == 0); - constexpr auto r2 = T{std::unexpect, Error::SomethingElse} | fn::inspect(fn); + constexpr auto r2 = T{::pfn::unexpect, Error::SomethingElse} | fn::inspect(fn); static_assert(r2.error() == Error::SomethingElse); SUCCEED(); @@ -401,7 +401,7 @@ TEST_CASE("constexpr inspect expected with sum", "[inspect][constexpr][expected] }; constexpr auto r12 = T{0} | fn::inspect(fn2); static_assert(r12.value() == fn::sum{0}); - constexpr auto r2 = T{std::unexpect, Error::SomethingElse} | fn::inspect(fn1); + constexpr auto r2 = T{::pfn::unexpect, Error::SomethingElse} | fn::inspect(fn1); static_assert(r2.error() == Error::SomethingElse); SUCCEED(); diff --git a/tests/fn/inspect_error.cpp b/tests/fn/inspect_error.cpp index 82f19e7b..3efe78a5 100644 --- a/tests/fn/inspect_error.cpp +++ b/tests/fn/inspect_error.cpp @@ -62,7 +62,7 @@ TEST_CASE("inspect_error expected", "[inspect_error][expected]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | inspect_error(fnError)); static_assert(std::is_same_v); REQUIRE((a // @@ -74,7 +74,7 @@ TEST_CASE("inspect_error expected", "[inspect_error][expected]") } WHEN("calling member function") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | inspect_error(&Error::finalize)); static_assert(std::is_same_v); auto const before = Error::count; @@ -97,9 +97,9 @@ TEST_CASE("inspect_error expected", "[inspect_error][expected]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | inspect_error(fnError)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | inspect_error(fnError)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | inspect_error(fnError)) .error() .what @@ -108,10 +108,10 @@ TEST_CASE("inspect_error expected", "[inspect_error][expected]") } WHEN("calling member function") { - using T = decltype(operand_t{std::unexpect, "Not good"} | inspect_error(&Error::finalize)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | inspect_error(&Error::finalize)); static_assert(std::is_same_v); auto const before = Error::count; - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | inspect_error(&Error::finalize)) .error() .what @@ -183,7 +183,7 @@ TEST_CASE("constexpr inspect_error expected", "[inspect_error][constexpr][expect constexpr auto fn = [](Error) constexpr noexcept -> void {}; constexpr auto r1 = T{0} | fn::inspect_error(fn); static_assert(r1.value() == 0); - constexpr auto r2 = T{std::unexpect, Error::SomethingElse} | fn::inspect_error(fn); + constexpr auto r2 = T{::pfn::unexpect, Error::SomethingElse} | fn::inspect_error(fn); static_assert(r2.error() == Error::SomethingElse); SUCCEED(); @@ -196,9 +196,9 @@ TEST_CASE("constexpr inspect_error expected with sum", "[inspect_error][constexp constexpr auto fn = fn::overload{[](Error) constexpr noexcept -> void {}, [](bool) constexpr noexcept -> void {}}; constexpr auto r1 = T{0} | fn::inspect_error(fn); static_assert(r1.value() == 0); - constexpr auto r2 = T{std::unexpect, fn::sum{Error::SomethingElse}} | fn::inspect_error(fn); + constexpr auto r2 = T{::pfn::unexpect, fn::sum{Error::SomethingElse}} | fn::inspect_error(fn); static_assert(r2.error() == fn::sum{Error::SomethingElse}); - constexpr auto r3 = T{std::unexpect, fn::sum{false}} | fn::inspect_error(fn); + constexpr auto r3 = T{::pfn::unexpect, fn::sum{false}} | fn::inspect_error(fn); static_assert(r3.error() == fn::sum{false}); SUCCEED(); diff --git a/tests/fn/or_else.cpp b/tests/fn/or_else.cpp index 27798c40..8df8b555 100644 --- a/tests/fn/or_else.cpp +++ b/tests/fn/or_else.cpp @@ -45,9 +45,9 @@ TEST_CASE("or_else", "[or_else][expected][expected_value]") constexpr auto fnError = [](Error e) -> operand_t { return {e.what.size()}; }; constexpr auto fnXerror - = [](Error e) -> fn::expected { return std::unexpected{"Was: " + e.what}; }; + = [](Error e) -> fn::expected { return ::pfn::unexpected{"Was: " + e.what}; }; constexpr auto wrong = [](Error) -> operand_t { throw 0; }; - constexpr auto fnFail = [](Error v) -> operand_t { return std::unexpected("Got: " + v.what); }; + constexpr auto fnFail = [](Error v) -> operand_t { return ::pfn::unexpected("Got: " + v.what); }; static_assert(is::invocable_with_any(fnError)); static_assert(is::invocable_with_any(fnXerror)); @@ -90,7 +90,7 @@ TEST_CASE("or_else", "[or_else][expected][expected_value]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | or_else(fnError)); static_assert(std::is_same_v); REQUIRE((a | or_else(fnError)).value() == 8); @@ -111,7 +111,7 @@ TEST_CASE("or_else", "[or_else][expected][expected_value]") } WHEN("calling member function") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | or_else(&Error::fn)); static_assert(std::is_same_v); REQUIRE((a | or_else(&Error::fn)).value() == 8); @@ -128,15 +128,15 @@ TEST_CASE("or_else", "[or_else][expected][expected_value]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | or_else(fnError)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | or_else(fnError)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} | or_else(fnError)).value() == 8); + REQUIRE((operand_t{::pfn::unexpect, "Not good"} | or_else(fnError)).value() == 8); WHEN("fail") { - using T = decltype(operand_t{std::unexpect, "Not good"} | or_else(fnFail)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | or_else(fnFail)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | or_else(fnFail)) .error() .what @@ -145,9 +145,9 @@ TEST_CASE("or_else", "[or_else][expected][expected_value]") } WHEN("calling member function") { - using T = decltype(operand_t{std::unexpect, "Not good"} | or_else(&Error::fn)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | or_else(&Error::fn)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} | or_else(&Error::fn)).value() == 8); + REQUIRE((operand_t{::pfn::unexpect, "Not good"} | or_else(&Error::fn)).value() == 8); } } } @@ -166,9 +166,9 @@ TEST_CASE("or_else", "[or_else][expected][expected_void]") return {}; }; constexpr auto fnXerror - = [](Error e) -> fn::expected { return std::unexpected{"Was: " + e.what}; }; + = [](Error e) -> fn::expected { return ::pfn::unexpected{"Was: " + e.what}; }; constexpr auto wrong = [](Error) -> operand_t { throw 0; }; - constexpr auto fnFail = [](Error v) -> operand_t { return std::unexpected("Got: " + v.what); }; + constexpr auto fnFail = [](Error v) -> operand_t { return ::pfn::unexpected("Got: " + v.what); }; static_assert(is::invocable_with_any(fnError)); static_assert(is::invocable_with_any(fnXerror)); @@ -201,7 +201,7 @@ TEST_CASE("or_else", "[or_else][expected][expected_void]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | or_else(fnError)); static_assert(std::is_same_v); (a | or_else(fnError)).value(); @@ -224,7 +224,7 @@ TEST_CASE("or_else", "[or_else][expected][expected_void]") } WHEN("calling member function") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | or_else(&Error::finalize)); static_assert(std::is_same_v); auto const before = Error::count; @@ -244,15 +244,15 @@ TEST_CASE("or_else", "[or_else][expected][expected_void]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | or_else(fnError)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | or_else(fnError)); static_assert(std::is_same_v); - (operand_t{std::unexpect, "Not good"} | or_else(fnError)).value(); + (operand_t{::pfn::unexpect, "Not good"} | or_else(fnError)).value(); WHEN("fail") { - using T = decltype(operand_t{std::unexpect, "Not good"} | or_else(fnFail)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | or_else(fnFail)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | or_else(fnFail)) .error() .what @@ -261,10 +261,10 @@ TEST_CASE("or_else", "[or_else][expected][expected_void]") } WHEN("calling member function") { - using T = decltype(operand_t{std::unexpect, "Not good"} | or_else(&Error::finalize)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | or_else(&Error::finalize)); static_assert(std::is_same_v); auto const before = Error::count; - (operand_t{std::unexpect, "Not good"} | or_else(&Error::finalize)).value(); + (operand_t{::pfn::unexpect, "Not good"} | or_else(&Error::finalize)).value(); CHECK(Error::count == before + 8); } } @@ -352,13 +352,13 @@ TEST_CASE("constexpr or_else expected", "[or_else][constexpr][expected]") constexpr auto fn = [](Error e) constexpr noexcept -> T { if (e == Error::SomethingElse) return {0}; - return std::unexpected{e}; + return ::pfn::unexpected{e}; }; constexpr auto r1 = T{0} | fn::or_else(fn); static_assert(r1.value() == 0); - constexpr auto r2 = T{std::unexpect, Error::SomethingElse} | fn::or_else(fn); + constexpr auto r2 = T{::pfn::unexpect, Error::SomethingElse} | fn::or_else(fn); static_assert(r2.value() == 0); - constexpr auto r3 = T{std::unexpect, Error::ThresholdExceeded} | fn::or_else(fn); + constexpr auto r3 = T{::pfn::unexpect, Error::ThresholdExceeded} | fn::or_else(fn); static_assert(r3.error() == Error::ThresholdExceeded); } @@ -372,12 +372,12 @@ TEST_CASE("constexpr or_else expected", "[or_else][constexpr][expected]") constexpr auto fn = [](Error e) constexpr noexcept -> T1 { if (e == Error::SomethingElse) return {true}; - return T1{std::unexpect}; + return T1{::pfn::unexpect}; }; - constexpr auto r1 = T{std::unexpect, Error::SomethingElse} | fn::or_else(fn); + constexpr auto r1 = T{::pfn::unexpect, Error::SomethingElse} | fn::or_else(fn); static_assert(std::is_same_v const>); static_assert(r1.value() == true); - constexpr auto r2 = T{std::unexpect, Error::ThresholdExceeded} | fn::or_else(fn); + constexpr auto r2 = T{::pfn::unexpect, Error::ThresholdExceeded} | fn::or_else(fn); static_assert(r2.error() == UnrecoverableError{}); } @@ -394,12 +394,12 @@ TEST_CASE("constexpr or_else expected with sum", "[or_else][constexpr][expected] constexpr auto fn = fn::overload{[](int i) constexpr noexcept -> T { if (i < 3) return {i + 1}; - return std::unexpected>{Error::ThresholdExceeded}; + return ::pfn::unexpected>{Error::ThresholdExceeded}; }, [](Error v) constexpr noexcept -> T { return {static_cast(v)}; }}; - constexpr auto r1 = T{std::unexpect, 0} | fn::or_else(fn); + constexpr auto r1 = T{::pfn::unexpect, 0} | fn::or_else(fn); static_assert(r1.value() == 1); - constexpr auto r2 = T{std::unexpect, 3} | fn::or_else(fn); + constexpr auto r2 = T{::pfn::unexpect, 3} | fn::or_else(fn); static_assert(r2.error() == fn::sum{Error::ThresholdExceeded}); } @@ -410,15 +410,15 @@ TEST_CASE("constexpr or_else expected with sum", "[or_else][constexpr][expected] = fn::overload{[](int i) constexpr noexcept -> T1 { if (i < 2) return {i + 1}; - return std::unexpected{Error::SomethingElse}; + return ::pfn::unexpected{Error::SomethingElse}; }, - [](Error) constexpr noexcept -> T1 { return std::unexpected{Error::UnexpectedType}; }}; - constexpr auto r1 = T{std::unexpect, 1} | fn::or_else(fn); + [](Error) constexpr noexcept -> T1 { return ::pfn::unexpected{Error::UnexpectedType}; }}; + constexpr auto r1 = T{::pfn::unexpect, 1} | fn::or_else(fn); static_assert(std::is_same_v const>); static_assert(r1.value() == 2); - constexpr auto r2 = T{std::unexpect, 2} | fn::or_else(fn); + constexpr auto r2 = T{::pfn::unexpect, 2} | fn::or_else(fn); static_assert(r2.error() == Error::SomethingElse); - constexpr auto r3 = T{std::unexpect, Error::ThresholdExceeded} | fn::or_else(fn); + constexpr auto r3 = T{::pfn::unexpect, Error::ThresholdExceeded} | fn::or_else(fn); static_assert(r3.error() == Error::UnexpectedType); } @@ -435,15 +435,15 @@ TEST_CASE("constexpr or_else graded monad", "[or_else][constexpr][expected][grad constexpr auto fn1 = [](Error i) -> fn::expected { if (i == Error::Unknown) return {0}; - return std::unexpected{(int)i}; + return ::pfn::unexpected{(int)i}; }; constexpr auto r1 = T{14} | fn::or_else(fn1); static_assert(std::is_same_v, int> const>); static_assert(r1.value() == fn::sum{14}); - constexpr auto r2 = T{std::unexpect, Error::InvalidValue} | fn::or_else(fn1); + constexpr auto r2 = T{::pfn::unexpect, Error::InvalidValue} | fn::or_else(fn1); static_assert(r2.error() == 1); - constexpr auto r3 = T{std::unexpect, Error::Unknown} | fn::or_else(fn1); + constexpr auto r3 = T{::pfn::unexpect, Error::Unknown} | fn::or_else(fn1); static_assert(r3.value() == fn::sum{0}); } diff --git a/tests/fn/recover.cpp b/tests/fn/recover.cpp index 6b93a0e8..8c717e96 100644 --- a/tests/fn/recover.cpp +++ b/tests/fn/recover.cpp @@ -66,7 +66,7 @@ TEST_CASE("recover", "[recover][expected][expected_value]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | recover(fnError)); static_assert(std::is_same_v); REQUIRE((a | recover(fnError)).value() == 8); @@ -83,9 +83,9 @@ TEST_CASE("recover", "[recover][expected][expected_value]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | recover(fnError)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | recover(fnError)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} | recover(fnError)).value() == 8); + REQUIRE((operand_t{::pfn::unexpect, "Not good"} | recover(fnError)).value() == 8); } } } @@ -128,7 +128,7 @@ TEST_CASE("recover", "[recover][expected][expected_void]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | recover(fnError)); static_assert(std::is_same_v); (a | recover(fnError)).value(); @@ -147,9 +147,9 @@ TEST_CASE("recover", "[recover][expected][expected_void]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | recover(fnError)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | recover(fnError)); static_assert(std::is_same_v); - (operand_t{std::unexpect, "Not good"} | recover(fnError)).value(); + (operand_t{::pfn::unexpect, "Not good"} | recover(fnError)).value(); REQUIRE(count == 1); } } @@ -223,9 +223,9 @@ TEST_CASE("constexpr recover expected", "[recover][constexpr][expected]") }; constexpr auto r1 = T{2} | fn::recover(fn); static_assert(r1.value() == 2); - constexpr auto r2 = T{std::unexpect, Error::SomethingElse} | fn::recover(fn); + constexpr auto r2 = T{::pfn::unexpect, Error::SomethingElse} | fn::recover(fn); static_assert(r2.value() == 0); - constexpr auto r3 = T{std::unexpect, Error::ThresholdExceeded} | fn::recover(fn); + constexpr auto r3 = T{::pfn::unexpect, Error::ThresholdExceeded} | fn::recover(fn); static_assert(r3.value() == 1); SUCCEED(); @@ -244,11 +244,11 @@ TEST_CASE("constexpr recover expected with sum", "[recover][constexpr][expected] [](bool e) constexpr noexcept -> int { return (int)e; }}; constexpr auto r1 = T{2} | fn::recover(fn); static_assert(r1.value() == 2); - constexpr auto r2 = T{std::unexpect, fn::sum{Error::SomethingElse}} | fn::recover(fn); + constexpr auto r2 = T{::pfn::unexpect, fn::sum{Error::SomethingElse}} | fn::recover(fn); static_assert(r2.value() == 0); - constexpr auto r3 = T{std::unexpect, fn::sum{true}} | fn::recover(fn); + constexpr auto r3 = T{::pfn::unexpect, fn::sum{true}} | fn::recover(fn); static_assert(r3.value() == 1); - constexpr auto r4 = T{std::unexpect, fn::sum{Error::ThresholdExceeded}} | fn::recover(fn); + constexpr auto r4 = T{::pfn::unexpect, fn::sum{Error::ThresholdExceeded}} | fn::recover(fn); static_assert(r4.value() == 1); SUCCEED(); diff --git a/tests/fn/transform.cpp b/tests/fn/transform.cpp index 4cb2ba42..cdb48b8e 100644 --- a/tests/fn/transform.cpp +++ b/tests/fn/transform.cpp @@ -69,7 +69,7 @@ TEST_CASE("transform", "[transform][expected][expected_value][pack]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | transform(wrong)); static_assert(std::is_same_v); REQUIRE((a // @@ -92,7 +92,7 @@ TEST_CASE("transform", "[transform][expected][expected_value][pack]") WHEN("operand is error") { constexpr auto wrong = [](auto...) -> int { throw 0; }; - REQUIRE((operand_t{std::unexpect, Error{"Not good"}} | transform(wrong)).error().what == "Not good"); + REQUIRE((operand_t{::pfn::unexpect, Error{"Not good"}} | transform(wrong)).error().what == "Not good"); } } @@ -113,9 +113,9 @@ TEST_CASE("transform", "[transform][expected][expected_value][pack]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | transform(wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | transform(wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | transform(wrong)) .error() .what @@ -161,7 +161,7 @@ TEST_CASE("transform", "[transform][expected][expected_void]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | transform(wrong)); static_assert(std::is_same_v); REQUIRE((a // @@ -190,9 +190,9 @@ TEST_CASE("transform", "[transform][expected][expected_void]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | transform(wrong)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | transform(wrong)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | transform(wrong)) .error() .what @@ -381,7 +381,7 @@ TEST_CASE("constexpr transform expected", "[transform][constexpr][expected]") static_assert(r1.value() == 1); constexpr auto r2 = r1 | fn::transform(fn) | fn::transform(fn) | fn::transform(fn); static_assert(r2.value() == 2); - constexpr auto r3 = T{std::unexpect, Error::SomethingElse} | fn::transform(fn); + constexpr auto r3 = T{::pfn::unexpect, Error::SomethingElse} | fn::transform(fn); static_assert(r3.error() == Error::SomethingElse); } @@ -395,7 +395,7 @@ TEST_CASE("constexpr transform expected", "[transform][constexpr][expected]") static_assert(r2.value() == false); constexpr auto r3 = T{2} | fn::transform(fn); static_assert(r3.value() == false); - constexpr auto r4 = T{std::unexpect, Error::SomethingElse} | fn::transform(fn); + constexpr auto r4 = T{::pfn::unexpect, Error::SomethingElse} | fn::transform(fn); static_assert(r4.error() == Error::SomethingElse); } @@ -422,7 +422,7 @@ TEST_CASE("constexpr transform expected with sum", "[transform][constexpr][expec static_assert(r2.value() == fn::sum{3}); constexpr auto r3 = T{Xint{4}} | fn::transform(fn); static_assert(r3.value() == fn::sum{4}); - constexpr auto r4 = T{std::unexpect, Error::SomethingElse} | fn::transform(fn); + constexpr auto r4 = T{::pfn::unexpect, Error::SomethingElse} | fn::transform(fn); static_assert(r4.error() == Error::SomethingElse); } @@ -437,7 +437,7 @@ TEST_CASE("constexpr transform expected with sum", "[transform][constexpr][expec static_assert(r2.value() == fn::sum{false}); constexpr auto r3 = T{Xint{3}} | fn::transform(fn); static_assert(r3.value() == fn::sum{3}); - constexpr auto r4 = T{std::unexpect, Error::SomethingElse} | fn::transform(fn); + constexpr auto r4 = T{::pfn::unexpect, Error::SomethingElse} | fn::transform(fn); static_assert(r4.error() == Error::SomethingElse); } diff --git a/tests/fn/transform_error.cpp b/tests/fn/transform_error.cpp index 55c69056..7f8c4295 100644 --- a/tests/fn/transform_error.cpp +++ b/tests/fn/transform_error.cpp @@ -64,7 +64,7 @@ TEST_CASE("transform_error", "[transform_error][expected]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | transform_error(fnError)); static_assert(std::is_same_v); REQUIRE((a // @@ -92,9 +92,9 @@ TEST_CASE("transform_error", "[transform_error][expected]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | transform_error(fnError)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | transform_error(fnError)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} // + REQUIRE((operand_t{::pfn::unexpect, "Not good"} // | transform_error(fnError)) .error() .what @@ -102,9 +102,9 @@ TEST_CASE("transform_error", "[transform_error][expected]") WHEN("change type") { - using T = decltype(operand_t{std::unexpect, "Not good"} | transform_error(fnXerror)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | transform_error(fnXerror)); static_assert(std::is_same_v>); - REQUIRE((operand_t{std::unexpect, "Not good"} | transform_error(fnXerror)).error().value == 8); + REQUIRE((operand_t{::pfn::unexpect, "Not good"} | transform_error(fnXerror)).error().value == 8); } } } @@ -136,11 +136,11 @@ TEST_CASE("constexpr transform_error expected", "[transform_error][constexpr][ex }; constexpr auto r1 = T{0} | fn::transform_error(fn); static_assert(r1.value() == 0); - constexpr auto r2 = T{std::unexpect, Error::ThresholdExceeded} | fn::transform_error(fn); + constexpr auto r2 = T{::pfn::unexpect, Error::ThresholdExceeded} | fn::transform_error(fn); static_assert(r2.error() == Error::ThresholdExceeded); - constexpr auto r3 = T{std::unexpect, Error::SomethingElse} | fn::transform_error(fn); + constexpr auto r3 = T{::pfn::unexpect, Error::SomethingElse} | fn::transform_error(fn); static_assert(r3.error() == Error::SomethingElse); - constexpr auto r4 = T{std::unexpect, Error::Unknown} | fn::transform_error(fn); + constexpr auto r4 = T{::pfn::unexpect, Error::Unknown} | fn::transform_error(fn); static_assert(r4.error() == Error::SomethingElse); } @@ -154,9 +154,9 @@ TEST_CASE("constexpr transform_error expected", "[transform_error][constexpr][ex constexpr auto r1 = T{0} | fn::transform_error(fn); static_assert(std::is_same_v const>); static_assert(r1.value() == 0); - constexpr auto r2 = T{std::unexpect, Error::ThresholdExceeded} | fn::transform_error(fn); + constexpr auto r2 = T{::pfn::unexpect, Error::ThresholdExceeded} | fn::transform_error(fn); static_assert(r2.error() == UnrecoverableError{}); - constexpr auto r3 = T{std::unexpect, Error::SomethingElse} | fn::transform_error(fn); + constexpr auto r3 = T{::pfn::unexpect, Error::SomethingElse} | fn::transform_error(fn); static_assert(r3.error() == UnrecoverableError{}); } @@ -172,10 +172,10 @@ TEST_CASE("constexpr transform_error expected with sum", "[transform_error][cons { constexpr auto fn = fn::overload{[](bool i) constexpr noexcept -> fn::sum { return not i; }, [](Error v) constexpr noexcept -> fn::sum { return v; }}; - constexpr auto r1 = T{std::unexpect, fn::sum{Error::SomethingElse}} | fn::transform_error(fn); + constexpr auto r1 = T{::pfn::unexpect, fn::sum{Error::SomethingElse}} | fn::transform_error(fn); static_assert(std::is_same_v> const>); static_assert(r1.error() == fn::sum{Error::SomethingElse}); - constexpr auto r2 = T{std::unexpect, fn::sum{true}} | fn::transform_error(fn); + constexpr auto r2 = T{::pfn::unexpect, fn::sum{true}} | fn::transform_error(fn); static_assert(r2.error() == fn::sum{false}); constexpr auto r3 = T{42} | fn::transform_error(fn); static_assert(r3.value() == 42); @@ -185,10 +185,10 @@ TEST_CASE("constexpr transform_error expected with sum", "[transform_error][cons { constexpr auto fn = fn::overload{[](bool i) constexpr noexcept -> bool { return not i; }, [](Error v) constexpr noexcept -> int { return static_cast(v) + 1; }}; - constexpr auto r1 = T{std::unexpect, fn::sum{Error::SomethingElse}} | fn::transform_error(fn); + constexpr auto r1 = T{::pfn::unexpect, fn::sum{Error::SomethingElse}} | fn::transform_error(fn); static_assert(std::is_same_v> const>); static_assert(r1.error() == fn::sum{2}); - constexpr auto r2 = T{std::unexpect, fn::sum{true}} | fn::transform_error(fn); + constexpr auto r2 = T{::pfn::unexpect, fn::sum{true}} | fn::transform_error(fn); static_assert(r2.error() == fn::sum{false}); constexpr auto r3 = T{42} | fn::transform_error(fn); static_assert(r3.value() == 42); diff --git a/tests/fn/value_or.cpp b/tests/fn/value_or.cpp index 421f793d..930394b2 100644 --- a/tests/fn/value_or.cpp +++ b/tests/fn/value_or.cpp @@ -35,7 +35,7 @@ TEST_CASE("value_or", "[value_or][expected][expected_value]") } WHEN("operand is error") { - operand_t a{std::unexpect, "Not good"}; + operand_t a{::pfn::unexpect, "Not good"}; using T = decltype(a | value_or(3)); static_assert(std::is_same_v); REQUIRE((a | value_or(3)).value() == 3); @@ -52,9 +52,9 @@ TEST_CASE("value_or", "[value_or][expected][expected_value]") } WHEN("operand is error") { - using T = decltype(operand_t{std::unexpect, "Not good"} | value_or(3)); + using T = decltype(operand_t{::pfn::unexpect, "Not good"} | value_or(3)); static_assert(std::is_same_v); - REQUIRE((operand_t{std::unexpect, "Not good"} | value_or(3)).value() == 3); + REQUIRE((operand_t{::pfn::unexpect, "Not good"} | value_or(3)).value() == 3); } } } @@ -107,7 +107,7 @@ TEST_CASE("constexpr value_or expected", "[value_or][constexpr][expected]") constexpr auto r1 = T{2} | fn::value_or(3); static_assert(r1.value() == 2); - constexpr auto r2 = T{std::unexpect, Error::SomethingElse} | fn::value_or(3); + constexpr auto r2 = T{::pfn::unexpect, Error::SomethingElse} | fn::value_or(3); static_assert(r2.value() == 3); SUCCEED(); diff --git a/tests/pfn/expected.cpp b/tests/pfn/expected.cpp index db2b7e33..d1145312 100644 --- a/tests/pfn/expected.cpp +++ b/tests/pfn/expected.cpp @@ -35,6 +35,13 @@ using pfn::unexpected; enum Error { unknown = 1, file_not_found = 5 }; +struct greedy_t { + greedy_t() = delete; + greedy_t(greedy_t const &) = delete; + greedy_t(greedy_t &&) = delete; + template constexpr greedy_t(U &&) noexcept {} +}; + TEST_CASE("bad_expected_access", "[expected][polyfill][bad_expected_access]") { std::string const e1 = "bad access to expected"; @@ -720,6 +727,14 @@ TEST_CASE("expected non void", "[expected][polyfill]") T const c(helper(13)); CHECK(c.value().v == 13 * from_rval); + + using H = expected; + static_assert(not std::is_copy_constructible_v); + static_assert(not std::is_move_constructible_v); + static_assert(not std::is_constructible_v); + static_assert(not std::is_constructible_v); + static_assert(not std::is_constructible_v); + static_assert(not std::is_constructible_v); } SECTION("from unexpected rval") @@ -891,7 +906,50 @@ TEST_CASE("expected non void", "[expected][polyfill]") static_assert(not std::is_copy_constructible_v>); static_assert(not std::is_move_constructible_v>); static_assert(not std::is_move_constructible_v>); - SUCCEED(); + + // An immovable (non-copyable, non-movable) value or error type is still + // usable: the expected can be built in place and observed, even though it is + // itself neither copyable nor movable. + static_assert(not std::is_copy_constructible_v>); + static_assert(not std::is_move_constructible_v>); + static_assert(not std::is_copy_constructible_v>); + static_assert(not std::is_move_constructible_v>); + { + expected const a(std::in_place, 6, 7); + CHECK(a.value().v == 6 * 7); + } + { + expected const a(unexpect, 6, 7); + CHECK(a.error().v == 6 * 7); + } + } + + SECTION("move-only value type") + { + using T = expected; + static_assert(not std::is_copy_constructible_v); + static_assert(std::is_move_constructible_v); + static_assert(not std::is_trivially_move_constructible_v); + static_assert(not extension || std::is_nothrow_move_constructible_v); + + T a(std::in_place, 7); + T b = std::move(a); + CHECK(b.has_value()); + CHECK(b.value().v == 7 * from_rval); + } + + SECTION("move-only error type") + { + using T = expected; + static_assert(not std::is_copy_constructible_v); + static_assert(std::is_move_constructible_v); + static_assert(not std::is_trivially_move_constructible_v); + static_assert(not extension || std::is_nothrow_move_constructible_v); + + T a(unexpect, 7); + T b = std::move(a); + CHECK(not b.has_value()); + CHECK(b.error().v == 7 * from_rval); } SECTION("trivial") @@ -2097,6 +2155,49 @@ TEST_CASE("expected non void", "[expected][polyfill]") } } + SECTION("move-only value type") + { + // Copy-assignment is deleted, so only rval (move) assignment is available. + using T = expected; + static_assert(not std::is_copy_assignable_v); + static_assert(std::is_move_assignable_v); + + SECTION("value to value") + { + T a(std::in_place, 3); + a = T(std::in_place, 7); + CHECK(a.value().v == 7 * from_rval); + } + + SECTION("error to value") + { + T a(unexpect, Error::unknown); + a = T(std::in_place, 7); + CHECK(a.value().v == 7 * from_rval); + } + } + + SECTION("move-only error type") + { + using T = expected; + static_assert(not std::is_copy_assignable_v); + static_assert(std::is_move_assignable_v); + + SECTION("error to error") + { + T a(unexpect, 3); + a = T(unexpect, 7); + CHECK(a.error().v == 7 * from_rval); + } + + SECTION("value to error") + { + T a(std::in_place, 5); + a = T(unexpect, 7); + CHECK(a.error().v == 7 * from_rval); + } + } + SECTION("constexpr") { SECTION("nothrow move") @@ -2238,6 +2339,21 @@ TEST_CASE("expected non void", "[expected][polyfill]") } } + SECTION("move-only value type") + { + // emplace constructs in place, so it needs neither copy nor move of the value. + expected, Error> a(unexpect, Error::file_not_found); + a.emplace(7); + CHECK(a.value().v == 7); + } + + SECTION("immovable value type") + { + expected, Error> a(unexpect, Error::unknown); + a.emplace(6, 7); + CHECK(a.value().v == 6 * 7); + } + SECTION("constexpr") { using T = expected; @@ -3761,6 +3877,34 @@ TEST_CASE("expected void", "[expected_void][polyfill]") SECTION("copy, move and dtor") { + SECTION("immovable error type") + { + // An immovable (non-copyable, non-movable) error type leaves the expected + // neither copyable nor movable, yet it can still be built in place and observed. + static_assert(not std::is_copy_constructible_v>); + static_assert(not std::is_move_constructible_v>); + + expected const a(unexpect, 6, 7); + CHECK(a.error().v == 6 * 7); + + expected const b(std::in_place); + CHECK(b.has_value()); + } + + SECTION("move-only error type") + { + using T = expected; + static_assert(not std::is_copy_constructible_v); + static_assert(std::is_move_constructible_v); + static_assert(not std::is_trivially_move_constructible_v); + static_assert(not extension || std::is_nothrow_move_constructible_v); + + T a(unexpect, 7); + T b = std::move(a); + CHECK(not b.has_value()); + CHECK(b.error().v == 7 * from_rval); + } + SECTION("trivial") { using T = expected; @@ -4458,6 +4602,28 @@ TEST_CASE("expected void", "[expected_void][polyfill]") } } + SECTION("move-only error type") + { + // Copy-assignment is deleted, so only rval (move) assignment is available. + using T = expected; + static_assert(not std::is_copy_assignable_v); + static_assert(std::is_move_assignable_v); + + SECTION("error to error") + { + T a(unexpect, 3); + a = T(unexpect, 7); + CHECK(a.error().v == 7 * from_rval); + } + + SECTION("value to error") + { + T a(std::in_place); + a = T(unexpect, 7); + CHECK(a.error().v == 7 * from_rval); + } + } + SECTION("constexpr") { using T = expected; @@ -4542,6 +4708,22 @@ TEST_CASE("expected void", "[expected_void][polyfill]") #endif } + SECTION("move-only error type") + { + // emplace() destroys the error and sets the value state, so the error type + // need be neither copyable nor movable. + expected a(unexpect, 7); + a.emplace(); + CHECK(a.has_value()); + } + + SECTION("immovable error type") + { + expected a(unexpect, 6, 7); + a.emplace(); + CHECK(a.has_value()); + } + SECTION("constexpr") { using T = expected; diff --git a/tests/util/helper_types.hpp b/tests/util/helper_types.hpp index 18e9a072..79ec3809 100644 --- a/tests/util/helper_types.hpp +++ b/tests/util/helper_types.hpp @@ -183,3 +183,92 @@ template constexpr void swap(helper_t &l, helper_t &r) } using helper = helper_t<0>; + +// Move-only counterpart to helper_t: copy construction/assignment are deleted; +// the move operations are witnessed by a prime factor and parameterized by V with +// the same scheme as helper_t (V in [3,5) throws on move-construct, V in [40,41) +// throws on move-assign, V < 8 throws on the value constructor). +template struct helper_move_only_t { + int v = {}; + + helper_move_only_t() = delete; + constexpr ~helper_move_only_t() noexcept {}; + + helper_move_only_t(helper_move_only_t const &) = delete; + helper_move_only_t &operator=(helper_move_only_t const &) = delete; + + constexpr helper_move_only_t(helper_move_only_t &&o) noexcept(V < 3 || V >= 5) : v(o.v) + { + v *= from_rval; + if constexpr (V >= 3 && V < 5) { + if (v == 0) + throw std::runtime_error("invalid input"); + } + } + constexpr helper_move_only_t(helper_move_only_t const &&o) noexcept : v(o.v) { v *= from_rval_const; } + + constexpr helper_move_only_t &operator=(helper_move_only_t &&o) noexcept(V < 40 || V >= 41) + { + if constexpr (V >= 40 && V < 41) { + if (o.v == 0) + throw std::runtime_error("invalid input"); + } + v = o.v; + v *= from_rval; + return *this; + } + + helper_move_only_t(std::integral auto... a) noexcept(V >= 8) + requires(sizeof...(a) > 0) // intentionally implicit when sizeof...(a) == 1 + : v((1 * ... * a)) + { + if constexpr (V < 8) { + if (v == 0) + throw std::runtime_error("invalid input"); + } + } + + constexpr bool operator==(helper_move_only_t const &) const noexcept = default; +}; + +static_assert(not std::is_copy_constructible_v>); +static_assert(std::is_move_constructible_v>); +static_assert(std::is_nothrow_move_constructible_v>); +static_assert(not std::is_nothrow_move_constructible_v>); // throwing move ctor +static_assert(not std::is_copy_assignable_v>); +static_assert(std::is_move_assignable_v>); +static_assert(not std::is_nothrow_move_assignable_v>); // throwing move assign + +// Non-copyable AND non-movable: can only be constructed in place (from a value) +// and observed; V < 8 makes the value constructor throw on a zero result. +template struct helper_immovable_t { + int v = {}; + + helper_immovable_t() = delete; + constexpr ~helper_immovable_t() noexcept {}; + + helper_immovable_t(helper_immovable_t const &) = delete; + helper_immovable_t(helper_immovable_t &&) = delete; + helper_immovable_t &operator=(helper_immovable_t const &) = delete; + helper_immovable_t &operator=(helper_immovable_t &&) = delete; + + helper_immovable_t(std::integral auto... a) noexcept(V >= 8) + requires(sizeof...(a) > 0) // intentionally implicit when sizeof...(a) == 1 + : v((1 * ... * a)) + { + if constexpr (V < 8) { + if (v == 0) + throw std::runtime_error("invalid input"); + } + } + + constexpr bool operator==(helper_immovable_t const &) const noexcept = default; +}; + +static_assert(not std::is_copy_constructible_v>); +static_assert(not std::is_move_constructible_v>); +static_assert(not std::is_copy_assignable_v>); +static_assert(not std::is_move_assignable_v>); + +using helper_move_only = helper_move_only_t<0>; +using helper_immovable = helper_immovable_t<0>;