Created
December 15, 2017 20:18
-
-
Save imoldfella/efe5065620b193c3c12f29a99f96374c to your computer and use it in GitHub Desktop.
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 "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