Last active
January 20, 2021 23:50
-
-
Save ericniebler/72e8dd28aae416894157f70ab0cce72c to your computer and use it in GitHub Desktop.
Simple coroutine task<> type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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