20template<
typename T =
void>
26struct TaskPromiseBase {
27 std::coroutine_handle<> continuation;
28 std::exception_ptr exception;
32 bool detached =
false;
34 auto initial_suspend() noexcept {
return std::suspend_always{}; }
39 bool await_ready() const noexcept {
return detached; }
42 template<
typename Promise>
43 std::coroutine_handle<> await_suspend(std::coroutine_handle<Promise> h)
noexcept {
44 TaskPromiseBase<T>& base = h.promise();
45 return base.continuation ? base.continuation : std::noop_coroutine();
48 void await_resume() const noexcept {}
51 auto final_suspend() noexcept {
return FinalAwaiter{detached}; }
53 void unhandled_exception() noexcept { exception = std::current_exception(); }
57struct TaskPromise : TaskPromiseBase<T> {
59 std::optional<T> value;
61 Task<T> get_return_object() noexcept;
64 void return_value(U&& v) noexcept(std::is_nothrow_constructible_v<T, U>) {
65 value.emplace(std::forward<U>(v));
70struct TaskPromise<void> : TaskPromiseBase<void> {
71 using value_type = void;
72 Task<void> get_return_object() noexcept;
73 void return_void() noexcept {}
90 Task(
Task&& o) noexcept : handle_(std::exchange(o.handle_, {})) {}
93 if (handle_) handle_.destroy();
94 handle_ = std::exchange(o.handle_, {});
100 if (handle_) handle_.destroy();
103 [[nodiscard]]
bool done() const noexcept {
return handle_ && handle_.done(); }
110 auto operator co_await() &&
noexcept {
114 bool await_ready()
const noexcept {
return !h || h.done(); }
116 std::coroutine_handle<> await_suspend(std::coroutine_handle<> caller)
noexcept {
117 h.promise().continuation = caller;
122 if (!h) {
throw std::runtime_error(
"Task: empty handle"); }
123 auto& p = h.promise();
124 if (p.exception) std::rethrow_exception(p.exception);
125 if constexpr (!std::is_void_v<T>) {
126 return std::move(*p.value);
131 ~Awaiter() {
if (h) h.destroy(); }
134 Awaiter(Awaiter&& o) noexcept : h(std::exchange(o.h, {})) {}
136 Awaiter(
const Awaiter&) =
delete;
137 Awaiter&
operator=(
const Awaiter&) =
delete;
140 return Awaiter{std::exchange(handle_, {})};
145 if (handle_ && !handle_.done()) handle_.resume();
159 if (!handle_)
return;
160 auto h = std::exchange(handle_, {});
165 h.promise().detached =
true;
178 if (!handle_)
throw std::runtime_error(
"Task: empty handle");
179 if (!handle_.done()) handle_.resume();
180 if (!handle_.done())
throw std::runtime_error(
"Task: did not complete synchronously");
181 auto& p = handle_.promise();
182 if (p.exception) std::rethrow_exception(p.exception);
183 if constexpr (!std::is_void_v<T>) {
184 return std::move(*p.value);
189 handle_type handle_{};
194Task<T> TaskPromise<T>::get_return_object() noexcept {
195 return Task<T>{std::coroutine_handle<TaskPromise<T>>::from_promise(*
this)};
198inline Task<void> TaskPromise<void>::get_return_object() noexcept {
199 return Task<void>{std::coroutine_handle<TaskPromise<void>>::from_promise(*
this)};
~Task()
Definition task.hpp:99
void start_detached_()
Lvalue convenience used internally by AsyncCommand.
Definition task.hpp:173
T blocking_get()
Blocking accessor — only safe if the task body is synchronous (no real async).
Definition task.hpp:177
std::coroutine_handle< promise_type > handle_type
Definition task.hpp:82
Task & operator=(const Task &)=delete
bool done() const noexcept
Definition task.hpp:103
Task & operator=(Task &&o) noexcept
Definition task.hpp:91
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:158
detail::TaskPromise< T > promise_type
Definition task.hpp:81
void start()
Eagerly start the task without awaiting it. Use blocking_get() if you need the result.
Definition task.hpp:144
Task(Task &&o) noexcept
Definition task.hpp:90
Definition async_command.hpp:118