Last active
November 26, 2016 15:04
-
-
Save Voultapher/2cac627083b82b1b5e6c6f67e9b244d1 to your computer and use it in GitHub Desktop.
CoroutinesBasics
This file contains 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 <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