Skip to content

Instantly share code, notes, and snippets.

@Voultapher
Last active November 26, 2016 15:04
Show Gist options
  • Save Voultapher/2cac627083b82b1b5e6c6f67e9b244d1 to your computer and use it in GitHub Desktop.
Save Voultapher/2cac627083b82b1b5e6c6f67e9b244d1 to your computer and use it in GitHub Desktop.
CoroutinesBasics
#include <experimental\coroutine>
using namespace std::experimental;
coro_return_type<int> test()
{
int val = 0;
//return {}; // return only valid for subroutines aka functions
// works only if coro_return_type::promis_type specifies:
// coro_return_type get_return_object()
// coro_awaitable_type initial_suspend()
// coro_awaitable_type final_suspend()
co_await coro_awaitable_type{};
// works only if coro_return_type::promise_type specifies void yield_value(T val)
// yield coro_return_type::promise_type::val_type
co_yield int(3);
// works only if coro_return_type::promise_type specifies void return_value(T val)
// and not void return_void()
// return coro_return_type::promise_type::val_type
co_return int(5);
}
int main()
{
auto handle = test();
// possible if coro_return_type specifies resume()
handle.resume(); // resume co_await if coro_awaitable_type suspends
// possible if coro_return_type specifies value() and
// coro_return_type::promise_type specifies void yield_value(T val)
auto val = handle.value();
// its UB to resume a coroutine that is not suspended
handle.resume(); // resume co_yield if coro_awaitable_type suspends
// UB unless coro_return_type::promise_type final_suspend()::await_ready() returns false
auto val2 = handle.value();
// guranteed UB
handle.resume();
}
struct coro_awaitable_type
{
// all 3 functions with these return types and parameters are needed
bool await_ready(); // return if it should suspend at all
void await_suspend(coroutine_handle<>); // what should it do each suspend
void await_resume(); // what should it do each resume
};
template<typename T> class coro_return_type
{
public:
struct promise_type
{
using val_type = typename T;
T value;
coro_return_type get_return_object()
{
return coro_return_type(coroutine_handle<promise_type>::from_promise(*this));
}
coro_awaitable_type initial_suspend() { return{}; }
coro_awaitable_type final_suspend() { return{}; }
// needed if co_yield is used in a coroutine with coro_return_type as return type
void yield_value(T val) { value = val; }
// choose one return function
// #A
// needed if co_return is used in a coroutine with coro_return_type as return type
void return_value(T val) { value = val; }
// #B
// needed if no co_return is used in a coroutine with coro_return_type as return type
void return_void() {}
};
// optional default construction
coro_return_type() : _coroutine(nullptr) { }
// no copy only move
coro_return_type(const coro_return_type&) = delete;
coro_return_type(coro_return_type&& other) :
_coroutine(other._coroutine)
{
other._coroutine = nullptr;
}
coro_return_type& operator= (const coro_return_type&) = delete;
coro_return_type& operator= (coro_return_type&& other)
{
if (this != std::addressof(other))
{
_coroutine = other._coroutine;
other._coroutine = nullptr;
}
return *this;
}
// optional utility
void resume() { _coroutine.resume(); }
// works only if coro_return_type::promise_type specifies a member variable called value
T value() { return _coroutine.promise().value; }
// works only if coro_return_type::promise_type final_suspend()::await_ready() returns false
// otherwise will resume not suspended coroutine => UB
void wait()
{
while (!_coroutine.done())
_coroutine.resume();
}
bool done() const { return _coroutine.done(); }
private:
explicit coro_return_type(coroutine_handle<promise_type> coroutine) :
_coroutine(coroutine)
{ }
coroutine_handle<promise_type> _coroutine;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment