From d80e0dbd20bb8597afe92f770e39d20440557d1f Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sat, 25 Jun 2022 10:16:12 -0700 Subject: Demo for a coroutine-based step evaluator. --- aisa/coroutine.h | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 aisa/coroutine.h (limited to 'aisa/coroutine.h') diff --git a/aisa/coroutine.h b/aisa/coroutine.h new file mode 100644 index 0000000..40a6982 --- /dev/null +++ b/aisa/coroutine.h @@ -0,0 +1,120 @@ +#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; + } + +} -- cgit v1.2.3