Skip to content
Merged
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
2 changes: 0 additions & 2 deletions examples/intro_1_hello_world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ using namespace std::string_literals;

int main() {
// clang-format off
#if !defined(__GNUC__) || defined(__clang__) || (__GNUC__ > 15) || !defined(BEMAN_HAS_MODULES)
auto [result] =
ex::sync_wait(
ex::when_all(
Expand All @@ -34,7 +33,6 @@ int main() {
) | ex::then([](auto const& s1, auto const& s2) { return s1 + s2; })
).value_or(std::tuple(""s))
;
#endif
// clang-format on

// std::cout << std::get<0>(v) << '\n';
Expand Down
2 changes: 0 additions & 2 deletions examples/intro_2_hello_async.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ using namespace std::chrono_literals;

int main() {
std::cout << std::unitbuf;
#if !defined(__GNUC__) || defined(__clang__) || (__GNUC__ > 15) || !defined(BEMAN_HAS_MODULES)
intro::timer timer;

// clang-format off
Expand All @@ -48,5 +47,4 @@ int main() {
// clang-format on

std::cout << result << "\n";
#endif
}
2 changes: 0 additions & 2 deletions examples/playground.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ namespace ex = ::beman::execution;
// ----------------------------------------------------------------------------

int main() {
#if !defined(__GNUC__) || defined(__clang__) || (__GNUC__ > 15) || !defined(BEMAN_HAS_MODULES)
auto [result] = ex::sync_wait(ex::when_all(ex::just(std::string("hello, ")), ex::just(std::string("world"))) |
ex::then([](const auto& s1, const auto& s2) { return s1 + s2; }))
.value_or(std::tuple(std::string("oops")));
std::cout << "result='" << result << "'\n";
#endif
}
2 changes: 0 additions & 2 deletions examples/sender_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,12 @@ int main() {
ex::write_env(std::move(w), ex::detail::make_env(ex::get_allocator, std::pmr::polymorphic_allocator<>()));

std::cout << "before start\n";
#if !defined(__GNUC__) || defined(__clang__) || (__GNUC__ > 15) || !defined(BEMAN_HAS_MODULES)
auto r = ex::sync_wait(std::move(e));
if (r) {
auto [v] = *r;
std::cout << "produced='" << v << "'\n";
} else
std::cout << "operation was cancelled\n";
#endif
std::cout << "after start\n";
} catch (const std::exception& ex) {
std::cout << "ERROR: " << ex.what() << "\n";
Expand Down
2 changes: 0 additions & 2 deletions examples/when_all_cancel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ eager(Sender&&) -> eager<std::remove_cvref_t<Sender>>;
} // namespace

auto main() -> int {
#if !defined(__GNUC__) || defined(__clang__) || (__GNUC__ > 15) || !defined(BEMAN_HAS_MODULES)
auto s{eager{ex::when_all(await_stop{})}};

ex::inplace_stop_source source{};
Expand All @@ -160,5 +159,4 @@ auto main() -> int {
std::cout << "started\n";
source.request_stop();
std::cout << "done\n";
#endif
}
13 changes: 10 additions & 3 deletions include/beman/execution/detail/continues_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ 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 Down Expand Up @@ -84,6 +85,7 @@ import beman.execution.detail.start;
#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 @@ -119,13 +121,18 @@ 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 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()>,
::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::combine<
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>,
::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>;
additional_signatures>>;
};

template <typename Scheduler, typename ChildAttrs>
Expand Down
223 changes: 181 additions & 42 deletions include/beman/execution/detail/on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,21 @@
#ifdef BEMAN_HAS_IMPORT_STD
import std;
#else
#include <type_traits>
#include <utility>
#endif
#ifdef BEMAN_HAS_MODULES
import beman.execution.detail.basic_sender;
import beman.execution.detail.call_with_default;
import beman.execution.detail.completion_signatures_of_t;
import beman.execution.detail.continues_on;
import beman.execution.detail.default_impls;
import beman.execution.detail.default_domain;
import beman.execution.detail.env_of_t;
import beman.execution.detail.forward_like;
import beman.execution.detail.fwd_env;
import beman.execution.detail.get_completion_domain;
import beman.execution.detail.get_completion_signatures;
import beman.execution.detail.get_completion_scheduler;
import beman.execution.detail.get_domain;
import beman.execution.detail.get_env;
Expand All @@ -38,10 +43,16 @@ import beman.execution.detail.transform_sender;
#include <beman/execution/detail/basic_sender.hpp>
#include <beman/execution/detail/call_with_default.hpp>
#include <beman/execution/detail/continues_on.hpp>
#include <beman/execution/detail/default_impls.hpp>
#include <beman/execution/detail/default_domain.hpp>
#include <beman/execution/detail/env_of_t.hpp>
#include <beman/execution/detail/forward_like.hpp>
#include <beman/execution/detail/fwd_env.hpp>
#include <beman/execution/detail/get_completion_domain.hpp>
#include <beman/execution/detail/get_completion_signatures.hpp>
#include <beman/execution/detail/get_completion_scheduler.hpp>
#include <beman/execution/detail/get_domain.hpp>
#include <beman/execution/detail/get_env.hpp>
#include <beman/execution/detail/get_start_scheduler.hpp>
#include <beman/execution/detail/join_env.hpp>
#include <beman/execution/detail/make_sender.hpp>
Expand All @@ -60,52 +71,63 @@ import beman.execution.detail.transform_sender;

namespace beman::execution::detail {
struct on_t : ::beman::execution::sender_adaptor_closure<on_t> {
template <typename>
struct env_needs_get_start_scheduler {
using sender_concept = ::beman::execution::sender_tag;
template <typename, typename Env>
static constexpr auto get_completion_signatures() {
return env_needs_get_start_scheduler<Env>{};
template <typename Env, typename OutSndr>
static auto dry_run(OutSndr&& out_sndr) noexcept {
auto& [_, data, child] = out_sndr;
if constexpr (::beman::execution::scheduler<decltype(data)>) {
return ::std::bool_constant<::std::invocable<::beman::execution::get_start_scheduler_t, Env>>{};
} else {
::std::bool_constant<
::std::invocable<::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>,
::beman::execution::env_of_t<decltype(child)>,
Env>>{};
}
};
}

template <::beman::execution::detail::sender_for<on_t> OutSndr, typename Env>
auto transform_sender(::beman::execution::set_value_t, OutSndr&& out_sndr, const Env& env) const
requires(decltype(on_t::dry_run<Env>(::std::declval<OutSndr>()))::value)
static auto transform_sender(::beman::execution::set_value_t, OutSndr&& out_sndr, const Env& env)
-> decltype(auto) {
struct not_a_scheduler_t {};
auto&& data = out_sndr.template get<1>();
auto&& child = out_sndr.template get<2>();

if constexpr (::beman::execution::scheduler<decltype(data)>) {
auto sch{::beman::execution::detail::query_with_default(
::beman::execution::get_start_scheduler, env, not_a_scheduler_t{})};
if constexpr (::std::same_as<not_a_scheduler_t, decltype(sch)>) {
return env_needs_get_start_scheduler<Env>{};
} else {
return ::beman::execution::continues_on(
::beman::execution::starts_on(::beman::execution::detail::forward_like<OutSndr>(data),
::beman::execution::detail::forward_like<OutSndr>(child)),
::std::move(sch));
}
auto start_sch = ::beman::execution::get_start_scheduler(env);
return ::beman::execution::continues_on(
::beman::execution::starts_on(::beman::execution::detail::forward_like<OutSndr>(data),
::beman::execution::detail::forward_like<OutSndr>(child)),
::std::move(start_sch));
} else {
auto& [sch, closure] = data;
auto orig_sch{::beman::execution::detail::call_with_default(
::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>,
not_a_scheduler_t{},
::beman::execution::get_env(child),
env)};

if constexpr (::std::same_as<not_a_scheduler_t, decltype(orig_sch)>) {
return env_needs_get_start_scheduler<Env>{};
} else {
return ::beman::execution::continues_on(
::beman::execution::detail::forward_like<OutSndr>(closure)(::beman::execution::continues_on(
::beman::execution::detail::forward_like<OutSndr>(child), sch)),
orig_sch);
}
auto orig_sch = ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>(
::beman::execution::get_env(child), env);

return ::beman::execution::continues_on(
::beman::execution::detail::forward_like<OutSndr>(closure)(
::beman::execution::continues_on(::beman::execution::detail::forward_like<OutSndr>(child), sch)),
orig_sch);
}
}

struct impls_for : ::beman::execution::detail::default_impls {
struct get_attrs_impl {
template <typename Sched, typename Child>
auto operator()(const Sched&, const Child& child) const noexcept {
using ChildAttrs = ::std::remove_cvref_t<::beman::execution::env_of_t<Child>>;
return attrs1<ChildAttrs>{::beman::execution::get_env(child)};
}

template <typename Sched, typename Closure, typename Child>
auto operator()(const ::beman::execution::detail::product_type<Sched, Closure>&,
const Child& child) const noexcept {
using ChildAttrs = ::std::remove_cvref_t<::beman::execution::env_of_t<Child>>;
return attrs2<ChildAttrs>{::beman::execution::get_env(child)};
}
};

static constexpr auto get_attrs{get_attrs_impl{}};
};

template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr>
requires ::beman::execution::detail::is_sender_adaptor_closure<Sndr>
auto operator()(Sch&&, Sndr&&) const -> void =
Expand All @@ -115,8 +137,8 @@ struct on_t : ::beman::execution::sender_adaptor_closure<on_t> {
::beman::execution::sender Sndr,
::beman::execution::detail::is_sender_adaptor_closure Closure>
requires ::beman::execution::detail::is_sender_adaptor_closure<Sndr>
auto operator()(Sndr&&, Sch&&, Closure&&) const -> void =
BEMAN_EXECUTION_DELETE("on(sch, sndr) requires that sndr isn't both a sender and sender adaptor closure");
auto operator()(Sndr&&, Sch&&, Closure&&) const -> void = BEMAN_EXECUTION_DELETE(
"on(sndr, sch, closure) requires that sndr isn't both a sender and sender adaptor closure");

template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr>
auto operator()(Sch&& sch, Sndr&& sndr) const {
Expand All @@ -136,17 +158,134 @@ struct on_t : ::beman::execution::sender_adaptor_closure<on_t> {
return ::beman::execution::detail::make_sender_adaptor(
*this, ::std::forward<Sch>(sch), ::std::forward<Closure>(closure));
}

private:
template <typename>
struct is_completion_query : ::std::false_type {};

template <typename Tag>
struct is_completion_query<::beman::execution::get_completion_scheduler_t<Tag>> : ::std::true_type {};

template <typename Tag>
struct is_completion_query<::beman::execution::get_completion_domain_t<Tag>> : ::std::true_type {};

template <typename ChildAttrs>
struct attrs_base {
template <typename Query, typename... Args>
requires(!is_completion_query<::std::remove_cvref_t<Query>>::value) &&
requires(const ChildAttrs& child_attrs, Query query, Args&&... args) {
query(::beman::execution::detail::fwd_env(child_attrs), ::std::forward<Args>(args)...);
}
auto query(Query query, Args&&... args) const noexcept {
return query(::beman::execution::detail::fwd_env(this->child_attrs), ::std::forward<Args>(args)...);
}

ChildAttrs child_attrs;
};

template <typename ChildAttrs>
struct attrs1 : attrs_base<ChildAttrs> {
using attrs_base<ChildAttrs>::query;

template <typename Tag, typename Env>
requires requires(const Env& env) {
::beman::execution::get_completion_scheduler<Tag>(::beman::execution::get_start_scheduler(env),
::beman::execution::detail::fwd_env(env));
}
auto query(::beman::execution::get_completion_scheduler_t<Tag>, const Env& env) const noexcept {
auto sched = ::beman::execution::get_start_scheduler(env);
return ::beman::execution::get_completion_scheduler<Tag>(sched, ::beman::execution::detail::fwd_env(env));
}

template <typename Tag, typename Env>
requires requires(const Env& env) {
::beman::execution::get_completion_domain<Tag>(::beman::execution::get_start_scheduler(env),
::beman::execution::detail::fwd_env(env));
}
auto query(::beman::execution::get_completion_domain_t<Tag>, const Env& env) const noexcept {
auto sched = ::beman::execution::get_start_scheduler(env);
return ::beman::execution::get_completion_domain<Tag>(sched, ::beman::execution::detail::fwd_env(env));
}
};

template <typename ChildAttrs>
struct attrs2 : attrs_base<ChildAttrs> {
using attrs_base<ChildAttrs>::query;

template <typename Env>
auto original_sched(const Env& env) const noexcept {
return ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>(this->child_attrs,
env);
}

template <typename Tag, typename Env>
requires requires(const attrs2& self, const Env& env) {
::beman::execution::get_completion_scheduler<Tag>(self.original_sched(env),
::beman::execution::detail::fwd_env(env));
}
auto query(::beman::execution::get_completion_scheduler_t<Tag>, const Env& env) const noexcept {
return ::beman::execution::get_completion_scheduler<Tag>(this->original_sched(env),
::beman::execution::detail::fwd_env(env));
}

template <typename Tag, typename Env>
requires requires(const attrs2& self, const Env& env) {
::beman::execution::get_completion_domain<Tag>(self.original_sched(env),
::beman::execution::detail::fwd_env(env));
}
auto query(::beman::execution::get_completion_domain_t<Tag>, const Env& env) const noexcept {
return ::beman::execution::get_completion_domain<Tag>(this->original_sched(env),
::beman::execution::detail::fwd_env(env));
}
};

template <typename, typename...>
struct get_signatures;
template <typename Data, ::beman::execution::sender Sndr, typename... Env>
struct get_signatures<::beman::execution::detail::basic_sender<::beman::execution::detail::on_t, Data, Sndr>,
Env...> {
using type = ::beman::execution::completion_signatures_of_t<Sndr, Env...>;

/// for `on(scheduler, sender)`
template <typename Sched, typename Child, typename Env>
struct get_signatures<::beman::execution::detail::basic_sender<::beman::execution::detail::on_t, Sched, Child>,
Env> {
static consteval auto get()
requires ::std::invocable<::beman::execution::get_start_scheduler_t, Env>
{
using transformed_sndr = decltype(on_t::transform_sender(
::beman::execution::set_value,
::std::declval<
::beman::execution::detail::basic_sender<::beman::execution::detail::on_t, Sched, Child>>(),
::std::declval<Env>()));
return ::beman::execution::get_completion_signatures<transformed_sndr, Env>();
}
};

/// for `on(sender, scheduler, closure)`
template <typename Sched, typename Closure, typename Child, typename Env>
struct get_signatures<
::beman::execution::detail::basic_sender<::beman::execution::detail::on_t,
::beman::execution::detail::product_type<Sched, Closure>,
Child>,
Env> {
static consteval auto get()
requires ::std::invocable<::beman::execution::get_completion_scheduler_t<::beman::execution::set_value_t>,
::beman::execution::env_of_t<Child>,
Env>
{
using transformed_sndr = decltype(on_t::transform_sender(
::beman::execution::set_value,
::std::declval<
::beman::execution::detail::basic_sender<::beman::execution::detail::on_t,
::beman::execution::detail::product_type<Sched, Closure>,
Child>>(),
::std::declval<Env>()));
return ::beman::execution::get_completion_signatures<transformed_sndr, Env>();
}
};

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

Expand Down
Loading
Loading