Skip to content

Instantly share code, notes, and snippets.

@imoldfella
Created December 15, 2017 20:18
Show Gist options
  • Select an option

  • Save imoldfella/efe5065620b193c3c12f29a99f96374c to your computer and use it in GitHub Desktop.

Select an option

Save imoldfella/efe5065620b193c3c12f29a99f96374c to your computer and use it in GitHub Desktop.
#include "stdafx.h"
#include <experimental/coroutine>
using namespace std::experimental;
using namespace std;
template<class T>
struct gen
{
struct promise_type
{
uint64_t* tid_;
T const* current_value;
auto initial_suspend() { return suspend_always(); }
auto final_suspend() { return suspend_always(); }
auto yield_value(T const & x)
{
current_value = &x;
return suspend_always();
}
gen get_return_object()
{
return gen(coroutine_handle<promise_type>::from_promise(*this));
}
void unhandled_exception() { std::terminate(); }
};
gen(coroutine_handle<promise_type> x)
: handle(x)
{}
coroutine_handle<promise_type> handle;
gen(const gen& x)
{
handle = x.handle;
}
struct iterator
{
using iterator_category = input_iterator_tag;
using difference_type = ptrdiff_t;
using value_type = T;
using reference = T const &;
using pointer = T const *;
coroutine_handle<promise_type> _Coro = nullptr;
iterator() = default;
iterator(nullptr_t) : _Coro(nullptr)
{
}
iterator(coroutine_handle<promise_type> _CoroArg) : _Coro(_CoroArg)
{
}
iterator &operator++()
{
_Coro.resume();
if (_Coro.done())
_Coro = nullptr;
return *this;
}
void operator++(int)
{
// This postincrement operator meets the requirements of the Ranges TS
// InputIterator concept, but not those of Standard C++ InputIterator.
++*this;
}
bool operator==(iterator const &_Right) const
{
return _Coro == _Right._Coro;
}
bool operator!=(iterator const &_Right) const
{
return !(*this == _Right);
}
reference operator*() const
{
return *_Coro.promise().current_value;
}
pointer operator->() const
{
return &_Coro.promise().current_value;
}
};
iterator begin()
{
if (handle) {
handle.resume();
if (handle.done())
return { nullptr };
}
return { handle };
}
iterator end()
{
return { nullptr };
}
};
// this coroutine could be stolen by another thread
// which will then insert its own tid into the coroutine
// before resuming it.
gen<uint64_t> foo()
{
uint64_t tid;
co_yield (uint64_t)&tid;
co_yield tid + 2;
co_yield tid + 3;
co_yield tid + 4;
co_return;
}
int main(int, char*[])
{
auto h = foo().handle;
h.resume();
h.promise().tid_ = (uint64_t*)*h.promise().current_value;
// it would be much better if we could divide the coroutine arguments
// between ones that are captured at initialization, and those that
// provided at resume(), like h.resume(20);
*h.promise().tid_ = 10;
h.resume();
std::cout << *h.promise().current_value << std::endl;
std::thread([&]() {
*h.promise().tid_ = 20;
h.resume();
std::cout << *h.promise().current_value << std::endl;
}).join();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment