A weird game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
turings-tarpit/coro.hpp

107 lines
1.8 KiB

#pragma once
#include <concepts>
#include <coroutine>
#include <exception>
#include <assert.h>
enum TaskStates {
STARTED, AWAIT, YIELD,
EXCEPTION, RETURN,
RETURN_VOID, DEAD
};
template<typename T>
struct Task {
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
struct promise_type {
T value_;
std::exception_ptr exception_;
TaskStates state_{STARTED};
Task get_return_object() {
return Task(handle_type::from_promise(*this));
}
std::suspend_always initial_suspend() {
state_ = AWAIT;
return {};
}
std::suspend_always final_suspend() noexcept {
return {};
}
void unhandled_exception() {
state_ = EXCEPTION;
exception_ = std::current_exception();
}
template<std::convertible_to<T> From> // C++20 concept
void return_value(From &&from) {
state_ = RETURN;
value_ = std::forward<From>(from);
}
template<std::convertible_to<T> From> // C++20 concept
std::suspend_always yield_value(From &&from) {
state_ = YIELD;
value_ = std::forward<From>(from);
return {};
}
void return_void() {
state_ = RETURN_VOID;
}
};
handle_type h_;
Task() {
}
Task(handle_type h) : h_(h) {
}
Task(const Task &t) : h_(t.h_) {
}
void destroy() {
// this should make it safe to clal repeatedly
if(h_.promise().state_ != DEAD) {
h_.destroy();
h_.promise().state_ = DEAD;
}
}
T operator()() {
assert(!h_.done());
call();
return std::move(h_.promise().value_);
}
bool done() {
return h_.done();
}
TaskStates state() {
return h_.promise().state_;
}
private:
void call() {
h_();
if (h_.promise().exception_) {
std::rethrow_exception(h_.promise().exception_);
}
}
};
struct Pass : std::suspend_always {
};