99#include < vector>
1010#include < ranges>
1111
12+ // / @brief Values injected into actions and guards.
1213using Injection = std::vector<std::any>;
14+
15+ // / @brief Optional transition action callback.
16+ // / @see std::function<void()>
1317using Action = std::optional<std::function<void ()>>;
18+
19+ // / @brief Optional guard predicate for transitions.
20+ // / @return true if transition is allowed.
1421using Guard = std::optional<std::function<bool ()>>;
1522
23+ // / @brief Forward declaration of the state machine engine.
1624template <typename Parent>
1725class SM ;
1826
27+ // / @brief Container for states, transitions, and injections of the state machine.
28+ // / @tparam Parent Type defining State and Event.
1929template <typename Parent>
2030struct StateMachineContainer {
2131 using State = typename Parent::State;
@@ -24,21 +34,44 @@ struct StateMachineContainer {
2434 using Transition = std::tuple< State, Event, State, Guard, Action, Injection >;
2535 using Anonymous = std::tuple< State, State, Guard, Action, Injection >;
2636
37+ // / @brief Current active state of the state machine.
2738 State currentState;
39+
40+ // / @brief Registered state entries with guards and entry actions.
2841 std::vector<Entry> entries;
42+
43+ // / @brief Event-driven transitions.
2944 std::vector<Transition> transitions;
45+
46+ // / @brief Automatic transitions executed without an explicit event.
3047 std::vector<Anonymous> anonymous;
48+
49+ // / @brief Values injected into callbacks during state changes.
3150 Injection injections;
3251
3352 // Member convenience methods
53+ // / @brief Trigger a state machine event.
54+ // / @tparam ExternalInjection Types of additional data to inject.
55+ // / @param event Event to trigger.
56+ // / @param args Optional injection values.
3457 template <typename ... ExternalInjection>
3558 void triggerEvent (typename Parent::Event event, ExternalInjection&&... args) {
3659 SM<Parent>::triggerEvent (event, *this , std::forward<ExternalInjection>(args)...);
3760 }
61+
62+ // / @brief Set a new state directly, bypassing events.
63+ // / @tparam ExternalInjection Types of additional data to inject.
64+ // / @param state Target state to set.
65+ // / @param args Optional injection values.
3866 template <typename ... ExternalInjection>
3967 void setState (typename Parent::State state, ExternalInjection&&... args) {
4068 SM<Parent>::setState (state, *this , std::forward<ExternalInjection>(args)...);
4169 }
70+
71+ // / @brief Run anonymous transitions until none remain.
72+ // / @tparam ExternalInjection Types of additional data to inject.
73+ // / @param args Optional injection values.
74+ // / @return true if any anonymous transition executed.
4275 template <typename ... ExternalInjection>
4376 bool runAnonymous (ExternalInjection&&... args) {
4477 return SM<Parent>::runAnonymous (*this , std::forward<ExternalInjection>(args)...);
@@ -48,13 +81,20 @@ struct StateMachineContainer {
4881template <typename Parent>
4982using StateMachine = StateMachineContainer<Parent>;
5083
84+ // / @brief State machine engine implementing transitions and state changes.
85+ // / @tparam Parent Type defining State and Event.
5186template <typename Parent>
5287class SM {
5388 public:
5489 using State = typename Parent::State;
5590 using Event = typename Parent::Event;
5691 using StateMachine = StateMachineContainer<Parent>;
5792
93+ // / @brief Process an event and transition state if matching.
94+ // / @tparam ExternalInjection Types of optional injection values.
95+ // / @param event Event to handle.
96+ // / @param sm StateMachine instance to operate on.
97+ // / @param args Additional values for injection.
5898 template <typename ... ExternalInjection>
5999 static void triggerEvent (Parent::Event event, StateMachine &sm, ExternalInjection... args) {
60100 auto it = std::ranges::find_if (sm.transitions .begin (), sm.transitions .end (), [&](const auto &t) {
@@ -69,6 +109,11 @@ class SM {
69109 while (runAnonymous (sm, std::forward<ExternalInjection>(args)...)) {}
70110 }
71111
112+ // / @brief Force set the state with injection values.
113+ // / @tparam ExternalInjection Types of optional injection values.
114+ // / @param state New state to set.
115+ // / @param sm StateMachine instance to operate on.
116+ // / @param args Additional values for injection.
72117 template <typename ... ExternalInjection>
73118 static void setState (Parent::State state, StateMachine &sm, ExternalInjection... args) {
74119 auto it = std::ranges::find_if (sm.entries .begin (), sm.entries .end (),
@@ -82,6 +127,11 @@ class SM {
82127 while (runAnonymous (sm, std::forward<ExternalInjection>(args)...)) {}
83128 }
84129
130+ // / @brief Execute an anonymous transition if the current state matches.
131+ // / @tparam ExternalInjection Types of optional injection values.
132+ // / @param sm StateMachine instance to operate on.
133+ // / @param args Additional values for injection.
134+ // / @return true if a transition occurred.
85135 template <typename ... ExternalInjection>
86136 static bool runAnonymous (StateMachine &sm, ExternalInjection... args) {
87137 auto it = std::ranges::find_if (sm.anonymous .begin (), sm.anonymous .end (),
@@ -91,20 +141,32 @@ class SM {
91141 auto [fromState, nextState, guard, action, injection] = *it;
92142 updateInjection (sm, injection, std::forward<ExternalInjection>(args)...);
93143 handleStateChange (sm, nextState, guard, action);
94- return true ;
144+ return true ;
95145 }
96- return false ;
146+ return false ;
97147 }
98148
149+ // / @brief Retrieve the current state from the state machine.
150+ // / @param sm StateMachine instance.
151+ // / @return Current active state.
99152 static Parent::State getState (StateMachine &sm) { return sm.currentState ; }
100153
101154 private:
155+ // / @brief Evaluate guard and perform state change and action.
156+ // / @param sm Instance to update.
157+ // / @param nextState State to transition to.
158+ // / @param guard Optional guard predicate.
159+ // / @param action Optional action to execute.
102160 static void handleStateChange (StateMachine &sm, Parent::State nextState, Guard guard, Action action) {
103161 if (guard && !(*guard)()) return ;
104162 sm.currentState = nextState;
105163 if (action) (*action)();
106164 }
107165
166+ // / @brief Populate the injection vector for upcoming callbacks.
167+ // / @param sm Instance whose injections will be updated.
168+ // / @param injection Predefined injection values.
169+ // / @param args Additional values to inject.
108170 template <typename ... ExternalInjection>
109171 static void updateInjection (StateMachine &sm, Injection injection, ExternalInjection &&...args) {
110172 if (!injection.empty ()) {
0 commit comments