Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 39 additions & 27 deletions include/beman/execution/detail/continues_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import std;
import beman.execution.detail.as_tuple;
import beman.execution.detail.basic_sender;
import beman.execution.detail.child_type;
import beman.execution.detail.completion_signature;
import beman.execution.detail.completion_signatures;
import beman.execution.detail.completion_signatures_for;
import beman.execution.detail.completion_signatures_of_t;
Expand All @@ -29,6 +30,7 @@ import beman.execution.detail.env;
import beman.execution.detail.env_of_t;
import beman.execution.detail.error_types_of_t;
import beman.execution.detail.fwd_env;
import beman.execution.detail.gather_signatures;
import beman.execution.detail.get_completion_domain;
import beman.execution.detail.get_completion_scheduler;
import beman.execution.detail.get_completion_signatures;
Expand All @@ -37,6 +39,7 @@ import beman.execution.detail.impls_for;
import beman.execution.detail.join_env;
import beman.execution.detail.make_sender;
import beman.execution.detail.meta.combine;
import beman.execution.detail.meta.filter;
import beman.execution.detail.meta.prepend;
import beman.execution.detail.meta.to;
import beman.execution.detail.meta.transform;
Expand All @@ -48,9 +51,7 @@ import beman.execution.detail.schedule_result_t;
import beman.execution.detail.scheduler;
import beman.execution.detail.sender;
import beman.execution.detail.sender_adaptor_closure;
import beman.execution.detail.sender_for;
import beman.execution.detail.sender_in;
import beman.execution.detail.sends_stopped;
import beman.execution.detail.set_error;
import beman.execution.detail.set_stopped;
import beman.execution.detail.set_value;
Expand All @@ -66,13 +67,15 @@ import beman.execution.detail.start;
#include <beman/execution/detail/env_of_t.hpp>
#include <beman/execution/detail/error_types_of_t.hpp>
#include <beman/execution/detail/fwd_env.hpp>
#include <beman/execution/detail/gather_signatures.hpp>
#include <beman/execution/detail/get_completion_domain.hpp>
#include <beman/execution/detail/get_completion_scheduler.hpp>
#include <beman/execution/detail/get_env.hpp>
#include <beman/execution/detail/impls_for.hpp>
#include <beman/execution/detail/join_env.hpp>
#include <beman/execution/detail/make_sender.hpp>
#include <beman/execution/detail/meta_combine.hpp>
#include <beman/execution/detail/meta_filter.hpp>
#include <beman/execution/detail/meta_prepend.hpp>
#include <beman/execution/detail/meta_to.hpp>
#include <beman/execution/detail/meta_transform.hpp>
Expand All @@ -83,9 +86,7 @@ import beman.execution.detail.start;
#include <beman/execution/detail/scheduler.hpp>
#include <beman/execution/detail/sender.hpp>
#include <beman/execution/detail/sender_adaptor.hpp>
#include <beman/execution/detail/sender_for.hpp>
#include <beman/execution/detail/sender_in.hpp>
#include <beman/execution/detail/sends_stopped.hpp>
#include <beman/execution/detail/set_error.hpp>
#include <beman/execution/detail/set_stopped.hpp>
#include <beman/execution/detail/set_value.hpp>
Expand Down Expand Up @@ -113,6 +114,20 @@ struct continues_on_t {
}

private:
template <typename Child, typename Env>
using variant_type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend<
::std::monostate,
::beman::execution::detail::meta::transform<
::beman::execution::detail::as_tuple_t,
::beman::execution::detail::meta::to<::std::variant,
::beman::execution::completion_signatures_of_t<Child, Env>>>>>;

template <typename... E>
using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>;

template <typename Tag>
using is_not_set_value = ::std::negation<::beman::execution::detail::is_set_value<Tag>>;

template <typename, typename...>
struct get_signatures;
template <typename Sender>
Expand All @@ -121,18 +136,21 @@ struct continues_on_t {
struct get_signatures<
::beman::execution::detail::basic_sender<::beman::execution::detail::continues_on_t, Scheduler, Sender>,
Env> {
using scheduler_sender = ::beman::execution::schedule_result_t<Scheduler>;
using additional_signatures = ::std::conditional_t<
::beman::execution::sends_stopped<scheduler_sender, Env>,
::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr),
::beman::execution::set_stopped_t()>,
using exception_signature = ::std::conditional_t<
::std::is_nothrow_move_constructible_v<variant_type<Sender, Env>>,
::beman::execution::completion_signatures<>,
::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>;
template <typename... E>
using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>;
using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine<
decltype(::beman::execution::get_completion_signatures<Sender, Env>()),
::beman::execution::error_types_of_t<scheduler_sender, Env, as_set_error>,
additional_signatures>>;

static consteval auto get() {
[[maybe_unused]] auto child_sigs = ::beman::execution::get_completion_signatures<Sender, Env>();
[[maybe_unused]] auto sched_sigs =
::beman::execution::get_completion_signatures<::beman::execution::schedule_result_t<Scheduler>, Env>();
using child_sigs_t = decltype(child_sigs);
using extra_sigs_t = ::beman::execution::detail::meta::filter<is_not_set_value, decltype(sched_sigs)>;
using type = ::beman::execution::detail::meta::unique<
::beman::execution::detail::meta::combine<child_sigs_t, exception_signature, extra_sigs_t>>;
return type{};
}
};

