fsm
state_manager.h
1 
12 #pragma once
13 
14 #include <variant>
15 
16 #include "../../base/type_traits.h"
17 
18 #include "../transitions.h"
19 #include "../states.h"
20 #include "../contexts.h"
21 //#include "fsmpp2/config.hpp"
22 #include "state_container.h"
24 #include "traits.h"
25 #include <variant>
26 
27 namespace escad::detail
28 {
29 
30 struct NullTracer {
31  template<class State, class E>
32  void begin_event_handling () {}
33  void end_event_handling(bool) {}
34  template<class State>
35  void transition() {}
36 };
37 
41 template<class States, class Context, class Tracer = NullTracer>
43 {
44 private:
45  using type_list = typename States::type_list;
46 
47 public:
48  state_manager(Context &ctx, Tracer& tracer)
49  : context_ {ctx}
50  , tracer_ {tracer}
51  {
52  enter_first();
53  }
54 
55  ~state_manager() {
56  exit();
57  }
58 
59  template<class T>
60  void enter() {
61  exit();
62 
63  // create substate manager
64  substates_.template create<T>(context_, tracer_);
65 
66  // construct state
67  emplace_state<T>(context_);
68  }
69 
70  void exit() {
71  states_.exit();
72  }
73 
74  template<class E>
75  auto dispatch(E const& e) {
76  auto result = false;
77 
78  substates_.visit(
79  [&](auto &substate) {
80  //Unused << this;
81  result = substate_dispatch(substate, e);
82  }
83  );
84 
85  if (result == false) {
86  states_.visit([this, &e, &result](auto &state) {
87  tracer_.template begin_event_handling<
88  std::remove_reference_t<decltype(state)>,
89  std::remove_reference_t<decltype(e)>>();
90 
91  result = handle(state, e);
92  tracer_.end_event_handling(result);
93  });
94  }
95 
96  return result;
97  }
98 
99  template<class S>
100  bool is_in() const {
101  return states_.template is_in<S>();
102  }
103 
104  template<class S>
105  S& state() {
106  return states_.template state<S>();
107  }
108 
109 private:
110  template<class T, class C>
111  void emplace_state(C &c) {
112  if constexpr (std::is_constructible_v<T, C&>) {
113  states_.template enter<T>(c);
114  } else {
115  states_.template enter<T>();
116  }
117  }
118 
119  template<class T, class... C>
120  static constexpr bool is_constructible_by_one_of() {
121  return (std::is_constructible_v<T, C&> || ...);
122  }
123 
124  template<class T, class U, class... C>
125  void try_emplace_state(escad::contexts<C...> &ctx) {
126  if constexpr (std::is_constructible_v<T, U&>) {
127  states_.template enter<T>(ctx.template get<U>());
128  }
129  }
130 
131  template<class T, class... C>
132  void emplace_state(escad::contexts<C...> &ctx) {
133  if constexpr(std::is_constructible_v<T, escad::contexts<C...> &>) {
134  states_.template enter<T>(ctx);
135  } else {
136  if constexpr(is_constructible_by_one_of<T, C...>()) {
137  (try_emplace_state<T, C, C...>(ctx), ...);
138  } else {
139  states_.template enter<T>();
140  }
141  }
142  }
143 
144  void enter_first() {
145  if constexpr (States::count > 0) {
146  using first_t = typename mpl::type_list_first<type_list>::type;
147  enter<first_t>();
148  }
149  }
150 
151  template<class SS, class E>
152  bool substate_dispatch(SS& substate, E const &e) {
153  return substate.dispatch(e);
154  }
155 
156  template<class E>
157  bool substate_dispatch(std::monostate, E const&) {
158  return false;
159  }
160 
161  template<class S, class E>
162  auto handle(S &state, E const& e) -> std::enable_if_t<detail::can_handle_event<S, E>::value, bool> {
163  if (handle_result(state.handle(e))) {
164  return true;
165  } else {
166  return false;
167  }
168  }
169 
170  template<class S, class E>
171  auto handle(S &state, E const& e) -> std::enable_if_t<detail::can_handle_event_with_context<S, E, Context>::value, bool> {
172  if (handle_result(state.handle(e, context_))) {
173  return true;
174  } else {
175  return false;
176  }
177  }
178 
179  template<class S, class E>
180  auto handle(S&, E const& ) -> std::enable_if_t<
182  bool> {
183  return false;
184  }
185 
186  // state handler declared a return transitions<> return type
187  template<class... T>
188  bool handle_result(transitions<T...> t) {
189  if (t.is_transition()) {
190  handle_transition(t, std::make_index_sequence<sizeof...(T)>{});
191  return true;
192  }
193 
194  return t.is_handled();
195  }
196 
197  template<class Transition, std::size_t... I>
198  void handle_transition(Transition trans, std::index_sequence<I...>) {
199  (handle_transition_impl<I>(trans), ...);
200  }
201 
202  template<std::size_t I, class Transition>
203  void handle_transition_impl(Transition trans) {
204  if (trans.idx == I) {
205  using transition_type_list = typename Transition::list;
206  //using type_at_index = typename meta::type_list_type<I, transition_type_list>::type;
207  using type_at_index = mpl::type_list_element_t<I, transition_type_list>;
208 
209  //if constexpr (meta::type_list_has<type_at_index>(type_list{})) {
210  if (mpl::type_list_contains_v<type_list, type_at_index>) {
211  tracer_.template transition<type_at_index>();
212  enter<type_at_index>();
213  }
214  }
215  }
216 
217 private:
218  template<class X>
220 
223 
224  Context& context_;
225  StateContainer states_;
226  SubStateContainer substates_;
227  Tracer& tracer_;
228 };
229 
230 } // namespace fsm::detail
Get first type in provided type_list<>
Definition: type_traits.h:414
Definition: traits.h:20
Definition: testJsonContexts.cpp:18
Manages a set of state, creates, destroys and pass events to a proper state.
Definition: state_manager.h:42
Definition: handle_result.h:14
Denotes a state.
Definition: states.h:61
bool is_transition() const
Check if this object is a transition type.
Definition: transitions.h:92
Definition: state_manager.h:30
Definition: handle_result.h:19
Event handler return type.
Definition: transitions.h:28
A set of references to different context types.
Definition: contexts.h:26
bool is_handled() const
Check if the event was handled.
Definition: transitions.h:102
Wrapper around std::variant, which is current implementation of states container. ...
Definition: state_container.h:30