#pragma once #include namespace aisa { inline auto suspend() noexcept { return std::suspend_always{}; } template struct promise; template struct task : public std::coroutine_handle> { using handle = std::coroutine_handle>; using promise_type = struct promise; bool await_ready() const noexcept { return handle::done(); } result_t await_resume() const noexcept; template void await_suspend(std::coroutine_handle> h) const noexcept; std::optional operator()() noexcept; }; template<> struct task : public std::coroutine_handle> { using handle = std::coroutine_handle>; using promise_type = struct promise; bool await_ready() const noexcept { return handle::done(); } void await_resume() const noexcept; template void await_suspend(std::coroutine_handle> h) const noexcept; bool operator()() noexcept; }; template struct promise { std::coroutine_handle<> precursor; std::optional result; promise() = default; promise(const promise &) = delete; task get_return_object() noexcept { return task{std::coroutine_handle>::from_promise(*this)}; } std::suspend_never initial_suspend() const noexcept { return {}; } std::suspend_always final_suspend() const noexcept { return {}; } void unhandled_exception() { } void return_value(result_t x) noexcept { result = std::move(x); } }; template<> struct promise { std::coroutine_handle<> precursor; promise() = default; promise(const promise &) = delete; task get_return_object() noexcept { return task{std::coroutine_handle>::from_promise(*this)}; } std::suspend_never initial_suspend() const noexcept { return {}; } std::suspend_always final_suspend() const noexcept { return {}; } void unhandled_exception() { } void return_void() noexcept { } }; template result_t task::await_resume() const noexcept { auto x = std::move(handle::promise().result.value()); handle::destroy(); return std::move(x); } template template void task::await_suspend(std::coroutine_handle> h) const noexcept { h.promise().precursor = *this; } template std::optional task::operator()() noexcept { if (!handle::operator bool()) return {}; if (!handle::done()) { auto &precursor = handle::promise().precursor; if (precursor) { if (!precursor.done()) precursor.resume(); if (precursor.done()) precursor = nullptr; } if (!precursor) handle::resume(); } if (handle::done()) { auto x = await_resume(); handle::operator=(nullptr); return std::move(x); } return {}; } inline void task::await_resume() const noexcept { handle::destroy(); } template void task::await_suspend(std::coroutine_handle> h) const noexcept { h.promise().precursor = *this; } inline bool task::operator()() noexcept { if (!handle::operator bool()) return true; if (!handle::done()) { auto &precursor = handle::promise().precursor; if (precursor) { if (!precursor.done()) precursor.resume(); if (precursor.done()) precursor = nullptr; } if (!precursor) handle::resume(); } if (handle::done()) { await_resume(); handle::operator=(nullptr); return true; } return false; } }