Skip to content

Commit 8db3826

Browse files
committed
start towards supporting an awaiter
1 parent fc374ac commit 8db3826

File tree

12 files changed

+329
-87
lines changed

12 files changed

+329
-87
lines changed

examples/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
22

33
set(ALL_EXAMPLES
4+
co_await-task
5+
)
6+
set(xALL_EXAMPLES
7+
co_await-task
48
task_scheduler
59
environment
610
c++now-basic

examples/co_await-task.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// examples/co_await-task.cpp -*-C++-*-
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#include <beman/execution/task.hpp>
5+
#include <beman/execution/execution.hpp>
6+
#include <iostream>
7+
8+
namespace ex = beman::execution;
9+
10+
// ----------------------------------------------------------------------------
11+
12+
auto inner() -> ex::task<> {
13+
beman::task::detail::logger log("inner");
14+
co_return;
15+
}
16+
17+
auto outer() -> ex::task<> {
18+
beman::task::detail::logger log("outer");
19+
for (int i{}; i < 10; ++i) {
20+
co_await inner().as_awaitable();
21+
log.log("inner_awaited");
22+
}
23+
co_return;
24+
}
25+
26+
auto main() -> int {
27+
std::cout << std::unitbuf;
28+
beman::task::detail::logger log("sync_wait");
29+
ex::sync_wait(outer());
30+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// include/beman/task/detail/awaiter.hpp -*-C++-*-
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#ifndef INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_AWAITER
5+
#define INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_AWAITER
6+
7+
#include <beman/task/detail/handle.hpp>
8+
#include <beman/task/detail/state_base.hpp>
9+
#include <coroutine>
10+
#include <utility>
11+
#include <iostream> //-dk:TODO
12+
13+
// ----------------------------------------------------------------------------
14+
15+
namespace beman::task::detail {
16+
template <typename Env, typename Promise>
17+
class awaiter : public ::beman::task::detail::state_base<Env> {
18+
public:
19+
using stop_token_type = typename ::beman::task::detail::state_base<Env>::stop_token_type;
20+
21+
explicit awaiter(::beman::task::detail::handle<Promise> h) : handle(::std::move(h)) {}
22+
constexpr auto await_ready() const noexcept -> bool { return false; }
23+
template <typename PP>
24+
auto await_suspend(::std::coroutine_handle<PP> parent) noexcept {
25+
::beman::task::detail::logger log("awaiter::suspend");
26+
this->parent = ::std::move(parent);
27+
assert(this->parent);
28+
return this->handle.start(this);
29+
}
30+
auto await_resume() { ::beman::task::detail::logger l("awaiter::await_resume()"); }
31+
32+
private:
33+
auto do_complete() -> std::coroutine_handle<> override {
34+
::beman::task::detail::logger l("awaiter::complete()");
35+
assert(this->parent);
36+
return ::std::move(this->parent);
37+
}
38+
auto do_get_stop_token() -> stop_token_type override { return {}; }
39+
auto do_get_context() -> Env& override { return this->env; }
40+
41+
::beman::task::detail::logger l{"awaiter"};
42+
Env env;
43+
::beman::task::detail::handle<Promise> handle;
44+
::std::coroutine_handle<> parent{};
45+
};
46+
} // namespace beman::task::detail
47+
48+
// ----------------------------------------------------------------------------
49+
50+
#endif

include/beman/task/detail/handle.hpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_HANDLE
66

77
#include <beman/execution/execution.hpp>
8+
#include <beman/task/detail/logger.hpp>
89
#include <coroutine>
910
#include <memory>
1011
#include <utility>
@@ -24,13 +25,17 @@ class handle {
2425

2526
public:
2627
explicit handle(P* p) : h(p) {}
27-
void reset() { this->h.reset(); }
28+
auto reset() -> void { this->h.reset(); }
2829
template <typename... A>
29-
void start(A&&... a) noexcept {
30-
this->h->start(::std::forward<A>(a)...);
30+
auto start(A&&... a) noexcept -> auto {
31+
::beman::task::detail::logger l("handle::start");
32+
return this->h->start(::std::forward<A>(a)...);
33+
}
34+
auto release() -> ::std::coroutine_handle<P> {
35+
return ::std::coroutine_handle<P>::from_promise(*this->h.release());
3136
}
3237
template <::beman::execution::receiver Receiver>
33-
void complete(Receiver&& receiver) {
38+
auto complete(Receiver&& receiver) -> void {
3439
this->h->complete(::std::forward<Receiver>(receiver));
3540
}
3641
};
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// include/beman/task/detail/logger.hpp -*-C++-*-
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#ifndef INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_LOGGER
5+
#define INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_LOGGER
6+
7+
#include <algorithm>
8+
#include <iterator>
9+
#include <iostream>
10+
11+
// ----------------------------------------------------------------------------
12+
13+
namespace beman::task::detail {
14+
struct logger {
15+
static auto level(int i) -> int {
16+
static int rc{};
17+
return rc += i;
18+
}
19+
::std::ostream& log(const char* pre, const char* msg) {
20+
::std::fill_n(::std::ostreambuf_iterator<char>(std::cout.rdbuf()), level(0), ' ');
21+
std::cout << pre;
22+
return std::cout << msg << "\n";
23+
}
24+
::std::ostream& log(const char* msg) { return log("| ", msg); }
25+
const char* msg;
26+
explicit logger(const char* m) : msg(m) {
27+
level(1);
28+
log("\\ ", this->msg);
29+
}
30+
logger(logger&&) = delete;
31+
~logger() {
32+
log("/ ", this->msg);
33+
level(-1);
34+
}
35+
};
36+
} // namespace beman::task::detail
37+
38+
// ----------------------------------------------------------------------------
39+
40+
#endif

include/beman/task/detail/promise_base.hpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_PROMISE_BASE
66

77
#include <beman/task/detail/result_type.hpp>
8+
#include <beman/task/detail/logger.hpp>
89
#include <beman/execution/execution.hpp>
910
#include <cstddef>
1011
#include <concepts>
@@ -22,6 +23,7 @@ namespace beman::task::detail {
2223
template <::beman::task::detail::stoppable Stop, typename Value, typename ErrorCompletions>
2324
class promise_base;
2425

26+
#if 0
2527
template <::beman::task::detail::stoppable Stop, typename Value>
2628
requires(not ::std::same_as<Value, void>)
2729
class promise_base<Stop, Value, ::beman::execution::completion_signatures<>>
@@ -33,9 +35,11 @@ class promise_base<Stop, Value, ::beman::execution::completion_signatures<>>
3335
*/
3436
template <typename T>
3537
void return_value(T&& value) {
38+
::beman::task::detail::logger l("promise_base::return_value(T&&)");
3639
this->set_value(::std::forward<T>(value));
3740
}
3841
};
42+
#endif
3943

4044
template <::beman::task::detail::stoppable Stop, typename Value, typename... Error>
4145
requires(not ::std::same_as<Value, void>)
@@ -46,21 +50,29 @@ class promise_base<Stop, Value, ::beman::execution::completion_signatures<::bema
4650
* \brief Set the value result.
4751
* \internal
4852
*/
53+
::beman::task::detail::logger l{"promise_base<T>"};
4954
template <typename T>
5055
void return_value(T&& value) {
56+
::beman::task::detail::logger l("promise_base::return_value(T&&)");
5157
this->set_value(::std::forward<T>(value));
5258
}
5359
};
5460

61+
#if 0
5562
template <typename ::beman::task::detail::stoppable Stop>
5663
class promise_base<Stop, void, ::beman::execution::completion_signatures<>>
5764
: public ::beman::task::detail::result_type<Stop, void_type> {
5865
public:
5966
/*
6067
* \brief Set the value result although without any value.
6168
*/
62-
void return_void() { this->set_value(void_type{}); }
69+
::beman::task::detail::logger l{"promise_base<void>"};
70+
void return_void() {
71+
::beman::task::detail::logger l("promise_base::return_void()");
72+
this->set_value(void_type{});
73+
}
6374
};
75+
#endif
6476

6577
template <typename ::beman::task::detail::stoppable Stop, typename... Error>
6678
class promise_base<Stop, void, ::beman::execution::completion_signatures<::beman::execution::set_error_t(Error)...>>
@@ -69,7 +81,11 @@ class promise_base<Stop, void, ::beman::execution::completion_signatures<::beman
6981
/*
7082
* \brief Set the value result although without any value.
7183
*/
72-
void return_void() { this->set_value(void_type{}); }
84+
::beman::task::detail::logger l{"promise_base<void>"};
85+
void return_void() {
86+
::beman::task::detail::logger l("promise_base::return_void()");
87+
this->set_value(void_type{});
88+
}
7389
};
7490
} // namespace beman::task::detail
7591

include/beman/task/detail/promise_type.hpp

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#ifndef INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_PROMISE_TYPE
55
#define INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_PROMISE_TYPE
66

7+
#include <beman/task/detail/awaiter.hpp>
78
#include <beman/task/detail/affine_on.hpp>
89
#include <beman/task/detail/allocator_of.hpp>
910
#include <beman/task/detail/allocator_support.hpp>
@@ -20,21 +21,24 @@
2021
#include <beman/task/detail/with_error.hpp>
2122
#include <beman/execution/execution.hpp>
2223
#include <beman/execution/detail/meta_contains.hpp>
24+
#include <cassert>
2325
#include <coroutine>
2426
#include <optional>
2527
#include <type_traits>
28+
#include <beman/task/detail/logger.hpp>
2629

2730
// ----------------------------------------------------------------------------
2831

32+
namespace beman::task::detail {
33+
34+
#if 0
2935
struct opt_rcvr {
3036
using receiver_concept = ::beman::execution::receiver_t;
3137
void set_value(auto&&...) && noexcept {}
3238
void set_error(auto&&) && noexcept {}
3339
void set_stopped() && noexcept {}
3440
};
3541

36-
namespace beman::task::detail {
37-
3842
template <typename T>
3943
struct has_exception_ptr;
4044
template <typename... T>
@@ -186,6 +190,10 @@ struct promise_type : ::beman::task::detail::promise_base<::beman::task::detail:
186190
// This overload is only used if error completions use `co_await with_error(e)`.
187191
return std::move(with);
188192
}
193+
template <typename Env, typename P>
194+
auto await_transform(::beman::task::detail::awaiter<Env, P>&& a) noexcept {
195+
return ::std::move(a);
196+
}
189197
template <::beman::execution::sender Sender, typename Scheduler>
190198
auto internal_await_transform(Sender&& sender, Scheduler&& sched) noexcept {
191199
if constexpr (std::same_as<::beman::task::detail::inline_scheduler, scheduler_type>)
@@ -223,14 +231,15 @@ struct promise_type : ::beman::task::detail::promise_base<::beman::task::detail:
223231
return std::noop_coroutine();
224232
}
225233

226-
struct env {
234+
struct env_t {
227235
const promise_type* promise;
228236

229237
scheduler_type query(::beman::execution::get_scheduler_t) const noexcept { return *promise->scheduler; }
230238
allocator_type query(::beman::execution::get_allocator_t) const noexcept { return promise->allocator; }
231239
stop_token_type query(::beman::execution::get_stop_token_t) const noexcept {
232240
return promise->state->get_stop_token();
233241
}
242+
auto foo() const {} //-dk:TODO remove
234243
template <typename Q, typename... A>
235244
requires requires(const C& c, Q q, A&&... a) {
236245
::beman::execution::forwarding_query(q);
@@ -241,8 +250,53 @@ struct promise_type : ::beman::task::detail::promise_base<::beman::task::detail:
241250
}
242251
};
243252

244-
env get_env() const noexcept { return {this}; }
253+
auto get_env() const noexcept -> env_t { return env_t{this}; }
245254
};
255+
#else
256+
template <typename Coroutine, typename T, typename Environment>
257+
class promise_type
258+
: public ::beman::task::detail::promise_base<::beman::task::detail::stoppable::yes,
259+
::std::remove_cvref_t<T>,
260+
::beman::task::detail::error_types_of_t<Environment>>,
261+
public ::beman::task::detail::allocator_support<::beman::task::detail::allocator_of_t<Environment>> {
262+
public:
263+
struct final_awaiter {
264+
::beman::task::detail::state_base<Environment>* state{};
265+
constexpr auto await_ready() const noexcept -> bool { return false; }
266+
auto await_suspend(auto&&) noexcept -> ::std::coroutine_handle<> {
267+
::beman::task::detail::logger l("promise_type::final_awaiter::await_suspend()");
268+
return this->state->complete();
269+
}
270+
constexpr auto await_resume() noexcept -> void {}
271+
};
272+
constexpr auto initial_suspend() noexcept -> ::std::suspend_always {
273+
::beman::task::detail::logger l("promise_type::initial_suspend");
274+
return {};
275+
}
276+
constexpr auto final_suspend() noexcept -> final_awaiter {
277+
::beman::task::detail::logger l("promise_type::final_suspend");
278+
assert(this->state != nullptr);
279+
return {this->state};
280+
}
281+
282+
auto unhandled_exception() noexcept { /*-dk:TODO*/ }
283+
auto get_return_object() noexcept { return Coroutine(::beman::task::detail::handle<promise_type>(this)); }
284+
285+
struct env {};
286+
auto get_env() const noexcept { return env{}; }
287+
288+
auto start(::beman::task::detail::state_base<Environment>* state) -> ::std::coroutine_handle<> {
289+
::beman::task::detail::logger l("promise_type::start");
290+
this->state = state;
291+
assert(this->state != nullptr);
292+
return ::std::coroutine_handle<promise_type>::from_promise(*this);
293+
}
294+
295+
private:
296+
::beman::task::detail::logger l{"promise_type"};
297+
::beman::task::detail::state_base<Environment>* state{};
298+
};
299+
#endif
246300
} // namespace beman::task::detail
247301

248302
// ----------------------------------------------------------------------------

include/beman/task/detail/result_type.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define INCLUDED_INCLUDE_BEMAN_TASK_DETAIL_RESULT_TYPE
66

77
#include <beman/task/detail/sub_visit.hpp>
8+
#include <beman/task/detail/logger.hpp>
89
#include <beman/execution/execution.hpp>
910
#include <exception>
1011
#include <utility>
@@ -56,13 +57,15 @@ class result_type {
5657
*/
5758
template <typename T>
5859
void set_value(T&& value) {
60+
::beman::task::detail::logger l("result_type::set_value(T&&)");
5961
this->result.template emplace<1u>(::std::forward<T>(value));
6062
}
6163
/*
6264
* \brief Set the result for a `set_error` completion.
6365
*/
6466
template <typename E>
6567
void set_error(E&& error) {
68+
::beman::task::detail::logger l("result_type::set_error(E&&)");
6669
this->result.template emplace<2u + find_index<0u, ::std::remove_cvref_t<E>, Error...>()>(
6770
::std::forward<E>(error));
6871
}
@@ -80,6 +83,7 @@ class result_type {
8083
*/
8184
template <::beman::execution::receiver Receiver>
8285
void complete(Receiver&& rcvr) {
86+
::beman::task::detail::logger l("result_type::complete(R&&)");
8387
switch (this->result.index()) {
8488
case 0:
8589
if constexpr (Stop == ::beman::task::detail::stoppable::yes)

0 commit comments

Comments
 (0)