[709e0e0] | 1 | #include <cassert> |
---|
| 2 | #include <cstdlib> |
---|
| 3 | #include <iostream> |
---|
| 4 | #include <experimental/coroutine> |
---|
| 5 | #include <unistd.h> |
---|
| 6 | |
---|
| 7 | int random(int max) { |
---|
| 8 | return std::rand() % max; |
---|
| 9 | } |
---|
| 10 | |
---|
| 11 | struct Prod; |
---|
| 12 | struct Cons; |
---|
| 13 | |
---|
[ae6b6cf] | 14 | struct resumable { |
---|
| 15 | virtual resumable * resume() = 0; |
---|
| 16 | }; |
---|
| 17 | |
---|
| 18 | struct Prod : public resumable { |
---|
[709e0e0] | 19 | struct local { |
---|
| 20 | Cons * c; |
---|
| 21 | int N, money, receipt; |
---|
| 22 | }; |
---|
| 23 | |
---|
| 24 | struct promise_type { |
---|
| 25 | local _l; |
---|
[ae6b6cf] | 26 | resumable * next; |
---|
[709e0e0] | 27 | |
---|
| 28 | Prod get_return_object() { |
---|
| 29 | return Prod(std::experimental::coroutine_handle<promise_type>::from_promise(*this)); |
---|
| 30 | } |
---|
| 31 | |
---|
| 32 | auto initial_suspend() { return std::experimental::suspend_never(); } |
---|
| 33 | auto final_suspend() { return std::experimental::suspend_always(); } |
---|
| 34 | |
---|
| 35 | void return_void() {} |
---|
| 36 | void unhandled_exception() {} |
---|
| 37 | }; |
---|
| 38 | |
---|
| 39 | struct data { |
---|
| 40 | promise_type * _promise = nullptr; |
---|
| 41 | bool await_ready() noexcept { return false; } |
---|
| 42 | void await_suspend(std::experimental::coroutine_handle<promise_type> _coroutine) noexcept { |
---|
| 43 | _promise = &_coroutine.promise(); |
---|
| 44 | } |
---|
| 45 | local & await_resume() noexcept { assert(_promise); return _promise->_l; } |
---|
| 46 | }; |
---|
| 47 | |
---|
| 48 | std::experimental::coroutine_handle<promise_type> _coroutine = nullptr; |
---|
| 49 | |
---|
| 50 | explicit Prod(std::experimental::coroutine_handle<promise_type> coroutine) |
---|
| 51 | : _coroutine(coroutine) |
---|
| 52 | {} |
---|
| 53 | |
---|
| 54 | ~Prod() { |
---|
| 55 | if(_coroutine) { _coroutine.destroy(); } |
---|
| 56 | } |
---|
| 57 | |
---|
| 58 | Prod() = default; |
---|
| 59 | Prod(Prod const &) = delete; |
---|
| 60 | Prod& operator=(Prod const &) = delete; |
---|
| 61 | |
---|
| 62 | Prod(Prod&& other) { |
---|
| 63 | std::swap(_coroutine, other._coroutine); |
---|
| 64 | } |
---|
| 65 | |
---|
| 66 | Prod& operator=(Prod&& other) { |
---|
| 67 | if(&other != this) { |
---|
| 68 | _coroutine = other._coroutine; |
---|
| 69 | other._coroutine = nullptr; |
---|
| 70 | } |
---|
| 71 | return *this; |
---|
| 72 | } |
---|
| 73 | |
---|
| 74 | static Prod main(); |
---|
| 75 | |
---|
[ae6b6cf] | 76 | struct payment_return; |
---|
| 77 | |
---|
| 78 | payment_return payment(int money); |
---|
[709e0e0] | 79 | |
---|
| 80 | auto start(int N, Cons & c) { |
---|
| 81 | _coroutine.promise()._l.c = &c; |
---|
| 82 | _coroutine.promise()._l.N = N; |
---|
| 83 | _coroutine.promise()._l.receipt = 0; |
---|
[ae6b6cf] | 84 | } |
---|
| 85 | |
---|
| 86 | virtual resumable * resume() override final { |
---|
[709e0e0] | 87 | _coroutine.resume(); |
---|
[ae6b6cf] | 88 | return _coroutine.promise().next; |
---|
[709e0e0] | 89 | } |
---|
| 90 | }; |
---|
| 91 | |
---|
[ae6b6cf] | 92 | struct Cons : public resumable { |
---|
[709e0e0] | 93 | struct local { |
---|
| 94 | Prod * p; |
---|
| 95 | int p1, p2, status; |
---|
| 96 | bool done; |
---|
| 97 | }; |
---|
| 98 | |
---|
| 99 | struct promise_type { |
---|
| 100 | local _l; |
---|
[ae6b6cf] | 101 | resumable * next; |
---|
[709e0e0] | 102 | |
---|
| 103 | Cons get_return_object() { |
---|
| 104 | return Cons(std::experimental::coroutine_handle<promise_type>::from_promise(*this)); |
---|
| 105 | } |
---|
| 106 | |
---|
| 107 | auto initial_suspend() { return std::experimental::suspend_never(); } |
---|
| 108 | auto final_suspend() { return std::experimental::suspend_always(); } |
---|
| 109 | |
---|
| 110 | void return_void() {} |
---|
| 111 | void unhandled_exception() {} |
---|
| 112 | }; |
---|
| 113 | |
---|
| 114 | struct data { |
---|
| 115 | Prod * _p; |
---|
| 116 | data(Prod & prod) : _p(&prod) {} |
---|
| 117 | promise_type * _promise = nullptr; |
---|
| 118 | bool await_ready() noexcept { return false; } |
---|
| 119 | void await_suspend(std::experimental::coroutine_handle<promise_type> _coroutine) noexcept { |
---|
| 120 | _promise = &_coroutine.promise(); |
---|
| 121 | } |
---|
| 122 | local & await_resume() noexcept { assert(_promise); _promise->_l.p = _p; return _promise->_l; } |
---|
| 123 | }; |
---|
| 124 | |
---|
| 125 | std::experimental::coroutine_handle<promise_type> _coroutine = nullptr; |
---|
| 126 | |
---|
| 127 | explicit Cons(std::experimental::coroutine_handle<promise_type> coroutine) |
---|
| 128 | : _coroutine(coroutine) |
---|
| 129 | {} |
---|
| 130 | |
---|
| 131 | ~Cons() { |
---|
| 132 | if(_coroutine) { _coroutine.destroy(); } |
---|
| 133 | } |
---|
| 134 | |
---|
| 135 | Cons() = default; |
---|
| 136 | Cons(Cons const &) = delete; |
---|
| 137 | Cons& operator=(Cons const &) = delete; |
---|
| 138 | |
---|
| 139 | Cons(Cons&& other) { |
---|
| 140 | std::swap(_coroutine, other._coroutine); |
---|
| 141 | } |
---|
| 142 | |
---|
| 143 | Cons& operator=(Cons&& other) { |
---|
| 144 | if(&other != this) { |
---|
| 145 | _coroutine = other._coroutine; |
---|
| 146 | other._coroutine = nullptr; |
---|
| 147 | } |
---|
| 148 | return *this; |
---|
| 149 | } |
---|
| 150 | |
---|
| 151 | static Cons main( Prod & prod ); |
---|
| 152 | |
---|
| 153 | auto deliver(int p1, int p2) { |
---|
| 154 | _coroutine.promise()._l.p1 = p1; |
---|
| 155 | _coroutine.promise()._l.p2 = p2; |
---|
| 156 | |
---|
| 157 | struct ret { |
---|
| 158 | int _status; |
---|
[ae6b6cf] | 159 | Cons * c; |
---|
[709e0e0] | 160 | bool await_ready() { return false; } |
---|
[ae6b6cf] | 161 | void await_suspend(std::experimental::coroutine_handle<Prod::promise_type> _coroutine) { |
---|
| 162 | _coroutine.promise().next = c; |
---|
| 163 | } |
---|
[709e0e0] | 164 | int await_resume() { return _status; } |
---|
| 165 | }; |
---|
[ae6b6cf] | 166 | return ret{ _coroutine.promise()._l.status, this }; |
---|
[709e0e0] | 167 | } |
---|
| 168 | |
---|
| 169 | auto stop() { |
---|
| 170 | _coroutine.promise()._l.done = true; |
---|
| 171 | struct ret { |
---|
[ae6b6cf] | 172 | Cons * c; |
---|
| 173 | Prod::promise_type * _promise; |
---|
[709e0e0] | 174 | bool await_ready() { return false; } |
---|
[ae6b6cf] | 175 | void await_suspend(std::experimental::coroutine_handle<Prod::promise_type> _coroutine) { |
---|
| 176 | _promise = &_coroutine.promise(); |
---|
| 177 | _promise->next = c; |
---|
| 178 | } |
---|
| 179 | void await_resume() { |
---|
| 180 | _promise->next = nullptr; |
---|
| 181 | } |
---|
[709e0e0] | 182 | }; |
---|
[ae6b6cf] | 183 | return ret{this, nullptr}; |
---|
[709e0e0] | 184 | } |
---|
[ae6b6cf] | 185 | |
---|
| 186 | virtual resumable * resume() override final { |
---|
| 187 | _coroutine.resume(); |
---|
| 188 | return _coroutine.promise().next; |
---|
| 189 | } |
---|
| 190 | }; |
---|
| 191 | |
---|
| 192 | struct Prod::payment_return { |
---|
| 193 | int _receipt; |
---|
| 194 | Prod * p; |
---|
| 195 | bool await_ready() { return false; } |
---|
| 196 | void await_suspend(std::experimental::coroutine_handle<Cons::promise_type> _coroutine) { |
---|
| 197 | _coroutine.promise().next = p; |
---|
| 198 | } |
---|
| 199 | int await_resume() { return _receipt; } |
---|
[709e0e0] | 200 | }; |
---|
| 201 | |
---|
[ae6b6cf] | 202 | Prod::payment_return Prod::payment(int money) { |
---|
| 203 | _coroutine.promise()._l.money = money; |
---|
| 204 | return payment_return{ _coroutine.promise()._l.receipt, this }; |
---|
| 205 | } |
---|
| 206 | |
---|
[709e0e0] | 207 | Prod Prod::main() { |
---|
| 208 | auto & p = co_await Prod::data(); |
---|
| 209 | for(int i = 0; i < p.N; i++) { |
---|
| 210 | int p1 = random(100), p2 = random(100); |
---|
[ae6b6cf] | 211 | std::cout << p1 << " " << p2 << std::endl; |
---|
[709e0e0] | 212 | int status = co_await p.c->deliver(p1, p2); |
---|
[ae6b6cf] | 213 | std::cout << " $" << p.money << std::endl << status << std::endl; |
---|
[709e0e0] | 214 | p.receipt += 1; |
---|
| 215 | } |
---|
| 216 | co_await p.c->stop(); |
---|
[ae6b6cf] | 217 | std::cout << "prod stops" << std::endl; |
---|
[709e0e0] | 218 | } |
---|
| 219 | |
---|
| 220 | Cons Cons::main( Prod & prod ) { |
---|
| 221 | auto & c = co_await Cons::data( prod ); |
---|
| 222 | int money = 1, receipt; |
---|
| 223 | for(;!c.done ;) { |
---|
[ae6b6cf] | 224 | std::cout << c.p1 << " " << c.p2 << std::endl; |
---|
| 225 | std::cout << " $ " << money << std::endl; |
---|
[709e0e0] | 226 | c.status += 1; |
---|
| 227 | receipt = co_await c.p->payment( money ); |
---|
[ae6b6cf] | 228 | std::cout << " # " << receipt << std::endl; |
---|
[709e0e0] | 229 | money += 1; |
---|
| 230 | } |
---|
[ae6b6cf] | 231 | std::cout << "cons stops" << std::endl; |
---|
| 232 | } |
---|
| 233 | |
---|
| 234 | void dispatch(resumable * r) { |
---|
| 235 | while((r = r->resume())); |
---|
[709e0e0] | 236 | } |
---|
| 237 | |
---|
| 238 | int main() { |
---|
| 239 | auto prod = Prod::main(); |
---|
| 240 | auto cons = Cons::main( prod ); |
---|
| 241 | srandom( getpid() ); |
---|
| 242 | prod.start(5, cons); |
---|
[ae6b6cf] | 243 | dispatch(&prod); |
---|
[709e0e0] | 244 | } |
---|