1
+ //
2
+ // Created by konstantin on 27.07.24.
3
+ //
4
+
5
+ #include < cassert>
6
+ #include < coroutine>
7
+ #include < iostream>
8
+ #include < unordered_map>
9
+
10
+ #include " generator.h"
11
+
12
+ struct Resumable final {
13
+ struct promise_type {
14
+ using coro_handle = std::coroutine_handle<promise_type>;
15
+
16
+ size_t current_value{};
17
+
18
+ std::suspend_always yield_value (const size_t pos) {
19
+ current_value = pos;
20
+ return {};
21
+ }
22
+
23
+ auto get_return_object () { return coro_handle ::from_promise (*this ); }
24
+
25
+ std::suspend_always initial_suspend () { return {}; }
26
+
27
+ std::suspend_always final_suspend () noexcept { return {}; }
28
+
29
+ auto unhandled_exception () { std::terminate (); }
30
+ };
31
+
32
+ Resumable (promise_type::coro_handle handle) : handle_(handle) {}
33
+
34
+ ~Resumable () {
35
+ if (handle_) handle_.destroy ();
36
+ }
37
+
38
+ promise_type::coro_handle handle () {
39
+ promise_type::coro_handle h = handle_;
40
+ handle_ = nullptr ;
41
+ return h;
42
+ }
43
+
44
+ bool resume () {
45
+ if (handle_) handle_.resume ();
46
+ return !handle_.done ();
47
+ }
48
+
49
+ private:
50
+ promise_type::coro_handle handle_;
51
+ };
52
+
53
+ using coro_t = std::coroutine_handle<>;
54
+
55
+ enum class Sym : char { A, B, Term };
56
+ enum class State { A, B };
57
+
58
+ Generator<Sym> input_seq (std::string seq) {
59
+ for (char c : seq) {
60
+ switch (c) {
61
+ case ' a' :
62
+ co_yield Sym::A;
63
+ break ;
64
+ case ' b' :
65
+ co_yield Sym::B;
66
+ break ;
67
+ default :
68
+ co_yield Sym::Term;
69
+ break ;
70
+ }
71
+ }
72
+ for (;;) {
73
+ co_yield Sym::Term;
74
+ }
75
+ }
76
+
77
+ template <typename F, typename SM>
78
+ struct stm_awaiter : public F {
79
+ SM& stm;
80
+ stm_awaiter (F f, SM& stm) : F(f), stm(stm) {}
81
+
82
+ bool await_ready () const noexcept { return false ; }
83
+ coro_t await_suspend (std::coroutine_handle<>) noexcept {
84
+ stm.gennext ();
85
+ auto sym = stm.genval ();
86
+ auto new_state = F::operator ()(sym);
87
+ return stm[new_state];
88
+ }
89
+ bool await_resume () const noexcept { return stm.genval () == Sym::Term; }
90
+ };
91
+
92
+ template <class State , class Sym >
93
+ class StateMachine final {
94
+ public:
95
+ StateMachine (Generator<Sym> gen) : gen(std::move(gen)) {}
96
+
97
+ coro_t operator [](State s) { return states[s]; }
98
+
99
+ template <typename F>
100
+ auto get_awaiter (F transition) {
101
+ return stm_awaiter (transition, *this );
102
+ }
103
+
104
+ template <class F >
105
+ void add_state (State state, F stf) {
106
+ states[state] = stf (*this ).handle ();
107
+ }
108
+
109
+ void run (State initial) {
110
+ current_state = initial;
111
+ states[initial].resume ();
112
+ }
113
+
114
+ Sym genval () const { return gen.current_value (); }
115
+
116
+ void gennext () { gen.move_next (); }
117
+
118
+ State current () const { return current_state; }
119
+
120
+ private:
121
+ State current_state;
122
+ std::unordered_map<State, coro_t > states;
123
+ Generator<Sym> gen;
124
+ };
125
+
126
+ using stm_t = StateMachine<State, Sym>;
127
+
128
+ Resumable StateA (stm_t & stm) {
129
+ auto transmition = [](auto sym) {
130
+ if (sym == Sym::B) {
131
+ return State::B;
132
+ }
133
+ return State::A;
134
+ };
135
+ for (;;) {
136
+ std::cout << " State A" << std::endl;
137
+ bool finish = co_await stm.get_awaiter (transmition);
138
+ if (finish) {
139
+ break ;
140
+ }
141
+ }
142
+ }
143
+
144
+ Resumable StateB (stm_t & stm) {
145
+ auto transmition = [](auto sym) {
146
+ if (sym == Sym::A) {
147
+ return State::A;
148
+ }
149
+ return State::B;
150
+ };
151
+ for (;;) {
152
+ std::cout << " State B" << std::endl;
153
+ bool finish = co_await stm.get_awaiter (transmition);
154
+ if (finish) {
155
+ break ;
156
+ }
157
+ }
158
+ }
159
+
160
+ int main () {
161
+ auto gen = input_seq (" aaabbaba" );
162
+ stm_t stm (std::move (gen));
163
+ stm.add_state (State::A, StateA);
164
+ stm.add_state (State::B, StateB);
165
+
166
+ stm.run (State::A);
167
+
168
+ auto curr = stm.current ();
169
+ assert (curr == State::A);
170
+ }
0 commit comments