Skip to content

Instantly share code, notes, and snippets.

@cleoold
Created October 28, 2023 02:32
Show Gist options
  • Save cleoold/fcd80b975dabda59ae90a6423dd0d8b5 to your computer and use it in GitHub Desktop.
Save cleoold/fcd80b975dabda59ae90a6423dd0d8b5 to your computer and use it in GitHub Desktop.
c++ coroutine intro
#include <coroutine>
#include <format>
#include <deque>
#include <optional>
using namespace std;
deque<coroutine_handle<>> queue;
template<class T>
struct task {
// awaitee site
struct promise_type {
task get_return_object() {
return { .handle = coroutine_handle<promise_type>::from_promise(*this) };
}
suspend_always initial_suspend() { return {}; };
suspend_never final_suspend() noexcept { return {}; }
template<class U> void return_value(U&& v) {
value = std::forward<U>(v);
if (parent) {
queue.push_back(parent);
}
}
// todo: save current_exception() and rethrow_exception() at resume site
void unhandled_exception() { throw; }
optional<T> value;
coroutine_handle<> parent;
};
// awaiter site
struct awaiter {
bool await_ready() { return false; }
void await_suspend(coroutine_handle<promise_type> parent) {
handle.promise().parent = parent;
queue.push_back(handle);
}
T &await_resume() { return *handle.promise().value; }
coroutine_handle<promise_type> handle;
};
awaiter operator co_await() { return awaiter{ .handle = handle }; };
T &operator*() { return *handle.promise().value; }
coroutine_handle<promise_type> handle;
};
task<int> return10() {
co_return 10;
}
task<int> plus5(int x) {
co_return x + 5;
}
task<int> example() {
auto r = co_await return10();
r = co_await plus5(r);
co_return r;
}
task<int> example2() {
auto r = co_await example();
r = co_await plus5(r);
r += co_await example();
co_return r;
}
int main() {
auto t = example2();
t.handle();
while (queue.size()) {
auto &front = queue.front();
front();
queue.pop_front();
}
printf("%d\n", *t);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment