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 
32 namespace 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
53  current_state() const
54  {
55  return _current_state;
56  }
57 
58  auto
60  {
61  return _is_initial_state;
62  }
63 
64  void
65  quit()
66  {
67  _quit = true;
68  }
69 
70  // *INDENT-ON*
71  private:
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>
80  class simple_state_machine
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
142  run()
143  {
144  ARMARX_TRACE;
145  for (const auto& [edge, _] : _transitions)
146  {
147  ARMARX_TRACE;
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  {
160  ARMARX_TRACE;
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
armarx::simple_state_machine::enum_t
EnumT enum_t
Definition: SimpleStatemachine.h:85
armarx::state_t::quit
void quit()
Definition: SimpleStatemachine.h:65
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:190
armarx::simple_state_machine::transition_function_t
std::function< void(const state_t &)> transition_function_t
Definition: SimpleStatemachine.h:90
armarx::simple_state_machine::set_post_transition_callback
void set_post_transition_callback(hook_function_t f)
Definition: SimpleStatemachine.h:117
armarx::simple_state_machine::run
state_t run()
Definition: SimpleStatemachine.h:142
armarx::simple_state_machine::hook_function_t
std::function< void(const state_t &)> hook_function_t
Definition: SimpleStatemachine.h:91
armarx::simple_state_machine
Definition: SimpleStatemachine.h:35
trace.h
armarx::state_t::current_state
auto current_state() const
Definition: SimpleStatemachine.h:53
armarx::state_t::is_initial_state
auto is_initial_state() const
Definition: SimpleStatemachine.h:59
armarx::state_t
Definition: SimpleStatemachine.h:38
armarx::simple_state_machine::state_function_t
std::function< enum_t(state_t &)> state_function_t
Definition: SimpleStatemachine.h:89
armarx::simple_state_machine::configure_transition
void configure_transition(transition_function_t f=noop_transition)
Definition: SimpleStatemachine.h:110
ARMARX_TRACE
#define ARMARX_TRACE
Definition: trace.h:77
armarx::simple_state_machine::set_pre_state_enter_callback
void set_pre_state_enter_callback(hook_function_t f)
Definition: SimpleStatemachine.h:135
armarx::simple_state_machine::noop_transition
static void noop_transition(const state_t &)
Definition: SimpleStatemachine.h:96
ExpressionException.h
armarx::simple_state_machine::set_pre_transition_callback
void set_pre_transition_callback(hook_function_t f)
Definition: SimpleStatemachine.h:123
ARMARX_CHECK_EXPRESSION
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
Definition: ExpressionException.h:73
hash.h
armarx::simple_state_machine::set_post_state_exit_callback
void set_post_state_exit_callback(hook_function_t f)
Definition: SimpleStatemachine.h:129
armarx::state_t::enum_t
EnumT enum_t
Definition: SimpleStatemachine.h:43
armarx::state_t::previous_state
auto previous_state() const
Definition: SimpleStatemachine.h:47
armarx::simple_state_machine::configure_state
void configure_state(state_function_t f)
Definition: SimpleStatemachine.h:102
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27