19template<
typename T =
void>
25struct TaskPromiseBase {
26 std::coroutine_handle<> continuation;
27 std::exception_ptr exception;
31 bool detached =
false;
33 auto initial_suspend() noexcept {
return std::suspend_always{}; }
38 bool await_ready() const noexcept {
return detached; }
41 template<
typename Promise>
42 std::coroutine_handle<> await_suspend(std::coroutine_handle<Promise> h)
noexcept {
43 TaskPromiseBase<T>& base = h.promise();
44 return base.continuation ? base.continuation : std::noop_coroutine();
47 void await_resume() const noexcept {}
50 auto final_suspend() noexcept {
return FinalAwaiter{detached}; }
52 void unhandled_exception() noexcept { exception = std::current_exception(); }
56struct TaskPromise : TaskPromiseBase<T> {
58 std::optional<T> value;
60 Task<T> get_return_object() noexcept;
63 void return_value(U&& v) noexcept(std::is_nothrow_constructible_v<T, U>) {
64 value.emplace(std::forward<U>(v));
69struct TaskPromise<void> : TaskPromiseBase<void> {
70 using value_type = void;
71 Task<void> get_return_object() noexcept;
72 void return_void() noexcept {}
89 Task(
Task&& o) noexcept : handle_(std::exchange(o.handle_, {})) {}
92 if (handle_) handle_.destroy();
93 handle_ = std::exchange(o.handle_, {});
99 if (handle_) handle_.destroy();
102 [[nodiscard]]
bool done() const noexcept {
return handle_ && handle_.done(); }
109 auto operator co_await() &&
noexcept {
113 bool await_ready()
const noexcept {
return !h || h.done(); }
115 std::coroutine_handle<> await_suspend(std::coroutine_handle<> caller)
noexcept {
116 h.promise().continuation = caller;
121 auto& p = h.promise();
122 if (p.exception) std::rethrow_exception(p.exception);
123 if constexpr (!std::is_void_v<T>) {
124 return std::move(*p.value);
129 ~Awaiter() {
if (h) h.destroy(); }
132 Awaiter(Awaiter&& o) noexcept : h(std::exchange(o.h, {})) {}
134 Awaiter(
const Awaiter&) =
delete;
135 Awaiter&
operator=(
const Awaiter&) =
delete;
138 return Awaiter{std::exchange(handle_, {})};
143 if (handle_ && !handle_.done()) handle_.resume();
157 if (!handle_)
return;
158 auto h = std::exchange(handle_, {});
163 h.promise().detached =
true;
176 if (!handle_)
throw std::runtime_error(
"Task: empty handle");
177 if (!handle_.done()) handle_.resume();
178 if (!handle_.done())
throw std::runtime_error(
"Task: did not complete synchronously");
179 auto& p = handle_.promise();
180 if (p.exception) std::rethrow_exception(p.exception);
181 if constexpr (!std::is_void_v<T>) {
182 return std::move(*p.value);
187 handle_type handle_{};
192Task<T> TaskPromise<T>::get_return_object() noexcept {
193 return Task<T>{std::coroutine_handle<TaskPromise<T>>::from_promise(*
this)};
196inline Task<void> TaskPromise<void>::get_return_object() noexcept {
197 return Task<void>{std::coroutine_handle<TaskPromise<void>>::from_promise(*
this)};
~Task()
Definition task.hpp:98
void start_detached_()
Lvalue convenience used internally by AsyncCommand.
Definition task.hpp:171
T blocking_get()
Blocking accessor — only safe if the task body is synchronous (no real async).
Definition task.hpp:175
std::coroutine_handle< promise_type > handle_type
Definition task.hpp:81
Task & operator=(const Task &)=delete
bool done() const noexcept
Definition task.hpp:102
Task & operator=(Task &&o) noexcept
Definition task.hpp:90
Task(const Task &)=delete
void start_detached() &&
Start the task and detach it: the coroutine frame stays alive until the coroutine completes,...
Definition task.hpp:156
detail::TaskPromise< T > promise_type
Definition task.hpp:80
void start()
Eagerly start the task without awaiting it. Use blocking_get() if you need the result.
Definition task.hpp:142
Task(Task &&o) noexcept
Definition task.hpp:89
Definition async_command.hpp:118