1#ifndef B6E7FCEC_A837_4D2C_B71A_E02D65C82406
2#define B6E7FCEC_A837_4D2C_B71A_E02D65C82406
31template<
typename Result>
39template<
typename Promise>
45 void unhandled_exception() noexcept { this->m_exception = std::current_exception(); }
47 [[nodiscard]]
constexpr auto initial_suspend() const noexcept {
return std::suspend_always{}; }
49 [[nodiscard]]
constexpr auto final_suspend() const noexcept
51 struct nested_awaiter {
52 [[nodiscard]]
constexpr bool await_ready() const noexcept {
return false; }
54 [[nodiscard]]
auto await_suspend(std::coroutine_handle<Promise> handle)
const noexcept
56 const auto& promise = handle.promise();
57 return promise.m_next ? promise.m_next : std::noop_coroutine();
60 void await_resume() const noexcept {}
63 return nested_awaiter{};
66 void set_next(std::coroutine_handle<> next)
noexcept { this->m_next = next; }
73 void rethrow_if_exception()
const
75 if (this->m_exception !=
nullptr) {
76 std::rethrow_exception(this->m_exception);
81 std::coroutine_handle<> m_next;
82 std::exception_ptr m_exception =
nullptr;
90 promise_base() noexcept = default;
95struct promise_type : promise_base<promise_type<T>> {
96 using value_type = std::remove_reference_t<T>;
98 std::conditional_t<std::is_lvalue_reference_v<T>, std::add_pointer_t<value_type>, std::optional<value_type>>;
99 using reference = std::conditional_t<std::is_rvalue_reference_v<T>, T, std::add_lvalue_reference_t<value_type>>;
101 auto get_return_object() {
return task<T>{std::coroutine_handle<promise_type>::from_promise(*
this)}; }
107 void return_value(
const T& res)
noexcept(std::is_nothrow_copy_constructible_v<T>)
108 requires(std::is_const_v<T> && !std::is_lvalue_reference_v<T>)
110 this->m_result.emplace(res);
118 void return_value(T res)
noexcept(std::is_nothrow_move_constructible_v<T>)
119 requires(!std::is_const_v<T> && !std::is_lvalue_reference_v<T>)
121 this->m_result = std::move(res);
128 void return_value(T& res)
noexcept
129 requires(std::is_lvalue_reference_v<T>)
131 this->m_result = std::addressof(res);
140 reference result_value()
142 this->rethrow_if_exception();
143 if constexpr (std::is_lvalue_reference_v<T>) {
144 if (this->m_result !=
nullptr) {
145 return *this->m_result;
148 else if (this->m_result.has_value()) {
149 if constexpr (std::is_rvalue_reference_v<T>) {
150 return std::move(this->m_result.value());
153 return this->m_result.value();
157 throw bad_result_access(
"task<T> result accessed before it was set");
169 storage_type m_result{};
173struct promise_type<void> : promise_base<promise_type<void>> {
174 task<void> get_return_object();
175 void return_void() const noexcept {}
176 void result_value()
const { this->rethrow_if_exception(); }
195template<
typename Result =
void>
215 task& operator=(const
task&) = delete;
224 task(
task&& other) noexcept : m_coroutine(std::exchange(other.m_coroutine,
nullptr)) {}
236 if (
this != std::addressof(other)) {
237 if (this->m_coroutine) {
238 this->m_coroutine.destroy();
241 this->m_coroutine = std::exchange(other.m_coroutine,
nullptr);
252 if (this->m_coroutine) {
253 this->m_coroutine.destroy();
269 [[nodiscard]]
constexpr bool is_ready() const noexcept {
return detail::is_ready(this->m_coroutine); }
289 this->m_coroutine.resume();
309 if (this->m_coroutine) {
310 this->m_coroutine.destroy();
311 this->m_coroutine =
nullptr;
322 std::conditional_t<std::is_rvalue_reference_v<Result>, Result, std::add_lvalue_reference_t<value_type>>;
345 detail::check_coroutine(this->m_coroutine);
347 if constexpr (std::is_rvalue_reference_v<Result>) {
348 return std::move(this->m_coroutine.promise().result_value());
351 return this->m_coroutine.promise().result_value();
370 detail::check_coroutine(this->m_coroutine);
371 return this->m_coroutine.promise().result_value();
388 detail::check_coroutine(this->m_coroutine);
389 return std::move(this->m_coroutine.promise().result_value());
405 auto operator co_await()
const&
noexcept
408 [[nodiscard]]
constexpr bool await_ready()
const noexcept {
return detail::is_ready(this->coroutine); }
410 auto await_suspend(std::coroutine_handle<> awaiting)
noexcept
412 this->coroutine.promise().set_next(awaiting);
413 return this->coroutine;
416 decltype(
auto) await_resume()
418 detail::check_coroutine(this->coroutine);
419 auto& promise = this->coroutine.promise();
420 if constexpr (std::is_rvalue_reference_v<Result>) {
421 return std::move(promise.result_value());
424 return promise.result_value();
429 std::coroutine_handle<promise_type> coroutine;
432 return awaiter{this->m_coroutine};
445 auto operator co_await() &&
noexcept
446 requires(!std::is_void_v<Result>)
449 [[nodiscard]]
constexpr bool await_ready()
const noexcept {
return detail::is_ready(this->coroutine); }
451 auto await_suspend(std::coroutine_handle<> awaiting)
noexcept
453 this->coroutine.promise().set_next(awaiting);
454 return this->coroutine;
457 decltype(
auto) await_resume()
459 detail::check_coroutine(this->coroutine);
460 return std::move(this->coroutine.promise().result_value());
464 std::coroutine_handle<promise_type> coroutine;
467 return awaiter{this->m_coroutine};
471 std::coroutine_handle<promise_type> m_coroutine;
482 explicit task(std::coroutine_handle<promise_type> handle) : m_coroutine(handle) {}
492inline task<void> detail::promise_type<void>::get_return_object()
494 return task<void>{std::coroutine_handle<promise_type>::from_promise(*
this)};
std::remove_reference_t< Result > value_type
Value type; a Result with all references stripped.
task() noexcept=default
Default constructor.
std::conditional_t< std::is_rvalue_reference_v< Result >, Result, std::add_lvalue_reference_t< value_type > > reference
Reference type; Result&& if Result is an rvalue reference, Result& otherwise.
rvalue_reference result_value() &&
Returns the result produced by the task.
task & operator=(task &&other) noexcept
Move assignment operator.
reference result_value() &
Returns the result produced by the task.
std::add_rvalue_reference_t< std::remove_cv_t< value_type > > rvalue_reference
Rvalue reference type.
bool destroy()
Destroys the task.
std::add_lvalue_reference_t< std::add_const_t< value_type > > const_reference
Constant version of reference.
detail::promise_type< Result > promise_type
The promise type associated with the task.
bool resume() const
Resumes the task.
constexpr bool is_ready() const noexcept
Checks if the task is ready.
const_reference result_value() const &
Returns the result produced by the task.
Internal utility functions for coroutine handling.
Custom exception classes for coroutine handling.