Corium 1.1.0
High-Performance Zero-Heap C++20 MPSC Application Runtime
Loading...
Searching...
No Matches
StateMachine.hpp
Go to the documentation of this file.
1
7#pragma once
8
9#include <type_traits>
10#include <utility>
11#include <variant>
12
14
15namespace corium::fsm {
16
17namespace detail {
18
19template <typename State, typename Event>
20constexpr void call_on_exit(State& s, const Event& e) {
21 if constexpr (requires { s.onExit(e); }) {
22 s.onExit(e);
23 } else if constexpr (requires { s.onExit(); }) {
24 s.onExit();
25 }
26}
27
28template <typename State, typename Event>
29constexpr void call_on_enter(State& s, const Event& e) {
30 if constexpr (requires { s.onEnter(e); }) {
31 s.onEnter(e);
32 } else if constexpr (requires { s.onEnter(); }) {
33 s.onEnter();
34 }
35}
36
37template <typename Guard, typename State, typename Event>
38constexpr bool evaluate_guard(const Guard& guard, const State& s, const Event& e) {
39 if constexpr (std::is_invocable_r_v<bool, Guard, const State&, const Event&>) {
40 return guard(s, e);
41 } else if constexpr (std::is_invocable_r_v<bool, Guard, const Event&>) {
42 return guard(e);
43 } else if constexpr (std::is_invocable_r_v<bool, Guard>) {
44 return guard();
45 } else {
46 return true;
47 }
48}
49
50template <typename Action, typename From, typename Event, typename To>
51constexpr void execute_action(const Action& action, From& from, const Event& e, To& to) {
52 if constexpr (std::is_invocable_v<Action, From&, const Event&, To&>) {
53 action(from, e, to);
54 } else if constexpr (std::is_invocable_v<Action, From&, const Event&>) {
55 action(from, e);
56 } else if constexpr (std::is_invocable_v<Action, const Event&>) {
57 action(e);
58 } else if constexpr (std::is_invocable_v<Action>) {
59 action();
60 }
61}
62
63template <typename T>
65 static constexpr bool value = false;
66};
67
68template <typename T>
69 requires requires { { T::is_internal } -> std::convertible_to<bool>; }
71 static constexpr bool value = T::is_internal;
72};
73
74template <typename T>
76
77} // namespace detail
78
84template <
85 typename Table,
86 typename InitialState,
87 typename... OtherStates
88>
90public:
91 using StateVariant = std::variant<InitialState, OtherStates...>;
92 using TransitionTableType = Table;
93
94 constexpr StateMachine()
95 : _state(InitialState{})
96 {
97 detail::call_on_enter(std::get<InitialState>(_state), int{0});
98 }
99
100 template <typename State>
101 requires (std::is_constructible_v<StateVariant, State>)
102 constexpr explicit StateMachine(State&& initial)
103 : _state(std::forward<State>(initial))
104 {
105 std::visit([](auto& s) {
106 detail::call_on_enter(s, int{0});
107 }, _state);
108 }
109
111 template <typename State>
112 [[nodiscard]] constexpr bool is() const noexcept {
113 return std::holds_alternative<State>(_state);
114 }
115
117 template <typename State>
118 [[nodiscard]] constexpr State& as() {
119 return std::get<State>(_state);
120 }
121
123 template <typename State>
124 [[nodiscard]] constexpr const State& as() const {
125 return std::get<State>(_state);
126 }
127
129 [[nodiscard]] constexpr const StateVariant& state() const noexcept {
130 return _state;
131 }
132
134 [[nodiscard]] constexpr StateVariant& state() noexcept {
135 return _state;
136 }
137
142 template <typename Event>
143 bool process_event(const Event& event) {
144 return std::visit([this, &event](auto& currentState) -> bool {
145 using CurrentStateType = std::decay_t<decltype(currentState)>;
146 return this->try_transition<CurrentStateType, Event>(currentState, event, Table{});
147 }, _state);
148 }
149
150private:
151 template <typename CurrentState, typename Event, typename... Transitions>
152 bool try_transition(CurrentState& current, const Event& event, TransitionTable<Transitions...>) {
153 return (try_single_transition<CurrentState, Event, Transitions>(current, event, Transitions{}) || ...);
154 }
155
156 template <typename CurrentState, typename Event, typename Trans>
157 bool try_single_transition(CurrentState& current, const Event& event, const Trans& trans) {
158 if constexpr (std::is_same_v<CurrentState, typename Trans::FromState> &&
159 std::is_same_v<std::decay_t<Event>, typename Trans::EventType>) {
160 if (detail::evaluate_guard(trans.guard, current, event)) {
161 if constexpr (detail::is_internal_transition_v<Trans>) {
162 detail::execute_action(trans.action, current, event, current);
163 } else {
164 detail::call_on_exit(current, event);
165 typename Trans::ToState nextState{};
166 detail::execute_action(trans.action, current, event, nextState);
167 _state = std::move(nextState);
168 detail::call_on_enter(std::get<typename Trans::ToState>(_state), event);
169 }
170 return true;
171 }
172 }
173 return false;
174 }
175
176 StateVariant _state;
177};
178
179} // namespace corium::fsm
Declarative compile-time transition rules, internal transitions, and action lists.
Zero-heap, compile-time Finite State Machine.
Definition StateMachine.hpp:89
Table TransitionTableType
Definition StateMachine.hpp:92
std::variant< InitialState, OtherStates... > StateVariant
Definition StateMachine.hpp:91
constexpr StateMachine()
Definition StateMachine.hpp:94
constexpr const State & as() const
Access const reference to current state as type State.
Definition StateMachine.hpp:124
constexpr StateMachine(State &&initial)
Definition StateMachine.hpp:102
bool process_event(const Event &event)
Process an incoming event through the state machine transition table.
Definition StateMachine.hpp:143
constexpr State & as()
Access reference to current state as type State (throws std::bad_variant_access if mismatch).
Definition StateMachine.hpp:118
constexpr StateVariant & state() noexcept
Access active state variant.
Definition StateMachine.hpp:134
constexpr bool is() const noexcept
Check if current active state matches type State.
Definition StateMachine.hpp:112
constexpr const StateVariant & state() const noexcept
Access active state variant.
Definition StateMachine.hpp:129
constexpr void call_on_enter(State &s, const Event &e)
Definition StateMachine.hpp:29
constexpr bool evaluate_guard(const Guard &guard, const State &s, const Event &e)
Definition StateMachine.hpp:38
constexpr bool is_internal_transition_v
Definition StateMachine.hpp:75
constexpr void call_on_exit(State &s, const Event &e)
Definition StateMachine.hpp:20
constexpr void execute_action(const Action &action, From &from, const Event &e, To &to)
Definition StateMachine.hpp:51
Definition HistoryState.hpp:9
DefaultEvents Event
Alias for DefaultEvents.
Definition Events.hpp:65
Compile-time table containing all valid state transitions.
Definition Transition.hpp:103
Definition StateMachine.hpp:64
static constexpr bool value
Definition StateMachine.hpp:65