metafunctions.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. // Copyright 2025 Christian Granzin
  2. // Copyright 2008 Christophe Henry
  3. // henry UNDERSCORE christophe AT hotmail DOT com
  4. // This is an extended version of the state machine available in the boost::mpl library
  5. // Distributed under the same license as the original.
  6. // Copyright for the original version:
  7. // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
  8. // under the Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #ifndef BOOST_MSM_BACKMP11_METAFUNCTIONS_H
  12. #define BOOST_MSM_BACKMP11_METAFUNCTIONS_H
  13. #include <boost/mp11.hpp>
  14. #include <boost/mp11/mpl_list.hpp>
  15. #include <boost/mpl/copy.hpp>
  16. #include <boost/mpl/is_sequence.hpp>
  17. #include <boost/mpl/front.hpp>
  18. #include <boost/type_traits/is_same.hpp>
  19. #include <boost/utility/enable_if.hpp>
  20. #include <boost/msm/row_tags.hpp>
  21. #include <boost/msm/backmp11/common_types.hpp>
  22. #include <boost/msm/back/traits.hpp>
  23. #include <boost/msm/front/detail/common_states.hpp>
  24. namespace boost { namespace msm { namespace backmp11
  25. {
  26. namespace detail
  27. {
  28. constexpr bool has_flag(visit_mode value, visit_mode flag)
  29. {
  30. return (static_cast<int>(value) & static_cast<int>(flag)) != 0;
  31. }
  32. struct back_end_tag {};
  33. template <typename T>
  34. using has_back_end_tag = std::is_same<typename T::internal::tag, back_end_tag>;
  35. template <class T>
  36. using is_back_end = has_back_end_tag<T>;
  37. template <typename T>
  38. using is_composite = mp11::mp_or<
  39. std::is_same<typename T::internal::tag, msm::front::detail::composite_state_tag>,
  40. has_back_end_tag<T>
  41. >;
  42. // Call a functor on all elements of List, until the functor returns true.
  43. template <typename List, typename Func>
  44. constexpr bool for_each_until(Func&& func)
  45. {
  46. bool condition = false;
  47. boost::mp11::mp_for_each<List>(
  48. [&func, &condition](auto&& item)
  49. {
  50. if (!condition)
  51. {
  52. condition = func(std::forward<decltype(item)>(item));
  53. }
  54. }
  55. );
  56. return condition;
  57. }
  58. // Wrapper for an instance of a type, which might not be present.
  59. template<typename T, bool C>
  60. struct optional_instance;
  61. template <typename T>
  62. struct optional_instance<T, true>
  63. {
  64. using type = T;
  65. type instance;
  66. static constexpr bool value = true;
  67. };
  68. template<typename T>
  69. struct optional_instance<T, false>
  70. {
  71. using type = T;
  72. static constexpr bool value = false;
  73. };
  74. // Helper to convert a single type or MPL sequence to Mp11
  75. template<typename T, typename Enable = void>
  76. struct to_mp_list
  77. {
  78. typedef typename mpl::copy<T, mpl::back_inserter<mp11::mp_list<>>>::type type;
  79. };
  80. template<typename T>
  81. struct to_mp_list<T, std::enable_if_t<!mpl::is_sequence<T>::value>>
  82. {
  83. using type = mp11::mp_list<T>;
  84. };
  85. template<typename ...T>
  86. struct to_mp_list<mp11::mp_list<T...>>
  87. {
  88. typedef mp11::mp_list<T...> type;
  89. };
  90. template<typename ...T>
  91. using to_mp_list_t = typename to_mp_list<T...>::type;
  92. template <class stt>
  93. struct generate_state_set;
  94. // iterates through a transition table to generate an ordered state set
  95. // first the source states, transition up to down
  96. // then the target states, up to down
  97. template <class Stt>
  98. struct generate_state_set
  99. {
  100. typedef to_mp_list_t<Stt> stt;
  101. // first add the source states
  102. template <typename V, typename T>
  103. using set_push_source_state =
  104. mp11::mp_set_push_back<V, typename T::current_state_type>;
  105. using source_state_set =
  106. mp11::mp_fold<stt, mp11::mp_list<>, set_push_source_state>;
  107. // then add the target states
  108. template <typename V, typename T>
  109. using set_push_target_state =
  110. mp11::mp_set_push_back<V, typename T::next_state_type>;
  111. using state_set =
  112. mp11::mp_fold<stt, source_state_set, set_push_target_state>;
  113. };
  114. // extends a state set to a map with key=state and value=id
  115. template <class StateSet>
  116. struct generate_state_map
  117. {
  118. typedef StateSet state_set;
  119. typedef mp11::mp_iota<mp11::mp_size<state_set>> indices;
  120. typedef mp11::mp_transform_q<
  121. mp11::mp_bind<mp11::mp_list, mp11::_1, mp11::_2>,
  122. state_set,
  123. indices
  124. > type;
  125. };
  126. // returns the id of a given state
  127. template <class StateMap, class State>
  128. struct get_state_id
  129. {
  130. typedef mp11::mp_second<mp11::mp_map_find<
  131. StateMap,
  132. State
  133. >> type;
  134. static constexpr typename type::value_type value = type::value;
  135. };
  136. // iterates through the transition table and generate a set containing all the events
  137. template <class stt>
  138. struct generate_event_set
  139. {
  140. typedef to_mp_list_t<stt> stt_mp11;
  141. template<typename V, typename T>
  142. using event_set_pusher = mp11::mp_set_push_back<
  143. V,
  144. typename T::transition_event
  145. >;
  146. typedef mp11::mp_fold<
  147. to_mp_list_t<stt>,
  148. mp11::mp_list<>,
  149. event_set_pusher
  150. > event_set_mp11;
  151. };
  152. // extends an event set to a map with key=event and value=id
  153. template <class stt>
  154. struct generate_event_map
  155. {
  156. typedef typename generate_event_set<stt>::event_set_mp11 event_set;
  157. typedef mp11::mp_iota<mp11::mp_size<event_set>> indices;
  158. typedef mp11::mp_transform_q<
  159. mp11::mp_bind<mp11::mp_list, mp11::_1, mp11::_2>,
  160. event_set,
  161. indices
  162. > type;
  163. };
  164. // returns the id of a given event
  165. template <class stt,class Event>
  166. struct get_event_id
  167. {
  168. typedef mp11::mp_second<mp11::mp_map_find<
  169. typename generate_event_map<stt>::type,
  170. Event
  171. >> type;
  172. enum {value = type::value};
  173. };
  174. template <class State>
  175. using has_state_deferred_events = mp11::mp_not<
  176. mp11::mp_empty<to_mp_list_t<typename State::deferred_events>>
  177. >;
  178. // Template used to create dummy entries for initial states not found in the stt.
  179. template< typename T1 >
  180. struct not_a_row
  181. {
  182. typedef int not_real_row_tag;
  183. struct dummy_event
  184. {
  185. };
  186. typedef T1 current_state_type;
  187. typedef T1 next_state_type;
  188. typedef dummy_event transition_event;
  189. };
  190. // used for states created with explicit_creation
  191. // if the state is an explicit entry, we reach for the wrapped state
  192. // otherwise, this returns the state itself
  193. template <class State>
  194. struct get_wrapped_state
  195. {
  196. template <typename T>
  197. using get_wrapped_entry = typename T::wrapped_entry;
  198. using type = mp11::mp_eval_or<State, get_wrapped_entry, State>;
  199. };
  200. // returns the transition table of a Composite state
  201. template <class Derived>
  202. struct get_transition_table
  203. {
  204. typedef typename Derived::internal::template create_real_stt<typename Derived::front_end_t>::type Stt;
  205. // get the state set
  206. typedef typename generate_state_set<Stt>::state_set states;
  207. // iterate through the initial states and add them in the stt if not already there
  208. typedef typename Derived::internal::initial_states initial_states;
  209. template<typename V, typename T>
  210. using states_pusher = mp11::mp_if_c<
  211. mp11::mp_set_contains<states, T>::value,
  212. V,
  213. mp11::mp_push_back<
  214. V,
  215. not_a_row<typename get_wrapped_state<T>::type>
  216. >
  217. >;
  218. typedef typename mp11::mp_fold<
  219. to_mp_list_t<initial_states>,
  220. to_mp_list_t<Stt>,
  221. states_pusher
  222. > with_init;
  223. // do the same for states marked as explicitly created
  224. template<typename T>
  225. using get_explicit_creation = to_mp_list_t<typename T::explicit_creation>;
  226. using fake_explicit_created = mp11::mp_eval_or<
  227. mp11::mp_list<>,
  228. get_explicit_creation,
  229. Derived
  230. >;
  231. //converts a "fake" (simulated in a state_machine_ description )state into one which will really get created
  232. template <class State>
  233. using convert_fake_state = mp11::mp_if_c<
  234. has_direct_entry<State>::value,
  235. typename Derived::template direct<State>,
  236. State
  237. >;
  238. using explicit_created = mp11::mp_transform<
  239. convert_fake_state,
  240. fake_explicit_created
  241. >;
  242. typedef typename mp11::mp_fold<
  243. to_mp_list_t<explicit_created>,
  244. with_init,
  245. states_pusher
  246. > type;
  247. };
  248. template<typename T>
  249. using get_transition_table_t = typename get_transition_table<T>::type;
  250. // recursively builds an internal table including those of substates, sub-substates etc.
  251. // variant for submachines
  252. template <class State, bool IsComposite>
  253. struct recursive_get_internal_transition_table
  254. {
  255. // get the composite's internal table
  256. typedef typename State::front_end_t::internal_transition_table composite_table;
  257. // and for every substate (state of submachine), recursively get the internal transition table
  258. using composite_states = typename State::internal::state_set;
  259. template<typename V, typename SubState>
  260. using append_recursive_internal_transition_table = mp11::mp_append<
  261. V,
  262. typename recursive_get_internal_transition_table<SubState, has_back_end_tag<SubState>::value>::type
  263. >;
  264. typedef typename mp11::mp_fold<
  265. composite_states,
  266. to_mp_list_t<composite_table>,
  267. append_recursive_internal_transition_table
  268. > type;
  269. };
  270. // stop iterating on leafs (simple states)
  271. template <class State>
  272. struct recursive_get_internal_transition_table<State, false>
  273. {
  274. typedef to_mp_list_t<
  275. typename State::internal_transition_table
  276. > type;
  277. };
  278. // recursively get a transition table for a given composite state.
  279. // returns the transition table for this state + the tables of all composite sub states recursively
  280. template <class Composite>
  281. struct recursive_get_transition_table
  282. {
  283. // get the transition table of the state if it's a state machine
  284. typedef typename mp11::mp_eval_if_c<
  285. !has_back_end_tag<Composite>::value,
  286. mp11::mp_list<>,
  287. get_transition_table_t,
  288. Composite
  289. > org_table;
  290. typedef typename generate_state_set<org_table>::state_set states;
  291. // and for every substate, recursively get the transition table if it's a state machine
  292. template<typename V, typename T>
  293. using append_recursive_transition_table = mp11::mp_append<
  294. V,
  295. typename recursive_get_transition_table<T>::type
  296. >;
  297. typedef typename mp11::mp_fold<
  298. states,
  299. org_table,
  300. append_recursive_transition_table> type;
  301. };
  302. // event used internally for wrapping a direct entry
  303. template <class State, class Event>
  304. struct direct_entry_event
  305. {
  306. public:
  307. typedef int direct_entry;
  308. typedef State active_state;
  309. typedef Event contained_event;
  310. direct_entry_event(Event const& event):m_event(event){}
  311. Event const& m_event;
  312. };
  313. //returns the owner of an explicit_entry state
  314. //which is the containing SM if the transition originates from outside the containing SM
  315. //or else the explicit_entry state itself
  316. template <class State,class ContainingSM>
  317. struct get_owner
  318. {
  319. using type = mp11::mp_if<
  320. mp11::mp_same<typename State::owner, ContainingSM>,
  321. State,
  322. typename State::owner
  323. >;
  324. };
  325. template <class Sequence, class ContainingSM>
  326. struct get_fork_owner
  327. {
  328. typedef typename ::boost::mpl::front<Sequence>::type seq_front;
  329. typedef typename ::boost::mpl::if_<
  330. typename ::boost::mpl::not_<
  331. typename ::boost::is_same<typename seq_front::owner,ContainingSM>::type>::type,
  332. typename seq_front::owner,
  333. seq_front >::type type;
  334. };
  335. // builds flags (add internal_flag_list and flag_list). internal_flag_list is used for terminate/interrupt states
  336. template <class State>
  337. struct get_flag_list
  338. {
  339. typedef typename mp11::mp_append<
  340. to_mp_list_t<typename State::flag_list>,
  341. to_mp_list_t<typename State::internal_flag_list>
  342. > type;
  343. };
  344. template <class State>
  345. struct is_state_blocking
  346. {
  347. template<typename T>
  348. using has_event_blocking_flag = typename has_event_blocking_flag<T>::type;
  349. typedef typename mp11::mp_any_of<
  350. typename get_flag_list<State>::type,
  351. has_event_blocking_flag
  352. > type;
  353. };
  354. template<typename T>
  355. using is_state_blocking_t = typename is_state_blocking<T>::type;
  356. } // detail
  357. }}} // boost::msm::backmp11
  358. #endif // BOOST_MSM_BACKMP11_METAFUNCTIONS_H