Skip to content

Instantly share code, notes, and snippets.

@ericniebler
Last active January 20, 2021 23:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericniebler/72e8dd28aae416894157f70ab0cce72c to your computer and use it in GitHub Desktop.
Save ericniebler/72e8dd28aae416894157f70ab0cce72c to your computer and use it in GitHub Desktop.
Simple coroutine task<> type
#include <cassert>
#include <mutex>
#include <condition_variable>
#include <variant>
#include <utility>
#include <exception>
#if __has_include(<coroutine>)
#include <coroutine>
namespace coro = std;
#else
#include <experimental/coroutine>
namespace coro = std::experimental;
#endif
template <class T>
struct task {
struct promise_type;
struct final_awaitable {
bool await_ready() const noexcept {
return false;
}
auto await_suspend(coro::coroutine_handle<promise_type> h) const noexcept {
return h.promise().parent_;
}
void await_resume() const noexcept {
}
};
struct promise_type {
task get_return_object() noexcept {
return task(coro::coroutine_handle<promise_type>::from_promise(*this));
}
coro::suspend_always initial_suspend() noexcept {
return {};
}
final_awaitable final_suspend() noexcept {
return {};
}
void unhandled_exception() noexcept {
data_.template emplace<2>(std::current_exception());
}
void return_value(T value) noexcept {
data_.template emplace<1>(std::move(value));
}
std::variant<std::monostate, T, std::exception_ptr> data_{};
coro::coroutine_handle<> parent_{};
};
task(task&& that) noexcept
: coro_(std::exchange(that.coro_, {}))
{}
~task() {
if (coro_)
coro_.destroy();
}
struct task_awaitable {
task& t;
bool await_ready() const noexcept {
return false;
}
auto await_suspend(coro::coroutine_handle<> parent) noexcept {
t.coro_.promise().parent_ = parent;
return t.coro_;
}
T await_resume() const {
if (t.coro_.promise().data_.index() == 2)
std::rethrow_exception(std::get<2>(t.coro_.promise().data_));
return std::get<T>(t.coro_.promise().data_);
}
};
friend task_awaitable operator co_await(task&& t) noexcept {
return task_awaitable{t};
}
private:
explicit task(coro::coroutine_handle<promise_type> coro) noexcept
: coro_(coro)
{}
coro::coroutine_handle<promise_type> coro_;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment