20template <
typename T =
void,
typename Allocator =
void>
class TaskBase {
22 using PromiseType =
typename Coro<T, Allocator>::promise_type;
24 TaskBase() : TaskBase(nullptr) {}
25 TaskBase(std::coroutine_handle<PromiseType> h) : handle_(h) {}
26 TaskBase(TaskBase &&other) noexcept
27 : handle_(std::exchange(other.handle_,
nullptr)) {}
28 TaskBase &operator=(TaskBase &&other)
noexcept {
31 panic_on(
"Task destroyed without being awaited");
33 handle_ = std::exchange(other.handle_,
nullptr);
38 CONDY_DELETE_COPY(TaskBase);
42 panic_on(
"Task destroyed without being awaited");
54 void detach() noexcept {
55 handle_.promise().request_detach();
63 bool joinable() const noexcept {
return handle_ !=
nullptr; }
75 auto operator co_await()
noexcept;
78 static void wait_inner_(std::coroutine_handle<PromiseType> handle);
81 std::coroutine_handle<PromiseType> handle_;
84template <
typename T,
typename Allocator>
85void TaskBase<T, Allocator>::wait_inner_(
86 std::coroutine_handle<PromiseType> handle) {
87 if (Context::current().runtime() !=
nullptr) [[unlikely]] {
88 throw std::logic_error(
"Sync wait inside runtime");
90 if (handle ==
nullptr) [[unlikely]] {
91 throw std::invalid_argument(
"Task not joinable");
93 std::promise<void> prom;
94 auto fut = prom.get_future();
95 struct TaskWaiter :
public InvokerAdapter<TaskWaiter> {
96 TaskWaiter(std::promise<void> &p) : prom_(p) {}
98 void invoke() noexcept { prom_.set_value(); }
100 std::promise<void> &prom_;
103 TaskWaiter waiter(prom);
104 if (handle.promise().request_join(&waiter)) {
110template <
typename T,
typename Allocator>
111struct TaskAwaiterBase :
public InvokerAdapter<TaskAwaiterBase<T, Allocator>> {
113 std::coroutine_handle<
typename Coro<T, Allocator>::promise_type>
116 : task_handle_(task_handle), runtime_(runtime) {}
118 bool await_ready()
const {
119 if (task_handle_ ==
nullptr) {
120 throw std::invalid_argument(
"Task not joinable");
125 template <
typename PromiseType>
127 await_suspend(std::coroutine_handle<PromiseType> caller_handle)
noexcept {
128 Context::current().runtime()->pend_work_internal();
129 assert(runtime_ !=
nullptr);
130 caller_promise_ = &caller_handle.promise();
131 return task_handle_.promise().request_join(
this);
134 void invoke() noexcept {
135 assert(caller_promise_ !=
nullptr);
136 runtime_->schedule_internal(caller_promise_);
139 std::coroutine_handle<typename Coro<T, Allocator>::promise_type>
141 Runtime *runtime_ =
nullptr;
142 WorkInvoker *caller_promise_ =
nullptr;
145template <
typename T,
typename Allocator>
146struct TaskAwaiter :
public TaskAwaiterBase<T, Allocator> {
147 using Base = TaskAwaiterBase<T, Allocator>;
151 Context::current().runtime()->resume_work_internal();
152 auto exception = std::move(Base::task_handle_.promise()).exception();
153 if (exception) [[unlikely]] {
154 Base::task_handle_.destroy();
155 std::rethrow_exception(exception);
157 T value = std::move(Base::task_handle_.promise()).value();
158 Base::task_handle_.destroy();
163template <
typename Allocator>
164struct TaskAwaiter<void, Allocator> :
public TaskAwaiterBase<void, Allocator> {
165 using Base = TaskAwaiterBase<void, Allocator>;
168 void await_resume() {
169 Context::current().runtime()->resume_work_internal();
170 auto exception = std::move(Base::task_handle_.promise()).exception();
171 Base::task_handle_.destroy();
172 if (exception) [[unlikely]] {
173 std::rethrow_exception(exception);
178template <
typename T,
typename Allocator>
179inline auto TaskBase<T, Allocator>::operator
co_await()
noexcept {
180 return TaskAwaiter<T, Allocator>(std::exchange(handle_,
nullptr),
181 Context::current().runtime());
184struct [[nodiscard]] SwitchAwaiter {
185 bool await_ready() const noexcept {
return false; }
187 template <
typename PromiseType>
188 void await_suspend(std::coroutine_handle<PromiseType> handle)
noexcept {
189 runtime_->schedule_internal(&handle.promise());
192 void await_resume() const noexcept {}
Polymorphic invocation utilities.
The main namespace for the Condy library.
Runtime type for running the io_uring event loop.