SimpleStatemachine.h
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package ARCHES::ArmarXObjects::ARCHESArmar6GraspCandidateExecutor
17 * @author Raphael Grimm ( raphael dot grimm at kit dot edu )
18 * @date 2019
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23#pragma once
24
25#include <functional>
26#include <type_traits>
27
31
32namespace armarx
33{
34 template <class EnumT>
36
37 template <class EnumT>
38 class state_t
39 {
40 static_assert(std::is_enum_v<EnumT>);
41
42 public:
43 using enum_t = EnumT;
44
45 // *INDENT-OFF*
46 auto
48 {
49 return _previous_state;
50 }
51
52 auto
54 {
55 return _current_state;
56 }
57
58 auto
60 {
61 return _is_initial_state;
62 }
63
64 void
66 {
67 _quit = true;
68 }
69
70 // *INDENT-ON*
71 private:
72 friend class simple_state_machine<enum_t>;
73 enum_t _previous_state;
74 enum_t _current_state;
75 bool _quit{false};
76 bool _is_initial_state{true};
77 };
78
79 template <class EnumT>
81 {
82 static_assert(std::is_enum_v<EnumT>);
83
84 public:
85 using enum_t = EnumT;
88
89 using state_function_t = std::function<enum_t(state_t&)>;
90 using transition_function_t = std::function<void(const state_t&)>;
91 using hook_function_t = std::function<void(const state_t&)>;
92
93
94 public:
95 static void
97 {
98 }
99
100 template <enum_t state>
101 void
103 {
104 ARMARX_CHECK_EXPRESSION(!_states.count(state));
105 _states[state] = std::move(f);
106 }
107
108 template <enum_t state0, enum_t state1>
109 void
111 {
112 ARMARX_CHECK_EXPRESSION(!_transitions.count({state0, state1}));
113 _transitions[{state0, state1}] = std::move(f);
114 }
115
116 void
118 {
119 _post_transition_callback = std::move(f);
120 }
121
122 void
124 {
125 _pre_transition_callback = std::move(f);
126 }
127
128 void
130 {
131 _post_state_exit_callback = std::move(f);
132 }
133
134 void
136 {
137 _pre_state_enter_callback = std::move(f);
138 }
139
140 template <enum_t state0>
141 state_t
143 {
145 for (const auto& [edge, _] : _transitions)
146 {
148 const auto [f, t] = edge;
149 ARMARX_CHECK_EXPRESSION(_states.count(f)) << "No state " << f;
150 ARMARX_CHECK_EXPRESSION(_states.count(t)) << "No state " << t;
151 }
152 state_t state;
153 state._previous_state = state0;
154 state._current_state = state0;
155 state._is_initial_state = true;
156 state._quit = false;
157
158 while (true)
159 {
161 _pre_state_enter_callback(state);
162 ARMARX_IMPORTANT << "Executing state '" << state._current_state << "'";
163 const auto next = _states.at(state._current_state)(state);
164 state._previous_state = state._current_state;
165 state._current_state = next;
166 state._is_initial_state = false;
167 _post_state_exit_callback(state);
168 if (state._quit)
169 {
170 break;
171 }
172 const std::pair<enum_t, enum_t> t{state._previous_state, state._current_state};
173 ARMARX_CHECK_EXPRESSION(_transitions.count(t))
174 << "No transition from " << state._previous_state << " to "
175 << state._current_state;
176 _pre_transition_callback(state);
177 ARMARX_IMPORTANT << "Taking transition '" << state._previous_state << "' -> '"
178 << state._current_state << "'";
179 _transitions.at(t)(state);
180 _post_transition_callback(state);
181 }
182 ARMARX_IMPORTANT << "Exiting while in state '" << state._current_state << "'";
183 return state;
184 }
185
186 private:
187 std::unordered_map<enum_t, state_function_t> _states;
188 std::unordered_map<std::pair<enum_t, enum_t>, transition_function_t> _transitions;
189
190 hook_function_t _pre_transition_callback = noop_transition;
191 hook_function_t _post_transition_callback = noop_transition;
192
193 hook_function_t _pre_state_enter_callback = noop_transition;
194 hook_function_t _post_state_exit_callback = noop_transition;
195 };
196} // namespace armarx
std::function< void(const state_t &)> hook_function_t
::armarx::state_t< enum_t > state_t
std::function< void(const state_t &)> transition_function_t
void set_pre_transition_callback(hook_function_t f)
void set_post_state_exit_callback(hook_function_t f)
void set_post_transition_callback(hook_function_t f)
void set_pre_state_enter_callback(hook_function_t f)
void configure_transition(transition_function_t f=noop_transition)
std::function< enum_t(state_t &)> state_function_t
simple_state_machine< enum_t > state_machine_t
void configure_state(state_function_t f)
static void noop_transition(const state_t &)
auto is_initial_state() const
auto previous_state() const
auto current_state() const
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
This file offers overloads of toIce() and fromIce() functions for STL container types.
#define ARMARX_TRACE
Definition trace.h:77