diff --git a/include/beman/execution26/detail/then.hpp b/include/beman/execution26/detail/then.hpp index 623b89f6..4d29d5e2 100644 --- a/include/beman/execution26/detail/then.hpp +++ b/include/beman/execution26/detail/then.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -93,10 +94,17 @@ namespace beman::execution26::detail } catch (...) { - ::beman::execution26::set_error( - ::std::move(receiver), - ::std::current_exception() - ); + if constexpr (not noexcept( + ::std::invoke(::std::move(fun), + ::std::forward(args)...) + + )) + { + ::beman::execution26::set_error( + ::std::move(receiver), + ::std::current_exception() + ); + } } } else @@ -123,6 +131,16 @@ namespace beman::execution26::detail using type = Completion; }; + template + struct then_transform + { + using type = + typename ::beman::execution26::detail::then_set_value< + ::beman::execution26::detail::call_result_t + >::type + ; + }; + template struct then_transform_t { @@ -132,12 +150,23 @@ namespace beman::execution26::detail ::type; }; - template - struct then_transform + template + struct then_exception_fun: ::std::false_type {}; + template + struct then_exception_fun + : ::std::bool_constant()(::std::declval()...))> { - using type = typename ::beman::execution26::detail::then_set_value< - ::beman::execution26::detail::call_result_t - >::type; + }; + + template + struct then_exception: ::std::false_type {}; + template + struct then_exception> + { + static constexpr bool value{ + then_exception_fun::value + || then_exception>::value + }; }; template @@ -151,9 +180,20 @@ namespace beman::execution26::detail > { using type = ::beman::execution26::detail::meta::unique< - ::beman::execution26::detail::meta::transform< - ::beman::execution26::detail::then_transform_t::template transform, - ::beman::execution26::completion_signatures_of_t + ::beman::execution26::detail::meta::combine< + ::beman::execution26::detail::meta::transform< + ::beman::execution26::detail::then_transform_t::template transform, + ::beman::execution26::completion_signatures_of_t + >, + ::std::conditional_t< + ::beman::execution26::detail::then_exception< + Completion, + Fun, + ::beman::execution26::completion_signatures_of_t + >::value, + ::beman::execution26::completion_signatures<::beman::execution26::set_error_t(::std::exception_ptr)>, + ::beman::execution26::completion_signatures<> + > > >; }; diff --git a/src/beman/execution26/tests/exec-then.pass.cpp b/src/beman/execution26/tests/exec-then.pass.cpp index 849afd97..035f3fc5 100644 --- a/src/beman/execution26/tests/exec-then.pass.cpp +++ b/src/beman/execution26/tests/exec-then.pass.cpp @@ -68,19 +68,19 @@ namespace auto test_then_type() -> void { - test_then_type< test_std::set_value_t()>(test_std::just(0) | test_std::then([](auto){})); - test_then_type< test_std::set_value_t(int)>(test_std::just() | test_std::then([]{ return 0; })); - test_then_type< test_std::set_error_t(int)>(test_std::just_error(0) | test_std::then([]{ return 0; })); - test_then_type< test_std::set_stopped_t()>(test_std::just_stopped() | test_std::then([]{ return 0; })); + test_then_type< test_std::set_value_t()>(test_std::just(0) | test_std::then([](auto)noexcept{})); + test_then_type< test_std::set_value_t(int)>(test_std::just() | test_std::then([]()noexcept{ return 0; })); + test_then_type< test_std::set_error_t(int)>(test_std::just_error(0) | test_std::then([]()noexcept{ return 0; })); + test_then_type< test_std::set_stopped_t()>(test_std::just_stopped() | test_std::then([]()noexcept{ return 0; })); - test_then_type< test_std::set_value_t()>(test_std::just() | test_std::upon_error([]{ return 0; })); + test_then_type< test_std::set_value_t()>(test_std::just() | test_std::upon_error([]()noexcept{ return 0; })); test_then_type< test_std::set_value_t(int)>(test_std::just_error(error{}) - | test_std::upon_error([](error){ return 0; })); - test_then_type< test_std::set_stopped_t()>(test_std::just_stopped() | test_std::upon_error([]{})); + | test_std::upon_error([](error)noexcept{ return 0; })); + test_then_type< test_std::set_stopped_t()>(test_std::just_stopped() | test_std::upon_error([]()noexcept{})); - test_then_type< test_std::set_value_t(int)>(test_std::just(0) | test_std::upon_stopped([]{})); - test_then_type< test_std::set_error_t(int)>(test_std::just_error(0) | test_std::upon_stopped([]{})); - test_then_type< test_std::set_value_t()>(test_std::just_stopped() | test_std::upon_stopped([]{})); + test_then_type< test_std::set_value_t(int)>(test_std::just(0) | test_std::upon_stopped([]()noexcept{})); + test_then_type< test_std::set_error_t(int)>(test_std::just_error(0) | test_std::upon_stopped([]()noexcept{})); + test_then_type< test_std::set_value_t()>(test_std::just_stopped() | test_std::upon_stopped([]()noexcept{})); } auto test_then_multi_type() -> void @@ -102,7 +102,8 @@ namespace test_then_type< test_std::set_value_t(bool), test_std::set_error_t(error), - test_std::set_stopped_t() + test_std::set_stopped_t(), + test_std::set_error_t(::std::exception_ptr) >(sender< test_std::set_value_t(), test_std::set_value_t(int, int), @@ -113,7 +114,8 @@ namespace test_std::set_value_t(), test_std::set_value_t(int, int), test_std::set_value_t(bool), - test_std::set_stopped_t() + test_std::set_stopped_t(), + test_std::set_error_t(::std::exception_ptr) >(sender< test_std::set_value_t(), test_std::set_value_t(int, int), @@ -123,7 +125,8 @@ namespace test_then_type< test_std::set_value_t(), test_std::set_value_t(int, int), - test_std::set_stopped_t() + test_std::set_stopped_t(), + test_std::set_error_t(::std::exception_ptr) >(sender< test_std::set_value_t(), test_std::set_value_t(int, int), @@ -140,7 +143,7 @@ namespace test_std::set_value_t(int, int), test_std::set_error_t(error), test_std::set_stopped_t() - >() | test_std::upon_stopped([]{})); + >() | test_std::upon_stopped([]()noexcept{})); test_then_type< test_std::set_value_t(), test_std::set_value_t(int, int), @@ -150,6 +153,17 @@ namespace test_std::set_value_t(int, int), test_std::set_error_t(error), test_std::set_stopped_t() + >() | test_std::upon_stopped([]()noexcept{})); + test_then_type< + test_std::set_value_t(), + test_std::set_value_t(int, int), + test_std::set_error_t(error), + test_std::set_error_t(::std::exception_ptr) + >(sender< + test_std::set_value_t(), + test_std::set_value_t(int, int), + test_std::set_error_t(error), + test_std::set_stopped_t() >() | test_std::upon_stopped([]{})); }