-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy path12_state_and_visitation.cpp
108 lines (89 loc) · 2.78 KB
/
12_state_and_visitation.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <stdexcept>
#include <variant>
namespace state {
struct Depleted {};
struct Available {
int count;
};
struct Discontinued {};
} // namespace state
using State =
std::variant<state::Depleted, state::Available, state::Discontinued>;
namespace event {
struct DeliveryArrived {
int count;
};
struct Purchased {
int count;
};
struct Discontinued {};
} // namespace event
State on_event(state::Available available, event::DeliveryArrived delivered) {
available.count += delivered.count;
return available;
}
State on_event(state::Available available, event::Purchased purchased) {
available.count -= purchased.count;
if (available.count > 0) return available;
return state::Depleted{};
}
template <typename S>
State on_event(S, event::Discontinued) {
return state::Discontinued{};
}
State on_event(state::Depleted depleted, event::DeliveryArrived delivered) {
return state::Available{delivered.count};
}
template <class... Ts>
struct overload : Ts... {
using Ts::operator()...;
};
template <class... Ts>
overload(Ts...) -> overload<Ts...>;
class ItemStateMachine {
public:
template <typename Event>
void process_event(Event &&event) {
state_ = std::visit(overload{
[&](const auto &state)
requires std::is_same_v<decltype(on_event(
state, std::forward<Event>(event))),
State>
{ return on_event(state, std::forward<Event>(event)); },
[](const auto &unsupported_state) -> State {
throw std::logic_error{"Unsupported state transition"};
}},
state_);
}
std::string report_current_state() {
return std::visit(
overload{[](const state::Available &state) -> std::string {
return std::to_string(state.count) + " items available";
},
[](const state::Depleted) -> std::string {
return "Item is temporarily out of stock";
},
[](const state::Discontinued) -> std::string {
return "Item has been discontinued";
}},
state_);
}
private:
State state_;
};
int main() {
auto fsm = ItemStateMachine{};
std::cout << fsm.report_current_state() << '\n';
fsm.process_event(event::DeliveryArrived{3});
std::cout << fsm.report_current_state() << '\n';
fsm.process_event(event::Purchased{2});
std::cout << fsm.report_current_state() << '\n';
fsm.process_event(event::DeliveryArrived{2});
std::cout << fsm.report_current_state() << '\n';
fsm.process_event(event::Purchased{3});
std::cout << fsm.report_current_state() << '\n';
fsm.process_event(event::Discontinued{});
std::cout << fsm.report_current_state() << '\n';
// fsm.process_event(event::DeliveryArrived{1});
}