14#if defined(__cpp_impl_coroutine) && __cpp_impl_coroutine >= 201902L
28template <
typename T =
void>
39 virtual void execute(std::coroutine_handle<>) = 0;
40 virtual ~executor_base() =
default;
48template <
typename Pool>
49struct pool_executor : executor_base
52 explicit pool_executor(Pool& p) : pool(p) {}
54 void execute(std::coroutine_handle<> h)
override
56 pool.submit([h]()
mutable { h.resume(); });
75 [[nodiscard]]
auto await_ready() const noexcept ->
bool
80 template <
typename Promise>
81 auto await_suspend(std::coroutine_handle<Promise> h)
const noexcept -> std::coroutine_handle<>
83 auto cont = h.promise().continuation_;
84 if (h.promise().executor_ && cont)
86 h.promise().executor_->execute(cont);
87 return std::noop_coroutine();
91 return std::noop_coroutine();
94 void await_resume() const noexcept
121class task_promise_base
124 task_promise_base() =
default;
126 auto initial_suspend() noexcept -> std::suspend_always
131 auto final_suspend() noexcept -> final_awaiter
136 void unhandled_exception() noexcept
138 exception_ = std::current_exception();
141 void rethrow_if_exception()
144 std::rethrow_exception(exception_);
147 std::coroutine_handle<> continuation_{};
148 executor_base* executor_{
nullptr};
151 std::exception_ptr exception_{};
193 struct promise_type : detail::task_promise_base<T>
195 auto get_return_object() noexcept -> task
197 return task{std::coroutine_handle<promise_type>::from_promise(*
this)};
200 void return_value(T value)
noexcept(std::is_nothrow_move_constructible_v<T>)
202 result_.emplace(std::move(value));
207 this->rethrow_if_exception();
208 return std::move(*result_);
212 std::optional<T> result_{};
215 task() noexcept = default;
217 task(task&& other) noexcept : handle_(std::exchange(other.handle_,
nullptr))
221 auto operator=(task&& other)
noexcept -> task&
226 handle_ = std::exchange(other.handle_,
nullptr);
236 task(task
const&) =
delete;
237 auto operator=(task
const&) -> task& =
delete;
239 [[nodiscard]]
auto handle() const noexcept -> std::coroutine_handle<promise_type>
246 std::coroutine_handle<promise_type> handle_;
248 [[nodiscard]]
auto await_ready() const noexcept ->
bool
253 auto await_suspend(std::coroutine_handle<> continuation)
noexcept -> std::coroutine_handle<>
255 handle_.promise().continuation_ = continuation;
259 auto await_resume() -> T
261 return handle_.promise().result();
265 auto operator co_await()
const&
noexcept -> awaiter
267 return awaiter{handle_};
270 auto operator co_await()
const&&
noexcept -> awaiter
272 return awaiter{handle_};
276 explicit task(std::coroutine_handle<promise_type> h) noexcept : handle_(h)
289 std::coroutine_handle<promise_type> handle_{};
325 struct promise_type : detail::task_promise_base<void>
327 auto get_return_object() noexcept -> task<
void>
329 return task<void>{std::coroutine_handle<promise_type>::from_promise(*
this)};
332 void return_void() noexcept
338 this->rethrow_if_exception();
342 task() noexcept = default;
344 task(task&& other) noexcept : handle_(std::exchange(other.handle_,
nullptr))
348 auto operator=(task&& other)
noexcept -> task<void>&
353 handle_ = std::exchange(other.handle_,
nullptr);
363 task(task
const&) =
delete;
364 auto operator=(task
const&) -> task<void>& =
delete;
366 [[nodiscard]]
auto handle() const noexcept -> std::coroutine_handle<promise_type>
373 std::coroutine_handle<promise_type> handle_;
375 [[nodiscard]]
auto await_ready() const noexcept ->
bool
380 auto await_suspend(std::coroutine_handle<> continuation)
noexcept -> std::coroutine_handle<>
382 handle_.promise().continuation_ = continuation;
388 handle_.promise().result();
392 auto operator co_await()
const&
noexcept -> awaiter
394 return awaiter{handle_};
397 auto operator co_await()
const&&
noexcept -> awaiter
399 return awaiter{handle_};
403 explicit task(std::coroutine_handle<promise_type> h) noexcept : handle_(h)
416 std::coroutine_handle<promise_type> handle_{};
449 auto initial_suspend() noexcept -> std::suspend_always
454 auto final_suspend() noexcept
458 [[nodiscard]]
auto await_ready() const noexcept ->
bool
463 void await_suspend(std::coroutine_handle<promise_type> h)
const noexcept
465 h.promise().finished_.store(
true, std::memory_order_release);
466 h.promise().finished_.notify_one();
469 void await_resume() const noexcept
476 auto get_return_object() -> sync_wait_task
478 return sync_wait_task{std::coroutine_handle<promise_type>::from_promise(*
this)};
481 void return_void() noexcept
485 void unhandled_exception() noexcept
487 exception_ = std::current_exception();
490 std::atomic<bool> finished_{
false};
491 std::exception_ptr exception_{};
494 explicit sync_wait_task(std::coroutine_handle<promise_type> h) : handle_(h)
498 sync_wait_task(sync_wait_task&& other) noexcept : handle_(std::exchange(other.handle_,
nullptr))
508 sync_wait_task(sync_wait_task
const&) =
delete;
509 auto operator=(sync_wait_task
const&) -> sync_wait_task& =
delete;
510 auto operator=(sync_wait_task&&) -> sync_wait_task& =
delete;
519 handle_.promise().finished_.wait(
false, std::memory_order_acquire);
524 if (handle_.promise().exception_)
525 std::rethrow_exception(handle_.promise().exception_);
529 std::coroutine_handle<promise_type> handle_;
557auto sync_wait(task<T> t) -> T
559 std::optional<T> result;
560 std::exception_ptr ex;
562 auto wrapper = [&result, &ex](task<T> inner) -> detail::sync_wait_task {
565 result.emplace(
co_await inner);
569 ex = std::current_exception();
573 auto sw = wrapper(std::move(t));
579 std::rethrow_exception(ex);
581 return std::move(*result);
597inline void sync_wait(task<void> t)
599 std::exception_ptr ex;
601 auto wrapper = [&ex](task<void> inner) -> detail::sync_wait_task {
608 ex = std::current_exception();
612 auto sw = wrapper(std::move(t));
618 std::rethrow_exception(ex);
667template <
typename Pool>
672 [[nodiscard]]
auto await_ready() const noexcept ->
bool {
return false; }
674 void await_suspend(std::coroutine_handle<> h)
const
676 pool.submit([h]()
mutable { h.resume(); });
679 void await_resume() const noexcept {}
706template <
typename Pool,
typename F>
707auto run_on(Pool& pool, F&& coro_fn)
708 -> std::future<
decltype(sync_wait(std::declval<std::invoke_result_t<F>>()))>
710 return pool.submit([fn = std::forward<F>(coro_fn)]()
mutable {
711 return sync_wait(fn());