#include #include #include #include #include int random(int max) { return std::rand() % max; } struct Prod; struct Cons; struct Prod { struct local { Cons * c; int N, money, receipt; }; struct promise_type { local _l; Prod get_return_object() { return Prod(std::experimental::coroutine_handle::from_promise(*this)); } auto initial_suspend() { return std::experimental::suspend_never(); } auto final_suspend() { return std::experimental::suspend_always(); } void return_void() {} void unhandled_exception() {} }; struct data { promise_type * _promise = nullptr; bool await_ready() noexcept { return false; } void await_suspend(std::experimental::coroutine_handle _coroutine) noexcept { _promise = &_coroutine.promise(); } local & await_resume() noexcept { assert(_promise); return _promise->_l; } }; std::experimental::coroutine_handle _coroutine = nullptr; explicit Prod(std::experimental::coroutine_handle coroutine) : _coroutine(coroutine) {} ~Prod() { if(_coroutine) { _coroutine.destroy(); } } Prod() = default; Prod(Prod const &) = delete; Prod& operator=(Prod const &) = delete; Prod(Prod&& other) { std::swap(_coroutine, other._coroutine); } Prod& operator=(Prod&& other) { if(&other != this) { _coroutine = other._coroutine; other._coroutine = nullptr; } return *this; } static Prod main(); auto payment(int money) { _coroutine.promise()._l.money = money; struct ret { int _receipt; bool await_ready() { return false; } void await_suspend(std::experimental::coroutine_handle<>) {} int await_resume() { return _receipt; } }; return ret{ _coroutine.promise()._l.receipt }; } auto start(int N, Cons & c) { _coroutine.promise()._l.c = &c; _coroutine.promise()._l.N = N; _coroutine.promise()._l.receipt = 0; _coroutine.resume(); } }; struct Cons { struct local { Prod * p; int p1, p2, status; bool done; }; struct promise_type { local _l; Cons get_return_object() { return Cons(std::experimental::coroutine_handle::from_promise(*this)); } auto initial_suspend() { return std::experimental::suspend_never(); } auto final_suspend() { return std::experimental::suspend_always(); } void return_void() {} void unhandled_exception() {} }; struct data { Prod * _p; data(Prod & prod) : _p(&prod) {} promise_type * _promise = nullptr; bool await_ready() noexcept { return false; } void await_suspend(std::experimental::coroutine_handle _coroutine) noexcept { _promise = &_coroutine.promise(); } local & await_resume() noexcept { assert(_promise); _promise->_l.p = _p; return _promise->_l; } }; std::experimental::coroutine_handle _coroutine = nullptr; explicit Cons(std::experimental::coroutine_handle coroutine) : _coroutine(coroutine) {} ~Cons() { if(_coroutine) { _coroutine.destroy(); } } Cons() = default; Cons(Cons const &) = delete; Cons& operator=(Cons const &) = delete; Cons(Cons&& other) { std::swap(_coroutine, other._coroutine); } Cons& operator=(Cons&& other) { if(&other != this) { _coroutine = other._coroutine; other._coroutine = nullptr; } return *this; } static Cons main( Prod & prod ); auto deliver(int p1, int p2) { _coroutine.promise()._l.p1 = p1; _coroutine.promise()._l.p2 = p2; struct ret { int _status; bool await_ready() { return false; } void await_suspend(std::experimental::coroutine_handle<>) {} int await_resume() { return _status; } }; return ret{ _coroutine.promise()._l.status }; } auto stop() { _coroutine.promise()._l.done = true; struct ret { bool await_ready() { return false; } void await_suspend(std::experimental::coroutine_handle<>) {} void await_resume() {} }; return ret{}; } }; Prod Prod::main() { auto & p = co_await Prod::data(); for(int i = 0; i < p.N; i++) { int p1 = random(100), p2 = random(100); std::cout << p1 << " " << p2; int status = co_await p.c->deliver(p1, p2); std::cout << " $" << p.money << std::endl << status; p.receipt += 1; } co_await p.c->stop(); std::cout << "prod stops"; } Cons Cons::main( Prod & prod ) { auto & c = co_await Cons::data( prod ); int money = 1, receipt; for(;!c.done ;) { std::cout << c.p1 << " " << c.p2 << std::endl << " $" << money; c.status += 1; receipt = co_await c.p->payment( money ); std::cout << " #" << receipt; money += 1; } std::cout << "const stops"; } int main() { auto prod = Prod::main(); auto cons = Cons::main( prod ); srandom( getpid() ); prod.start(5, cons); }