template <typename Scheduler, typename ChildAttrs>
Expand Down Expand Up @@ -170,8 +188,8 @@ struct continues_on_t {

public:
template <typename Sender, typename... Env>
static consteval auto get_completion_signatures() noexcept {
return typename get_signatures<::std::remove_cvref_t<Sender>, Env...>::type{};
static consteval auto get_completion_signatures() {
return get_signatures<::std::remove_cvref_t<Sender>, Env...>::get();
}

struct impls_for : ::beman::execution::detail::default_impls {
Expand All @@ -190,7 +208,7 @@ struct continues_on_t {
State* state;

auto set_value() && noexcept -> void {
constexpr bool nothrow = std::is_nothrow_move_constructible_v<decltype(state->async_result)>;
constexpr bool nothrow = ::std::is_nothrow_move_constructible_v<decltype(state->async_result)>;
try {
::std::visit(
[this]<typename Tuple>(Tuple& result) noexcept -> void {
Expand Down Expand Up @@ -252,14 +270,8 @@ struct continues_on_t {
auto sch{sender.template get<1>()};

using sched_t = ::std::remove_cvref_t<decltype(sch)>;
using variant_t = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend<
::std::monostate,
::beman::execution::detail::meta::transform<
::beman::execution::detail::as_tuple_t,
::beman::execution::detail::meta::to<::std::variant,
::beman::execution::completion_signatures_of_t<
::beman::execution::detail::child_type<Sender>,
::beman::execution::env_of_t<Receiver>>>>>>;
using variant_t = variant_type<::beman::execution::detail::child_type<Sender>,
::beman::execution::env_of_t<Receiver>>;

return state_type<Receiver, sched_t, variant_t>(sch, receiver);
};
Expand All @@ -270,7 +282,7 @@ struct continues_on_t {
template <typename Tag, typename... Args>
auto operator()(auto, auto& state, auto& receiver, Tag, Args&&... args) const noexcept -> void {
using result_t = ::beman::execution::detail::decayed_tuple<Tag, Args...>;
constexpr bool nothrow = ::std::is_nothrow_constructible_v<result_t, Tag, Args...>;
constexpr bool nothrow = ::std::is_nothrow_move_constructible_v<decltype(state.async_result)>;

try {
[&]() noexcept(nothrow) {
Expand Down
85 changes: 46 additions & 39 deletions include/beman/execution/detail/let.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,48 +170,50 @@ struct let_t {
using let_env_t = decltype(let_env(::std::declval<Sndr>(), ::std::declval<Env>()));

private:
template <typename, typename>
struct apply_decayed;
template <typename Fun, typename... Args>
struct apply_decayed<Fun, Completion(Args...)> {
static_assert(::std::invocable<Fun, ::std::decay_t<Args>&...>,
"The callback function object of the `let` adapter shall be invocable with `Args&...`");
using sender_type = ::beman::execution::detail::call_result_t<Fun, ::std::decay_t<Args>&...>;
static_assert(::beman::execution::sender<sender_type>, "`Fun` shall return a sender");
using completions = ::std::conditional_t<
noexcept(::std::declval<Fun>()(::std::declval<::std::decay_t<Args>&>()...)),
::beman::execution::completion_signatures<>,
::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>;
};

template <typename T>
using other_completion = let_other_completion<Completion, T>;

template <typename T>
using matching_completion = let_matching_completion<Completion, T>;

template <typename, typename...>
struct get_signatures;

template <typename Comp, typename Fun, typename Child>
template <typename Fun, typename Child>
requires ::beman::execution::detail::non_dependent_successor<Completion, Child, Fun>::value
struct get_signatures<
::beman::execution::detail::basic_sender<::beman::execution::detail::let_t<Comp>, Fun, Child>>
: get_signatures<::beman::execution::detail::basic_sender<::beman::execution::detail::let_t<Comp>, Fun, Child>,
::beman::execution::env<>> {};
struct get_signatures<::beman::execution::detail::basic_sender<let_t, Fun, Child>>
: get_signatures<::beman::execution::detail::basic_sender<let_t, Fun, Child>, ::beman::execution::env<>> {};

template <typename Comp, typename Fun, typename Child, typename Env>
template <typename Fun, typename Child, typename Env>
struct get_signatures<
::beman::execution::detail::basic_sender<::beman::execution::detail::let_t<Comp>, Fun, Child>,
::beman::execution::detail::basic_sender<::beman::execution::detail::let_t<Completion>, Fun, Child>,
Env> {
template <typename T>
using other_completion = let_other_completion<Comp, T>;
template <typename T>
using matching_completion = let_matching_completion<Comp, T>;

template <typename>
struct apply_decayed;
template <typename C, typename... A>
struct apply_decayed<C(A...)> {
using sender_type = ::beman::execution::detail::call_result_t<Fun, ::std::decay_t<A>...>;
using completions = ::std::conditional_t<
noexcept(::std::declval<Fun>()(::std::declval<::std::decay_t<A>>()...)),
::beman::execution::completion_signatures<>,
::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>;
};

using successor_env =
::beman::execution::detail::join_env<let_env_t<Child, Env>, ::beman::execution::detail::fwd_env<Env>>;

template <typename>
struct get_completions;
template <template <typename...> class L, typename... C>
struct get_completions<L<C...>> {
template <typename... Sigs>
struct get_completions<::beman::execution::completion_signatures<Sigs...>> {
using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine<
::beman::execution::completion_signatures<>,
::beman::execution::completion_signatures_of_t<typename apply_decayed<C>::sender_type,
::beman::execution::completion_signatures_of_t<typename apply_decayed<Fun, Sigs>::sender_type,
successor_env>...,
typename apply_decayed<C>::completions...>>;
typename apply_decayed<Fun, Sigs>::completions...>>;
};

using upstream_completions = ::beman::execution::completion_signatures_of_t<Child, Env>;
Expand Down Expand Up @@ -271,7 +273,7 @@ struct let_t {
struct to_state {
template <typename Tuple>
using trans =
decltype(::beman::execution::connect(::std::apply(::std::declval<Fun>(), ::std::declval<Tuple>()),
decltype(::beman::execution::connect(::std::apply(::std::declval<Fun>(), ::std::declval<Tuple&>()),
::std::declval<let_receiver<Receiver, Env>>()));
};

Expand Down Expand Up @@ -308,28 +310,33 @@ struct let_t {
{},
{}};
}};

template <typename Receiver, typename Env, typename Fun, typename... Args>
static constexpr bool nothrow =
::std::is_nothrow_constructible_v<::beman::execution::detail::decayed_tuple<Args...>, Args...> &&
noexcept(::beman::execution::connect(
::std::invoke(::std::move(::std::declval<Fun>()), ::std::declval<::std::decay_t<Args>&>()...),
::std::declval<let_receiver<Receiver, Env>>()));

template <typename Receiver, typename... Args>
static auto let_bind(auto& state, Receiver& receiver, Args&&... args) noexcept(
noexcept(::beman::execution::connect(::std::invoke(::std::move(state.fun), ::std::forward<Args>(args)...),
let_receiver<Receiver, decltype(state.env)>{receiver, state.env}))) {
static auto let_bind(auto& state, Receiver& receiver, Args&&... args) {
using args_t = ::beman::execution::detail::decayed_tuple<Args...>;
auto mkop{[&] {
return ::beman::execution::connect(
::std::apply(::std::move(state.fun),
::std::move(state.args.template emplace<args_t>(::std::forward<Args>(args)...))),
let_receiver<Receiver, decltype(state.env)>{receiver, state.env});
auto& tpl = state.args.template emplace<args_t>(::std::forward<Args>(args)...);
return ::beman::execution::connect(::std::apply(::std::move(state.fun), tpl),
let_receiver<Receiver, decltype(state.env)>{receiver, state.env});
}};
::beman::execution::start(
state.ops2.template emplace<decltype(mkop())>(beman::execution::detail::emplace_from{mkop}));
}
struct complete_impl {
template <class Tag, class... Args>
auto operator()(auto, auto& state, auto& receiver, Tag, Args&&... args) const {
template <typename Tag, typename Receiver, typename... Args>
auto operator()(auto, auto& state, Receiver& receiver, Tag, Args&&... args) const {
if constexpr (::std::same_as<Tag, Completion>) {
try {
let_bind(state, receiver, ::std::forward<Args>(args)...);
(let_bind)(state, receiver, ::std::forward<Args>(args)...);
} catch (...) {
if constexpr (not noexcept(let_bind(state, receiver, ::std::forward<Args>(args)...))) {
if constexpr (not nothrow<Receiver, decltype(state.env), decltype(state.fun), Args...>) {
::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/beman/execution/completion_signature.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ export module beman.execution.detail.completion_signature;

namespace beman::execution::detail {
export using beman::execution::detail::completion_signature;
export using beman::execution::detail::is_set_value;
export using beman::execution::detail::is_set_error;
export using beman::execution::detail::is_set_stopped;
} // namespace beman::execution::detail
6 changes: 3 additions & 3 deletions tests/beman/execution/issue-186.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ TEST(issue186) {
assert(ret == 6);

// NOTE: Compile time error with move_only_type
auto snd2 = ex::just(move_only_type(1)) //
| ex::then([](move_only_type v) noexcept { return move_only_type{v.val * 2}; }) //
| ex::let_value([](move_only_type v) noexcept { return ex::just(v.val * 3); }); // move_only_type
auto snd2 = ex::just(move_only_type(1)) //
| ex::then([](move_only_type v) noexcept { return move_only_type{v.val * 2}; }) //
| ex::let_value([](move_only_type& v) noexcept { return ex::just(v.val * 3); }); // move_only_type
auto [ret2] = ex::sync_wait(std::move(snd2)).value();
assert(ret2 == 6);
}
Loading