Skip to content

Commit 5e10ecc

Browse files
committed
add stm
1 parent 92e3d76 commit 5e10ecc

File tree

4 files changed

+223
-40
lines changed

4 files changed

+223
-40
lines changed

example/coro/example_natural_nums.cpp

+1-40
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,7 @@
55
#include <coroutine>
66
#include <iostream>
77

8-
template <typename T>
9-
struct Generator {
10-
struct promise_type {
11-
using coro_handle = std::coroutine_handle<promise_type>;
12-
13-
T current_value;
14-
auto yield_value(T value) {
15-
current_value = value;
16-
return std::suspend_always();
17-
}
18-
19-
std::suspend_always initial_suspend() { return {}; }
20-
21-
std::suspend_always final_suspend() noexcept { return {}; }
22-
23-
auto get_return_object() { return coro_handle ::from_promise(*this); }
24-
25-
auto unhandled_exception() { std::terminate(); }
26-
};
27-
28-
Generator(promise_type::coro_handle handle) : handle_(handle) {}
29-
30-
~Generator() noexcept {
31-
if (handle_) handle_.destroy();
32-
}
33-
34-
bool resume() {
35-
if (!handle_.done()) handle_();
36-
return !handle_.done();
37-
}
38-
39-
T current_value() const { return handle_.promise().current_value; }
40-
41-
bool move_next() const {
42-
return (handle_ ? (handle_.resume(), !handle_.done()) : false);
43-
}
44-
45-
private:
46-
promise_type::coro_handle handle_;
47-
};
8+
#include "generator.h"
489

4910
Generator<int> natural_nums() {
5011
int num = 0;

example/coro/example_stm.cpp

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
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+
}

example/coro/generator.h

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// Created by konstantin on 27.07.24.
3+
//
4+
5+
#include <coroutine>
6+
#include <iostream>
7+
8+
template <typename T>
9+
struct Generator {
10+
struct promise_type {
11+
using coro_handle = std::coroutine_handle<promise_type>;
12+
13+
T current_value;
14+
auto yield_value(T value) {
15+
current_value = value;
16+
return std::suspend_always();
17+
}
18+
19+
std::suspend_always initial_suspend() { return {}; }
20+
21+
std::suspend_always final_suspend() noexcept { return {}; }
22+
23+
auto get_return_object() { return coro_handle ::from_promise(*this); }
24+
25+
auto unhandled_exception() { std::terminate(); }
26+
};
27+
28+
Generator(promise_type::coro_handle handle) : handle_(handle) {}
29+
30+
~Generator() noexcept {
31+
if (handle_) handle_.destroy();
32+
}
33+
34+
bool resume() {
35+
if (!handle_.done()) handle_();
36+
return !handle_.done();
37+
}
38+
39+
T current_value() const { return handle_.promise().current_value; }
40+
41+
bool move_next() const {
42+
return (handle_ ? (handle_.resume(), !handle_.done()) : false);
43+
}
44+
45+
private:
46+
promise_type::coro_handle handle_;
47+
};
48+

example/coro/meson.build

+4
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,7 @@ example_subscription = executable('example_subscription',
2323
example_mutex = executable('example_mutex',
2424
'example_mutex.cpp'
2525
)
26+
27+
example_stm = executable('example_stm',
28+
'example_stm.cpp'
29+
)

0 commit comments

Comments
 (0)