Skip to content

Commit 82f2c42

Browse files
authored
Implement stopped_as_error and stopped_as_optional (#232)
* Implement `stopped_as_error` and `stopped_as_optional`
1 parent 67b3828 commit 82f2c42

14 files changed

Lines changed: 387 additions & 19 deletions

include/beman/execution/detail/get_awaiter.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ import std;
1414
// ----------------------------------------------------------------------------
1515

1616
namespace beman::execution::detail {
17-
template <typename Expr, typename Promise>
18-
auto get_awaiter(Expr&& expr, Promise& promise) -> decltype(auto) {
17+
template <typename Expr, typename... Promise>
18+
requires(sizeof...(Promise) <= 1)
19+
auto get_awaiter(Expr&& expr, Promise&... promise) -> decltype(auto) {
1920
auto transform{[&]() -> decltype(auto) {
20-
if constexpr (requires { promise.await_transform(::std::forward<Expr>(expr)); })
21-
return promise.await_transform(::std::forward<Expr>(expr));
21+
if constexpr (sizeof...(Promise) == 1 &&
22+
requires { (..., promise.await_transform(::std::forward<Expr>(expr))); })
23+
return (..., promise.await_transform(::std::forward<Expr>(expr)));
2224
else
2325
return ::std::forward<Expr>(expr);
2426
}};

include/beman/execution/detail/get_completion_signatures.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ consteval auto get_completion_signatures() -> ::beman::execution::detail::valid_
9393
})
9494
return get_complsigs.template operator()<new_sender_type>();
9595
else if constexpr (::beman::execution::detail::is_awaitable<new_sender_type,
96-
::beman::execution::detail::env_promise<Env...>>) {
96+
::beman::execution::detail::env_promise<Env>...>) {
9797
using result_type = ::beman::execution::detail::
9898
await_result_type<new_sender_type, ::beman::execution::detail::env_promise<::std::tuple<Env...>>>;
9999
if constexpr (::std::same_as<void, result_type>) {

include/beman/execution/detail/is_awaitable.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ import beman.execution.detail.is_awaiter;
2121
// ----------------------------------------------------------------------------
2222

2323
namespace beman::execution::detail {
24-
template <typename T, typename Promise>
25-
concept is_awaitable = requires(Promise& promise) {
24+
template <typename T, typename... Promise>
25+
concept is_awaitable = requires(Promise&... promise) {
2626
{
27-
::beman::execution::detail::get_awaiter(::std::declval<T>(), promise)
28-
} -> ::beman::execution::detail::is_awaiter<Promise>;
27+
::beman::execution::detail::get_awaiter(::std::declval<T>(), promise...)
28+
} -> ::beman::execution::detail::is_awaiter<Promise...>;
2929
};
3030
} // namespace beman::execution::detail
3131

include/beman/execution/detail/is_awaiter.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import beman.execution.detail.await_suspend_result;
1919
// ----------------------------------------------------------------------------
2020

2121
namespace beman::execution::detail {
22-
template <typename Awaiter, typename Promise>
23-
concept is_awaiter = requires(Awaiter& awaiter, ::std::coroutine_handle<Promise> handle) {
22+
template <typename Awaiter, typename... Promise>
23+
concept is_awaiter = requires(Awaiter& awaiter, ::std::coroutine_handle<Promise...> handle) {
2424
awaiter.await_ready() ? 1 : 0;
2525
{ awaiter.await_suspend(handle) } -> ::beman::execution::detail::await_suspend_result;
2626
awaiter.await_resume();

include/beman/execution/detail/let.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,18 @@ struct let_t {
174174
template <template <typename...> class L, typename... C>
175175
struct get_completions<L<C...>> {
176176
using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine<
177-
decltype(::beman::execution::get_completion_signatures<typename apply_decayed<C>::sender_type,
178-
Env...>())...>>;
177+
::beman::execution::completion_signatures<>,
178+
::beman::execution::completion_signatures_of_t<typename apply_decayed<C>::sender_type, Env...>...>>;
179179
};
180180

181181
using upstream_env = typename let_upstream_env_helper<Child, 0 < sizeof...(Env), Env...>::type;
182182
using upstream_completions = decltype(::beman::execution::get_completion_signatures<Child, upstream_env>());
183183
using other_completions = ::beman::execution::detail::meta::filter<other_completion, upstream_completions>;
184184
using matching_completions =
185185
::beman::execution::detail::meta::filter<matching_completion, upstream_completions>;
186-
using type = ::beman::execution::detail::meta::combine<typename get_completions<matching_completions>::type,
187-
other_completions>;
186+
using type = ::beman::execution::detail::meta::unique<
187+
::beman::execution::detail::meta::combine<typename get_completions<matching_completions>::type,
188+
other_completions>>;
188189
};
189190

190191
public:
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// include/beman/execution/detail/stopped_as_error.hpp -*-C++-*-
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_STOPPED_AS_ERROR
5+
#define INCLUDED_BEMAN_EXECUTION_DETAIL_STOPPED_AS_ERROR
6+
7+
// ----------------------------------------------------------------------------
8+
#include <beman/execution/detail/common.hpp>
9+
#ifdef BEMAN_HAS_IMPORT_STD
10+
import std;
11+
#else
12+
#include <type_traits>
13+
#include <utility>
14+
#endif
15+
#ifdef BEMAN_HAS_MODULES
16+
import beman.execution.detail.forward_like;
17+
import beman.execution.detail.get_domain_early;
18+
import beman.execution.detail.just;
19+
import beman.execution.detail.let;
20+
import beman.execution.detail.make_sender;
21+
import beman.execution.detail.movable_value;
22+
import beman.execution.detail.sender;
23+
import beman.execution.detail.sender_adaptor_closure;
24+
import beman.execution.detail.sender_for;
25+
import beman.execution.detail.transform_sender;
26+
#else
27+
#include <beman/execution/detail/forward_like.hpp>
28+
#include <beman/execution/detail/get_domain_early.hpp>
29+
#include <beman/execution/detail/just.hpp>
30+
#include <beman/execution/detail/let.hpp>
31+
#include <beman/execution/detail/make_sender.hpp>
32+
#include <beman/execution/detail/movable_value.hpp>
33+
#include <beman/execution/detail/sender.hpp>
34+
#include <beman/execution/detail/sender_adaptor_closure.hpp>
35+
#include <beman/execution/detail/sender_for.hpp>
36+
#include <beman/execution/detail/transform_sender.hpp>
37+
#endif
38+
39+
namespace beman::execution::detail {
40+
struct stopped_as_error_t : ::beman::execution::sender_adaptor_closure<stopped_as_error_t> {
41+
template <::beman::execution::detail::sender_for<stopped_as_error_t> Sndr, typename Env>
42+
auto transform_sender(Sndr&& sndr, Env&&) const noexcept {
43+
auto&& data = sndr.template get<1>();
44+
auto&& child = sndr.template get<2>();
45+
using Error = ::std::decay_t<decltype(data)>;
46+
return ::beman::execution::let_stopped(
47+
::beman::execution::detail::forward_like<Sndr>(child),
48+
[error = ::beman::execution::detail::forward_like<Sndr>(data)]() mutable noexcept(
49+
::std::is_nothrow_move_constructible_v<Error>) {
50+
return ::beman::execution::just_error(::std::move(error));
51+
});
52+
}
53+
54+
template <::beman::execution::sender Sndr, ::beman::execution::detail::movable_value Error>
55+
auto operator()(Sndr&& sndr, Error error) const {
56+
return ::beman::execution::transform_sender(
57+
::beman::execution::detail::get_domain_early(sndr),
58+
::beman::execution::detail::make_sender(
59+
stopped_as_error_t{}, std::move(error), ::std::forward<Sndr>(sndr)));
60+
}
61+
62+
template <::beman::execution::detail::movable_value Error>
63+
auto operator()(Error error) const {
64+
return ::beman::execution::detail::make_sender_adaptor(*this, ::std::move(error));
65+
}
66+
};
67+
68+
} // namespace beman::execution::detail
69+
70+
namespace beman::execution {
71+
using stopped_as_error_t = ::beman::execution::detail::stopped_as_error_t;
72+
inline constexpr stopped_as_error_t stopped_as_error{};
73+
} // namespace beman::execution
74+
75+
// ----------------------------------------------------------------------------
76+
77+
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_STOPPED_AS_ERROR
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// include/beman/execution/detail/stopped_as_optional.hpp -*-C++-*-
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_STOPPED_AS_OPTIONAL
5+
#define INCLUDED_BEMAN_EXECUTION_DETAIL_STOPPED_AS_OPTIONAL
6+
7+
// ----------------------------------------------------------------------------
8+
9+
#include <beman/execution/detail/common.hpp>
10+
#ifdef BEMAN_HAS_IMPORT_STD
11+
import std;
12+
#else
13+
#include <optional>
14+
#include <type_traits>
15+
#include <utility>
16+
#endif
17+
#ifdef BEMAN_HAS_MODULES
18+
import beman.execution.detail.child_type;
19+
import beman.execution.detail.fwd_env;
20+
import beman.execution.detail.get_domain_early;
21+
import beman.execution.detail.just;
22+
import beman.execution.detail.let;
23+
import beman.execution.detail.make_sender;
24+
import beman.execution.detail.sender;
25+
import beman.execution.detail.sender_adaptor_closure;
26+
import beman.execution.detail.sender_for;
27+
import beman.execution.detail.single_sender;
28+
import beman.execution.detail.single_sender_value_type;
29+
import beman.execution.detail.then;
30+
import beman.execution.detail.transform_sender;
31+
#else
32+
#include <beman/execution/detail/child_type.hpp>
33+
#include <beman/execution/detail/fwd_env.hpp>
34+
#include <beman/execution/detail/get_domain_early.hpp>
35+
#include <beman/execution/detail/just.hpp>
36+
#include <beman/execution/detail/let.hpp>
37+
#include <beman/execution/detail/make_sender.hpp>
38+
#include <beman/execution/detail/sender.hpp>
39+
#include <beman/execution/detail/sender_adaptor_closure.hpp>
40+
#include <beman/execution/detail/sender_for.hpp>
41+
#include <beman/execution/detail/single_sender.hpp>
42+
#include <beman/execution/detail/single_sender_value_type.hpp>
43+
#include <beman/execution/detail/then.hpp>
44+
#include <beman/execution/detail/transform_sender.hpp>
45+
#endif
46+
47+
namespace beman::execution::detail {
48+
struct stopped_as_optional_t : ::beman::execution::sender_adaptor_closure<stopped_as_optional_t> {
49+
template <::beman::execution::detail::sender_for<stopped_as_optional_t> Sndr, typename Env>
50+
auto transform_sender(Sndr&& sndr, Env&&) const noexcept {
51+
static_assert(
52+
::beman::execution::detail::single_sender<child_type<Sndr>, ::beman::execution::detail::fwd_env<Env>>,
53+
"sender must be a single sender");
54+
using value_type =
55+
::beman::execution::detail::single_sender_value_type<child_type<Sndr>,
56+
::beman::execution::detail::fwd_env<Env>>;
57+
static_assert(!::std::is_void_v<value_type>, "the value type of sender can't be empty");
58+
return ::beman::execution::let_stopped(
59+
::beman::execution::then(
60+
::std::forward<Sndr>(sndr).template get<2>(),
61+
[]<class... Args>(Args&&... args) noexcept(::std::is_nothrow_constructible_v<value_type, Args...>) {
62+
return ::std::optional<value_type>(::std::in_place, ::std::forward<Args>(args)...);
63+
}),
64+
[]() noexcept { return ::beman::execution::just(::std::optional<value_type>()); });
65+
}
66+
67+
template <::beman::execution::sender Sndr>
68+
auto operator()(Sndr&& sndr) const {
69+
return ::beman::execution::transform_sender(
70+
::beman::execution::detail::get_domain_early(sndr),
71+
::beman::execution::detail::make_sender(stopped_as_optional_t{}, {}, ::std::forward<Sndr>(sndr)));
72+
}
73+
74+
auto operator()() const noexcept { return ::beman::execution::detail::make_sender_adaptor(*this); }
75+
};
76+
77+
} // namespace beman::execution::detail
78+
79+
namespace beman::execution {
80+
using stopped_as_optional_t = ::beman::execution::detail::stopped_as_optional_t;
81+
inline constexpr stopped_as_optional_t stopped_as_optional{};
82+
} // namespace beman::execution
83+
84+
// ----------------------------------------------------------------------------
85+
86+
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_STOPPED_AS_OPTIONAL

src/beman/execution/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ target_sources(
174174
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stop_when.hpp
175175
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stoppable_source.hpp
176176
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stoppable_token.hpp
177+
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stopped_as_error.hpp
178+
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/stopped_as_optional.hpp
177179
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/suppress_pop.hpp
178180
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/suppress_push.hpp
179181
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/suspend_complete.hpp
@@ -359,6 +361,8 @@ if(BEMAN_USE_MODULES)
359361
stop_when.cppm
360362
stoppable_source.cppm
361363
stoppable_token.cppm
364+
stopped_as_error.cppm
365+
stopped_as_optional.cppm
362366
suspend_complete.cppm
363367
sync_wait.cppm
364368
tag_of_t.cppm

src/beman/execution/execution.cppm

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export import beman.execution.detail.env_of_t;
2525
export import beman.execution.detail.error_types_of_t; // [exec.getcomplsigs], completion signatures
2626
import beman.execution.detail.forwarding_query;
2727
import beman.execution.detail.get_allocator;
28+
import beman.execution.detail.get_await_completion_adaptor;
2829
export import beman.execution.detail.get_completion_scheduler;
2930
export import beman.execution.detail.get_completion_signatures; // [exec.getcomplsigs], completion signatures
3031
import beman.execution.detail.get_delegation_scheduler;
@@ -64,6 +65,8 @@ export import beman.execution.detail.stop_callback_for_t;
6465
export import beman.execution.detail.stop_source; // [stopsource], class stop_source
6566
import beman.execution.detail.stop_token_of_t;
6667
import beman.execution.detail.stoppable_source;
68+
import beman.execution.detail.stopped_as_error;
69+
import beman.execution.detail.stopped_as_optional;
6770
import beman.execution.detail.sync_wait;
6871
export import beman.execution.detail.tag_of_t; // [exec.getcomplsigs], completion signatures
6972
import beman.execution.detail.then;
@@ -128,11 +131,13 @@ export using ::beman::execution::stop_token_of_t;
128131
export using ::beman::execution::get_domain_t;
129132
export using ::beman::execution::get_scheduler_t;
130133
export using ::beman::execution::get_delegation_scheduler_t;
134+
export using ::beman::execution::get_await_completion_adaptor_t;
131135
//-dk:TODO export using ::beman::execution::get_forward_progress_guarantee_t;
132136

133137
export using ::beman::execution::get_domain;
134138
export using ::beman::execution::get_scheduler;
135139
export using ::beman::execution::get_delegation_scheduler;
140+
export using ::beman::execution::get_await_completion_adaptor;
136141
//-dk:TODO export using ::beman::execution::forward_progress_guarantee;
137142
//-dk:TODO export using ::beman::execution::get_forward_progress_guarantee;
138143

@@ -195,8 +200,8 @@ export using ::beman::execution::bulk_t;
195200
export using ::beman::execution::when_all_t;
196201
export using ::beman::execution::when_all_with_variant_t;
197202
export using ::beman::execution::into_variant_t;
198-
//-dk:TODO export using ::beman::execution::stopped_as_optional_t;
199-
//-dk:TODO export using ::beman::execution::stopped_as_error_t;
203+
export using ::beman::execution::stopped_as_optional_t;
204+
export using ::beman::execution::stopped_as_error_t;
200205

201206
export using ::beman::execution::starts_on;
202207
export using ::beman::execution::continues_on;
@@ -213,8 +218,8 @@ export using ::beman::execution::bulk;
213218
export using ::beman::execution::when_all;
214219
export using ::beman::execution::when_all_with_variant;
215220
export using ::beman::execution::into_variant;
216-
//-dk:TODO export using ::beman::execution::stopped_as_optional;
217-
//-dk:TODO export using ::beman::execution::stopped_as_error;
221+
export using ::beman::execution::stopped_as_optional;
222+
export using ::beman::execution::stopped_as_error;
218223

219224
// [exec.util.cmplsig.trans]
220225
//-dk:TODO export using ::beman::execution::transform_completion_signatures;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module;
2+
// src/beman/execution/stopped_as_error.cppm -*-C++-*-
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
#include <beman/execution/detail/stopped_as_error.hpp>
6+
7+
export module beman.execution.detail.stopped_as_error;
8+
9+
namespace beman::execution {
10+
export using beman::execution::stopped_as_error_t;
11+
export using beman::execution::stopped_as_error;
12+
} // namespace beman::execution

0 commit comments

Comments
 (0)