metafunctions.hpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. // Copyright 2008 Christophe Henry
  2. // henry UNDERSCORE christophe AT hotmail DOT com
  3. // This is an extended version of the state machine available in the boost::mpl library
  4. // Distributed under the same license as the original.
  5. // Copyright for the original version:
  6. // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
  7. // under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_MSM_BACK11_METAFUNCTIONS_H
  11. #define BOOST_MSM_BACK11_METAFUNCTIONS_H
  12. #include <algorithm>
  13. #include <boost/mpl/set.hpp>
  14. #include <boost/mpl/at.hpp>
  15. #include <boost/mpl/pair.hpp>
  16. #include <boost/mpl/map.hpp>
  17. #include <boost/mpl/int.hpp>
  18. #include <boost/mpl/has_xxx.hpp>
  19. #include <boost/mpl/find.hpp>
  20. #include <boost/mpl/count_if.hpp>
  21. #include <boost/mpl/fold.hpp>
  22. #include <boost/mpl/if.hpp>
  23. #include <boost/mpl/has_key.hpp>
  24. #include <boost/mpl/insert.hpp>
  25. #include <boost/mpl/next_prior.hpp>
  26. #include <boost/mpl/map.hpp>
  27. #include <boost/mpl/push_back.hpp>
  28. #include <boost/mpl/is_sequence.hpp>
  29. #include <boost/mpl/size.hpp>
  30. #include <boost/mpl/transform.hpp>
  31. #include <boost/mpl/begin_end.hpp>
  32. #include <boost/mpl/bool.hpp>
  33. #include <boost/mpl/empty.hpp>
  34. #include <boost/mpl/identity.hpp>
  35. #include <boost/mpl/eval_if.hpp>
  36. #include <boost/mpl/insert_range.hpp>
  37. #include <boost/mpl/front.hpp>
  38. #include <boost/mpl/logical.hpp>
  39. #include <boost/mpl/plus.hpp>
  40. #include <boost/mpl/copy_if.hpp>
  41. #include <boost/mpl/back_inserter.hpp>
  42. #include <boost/mpl/transform.hpp>
  43. #include <boost/fusion/include/mpl.hpp>
  44. #include <boost/fusion/container/vector/convert.hpp>
  45. #include <boost/fusion/include/as_vector.hpp>
  46. #include <boost/fusion/include/as_set.hpp>
  47. #include <boost/fusion/container/vector.hpp>
  48. #include <boost/fusion/include/set.hpp>
  49. #include <boost/fusion/include/map.hpp>
  50. #include <boost/fusion/include/pair.hpp>
  51. #include <boost/fusion/include/at_key.hpp>
  52. #include <boost/fusion/include/for_each.hpp>
  53. #include <boost/fusion/include/make_vector.hpp>
  54. #include <boost/fusion/include/has_key.hpp>
  55. #include <boost/fusion/include/make_set.hpp>
  56. #include <boost/fusion/include/value_at_key.hpp>
  57. #include <boost/fusion/include/front.hpp>
  58. #include <boost/type_traits/is_same.hpp>
  59. #include <boost/utility/enable_if.hpp>
  60. #include <boost/msm/row_tags.hpp>
  61. // mpl_graph graph implementation and depth first search
  62. #include <boost/msm/mpl_graph/incidence_list_graph.hpp>
  63. #include <boost/msm/mpl_graph/depth_first_search.hpp>
  64. BOOST_MPL_HAS_XXX_TRAIT_DEF(explicit_creation)
  65. BOOST_MPL_HAS_XXX_TRAIT_DEF(pseudo_entry)
  66. BOOST_MPL_HAS_XXX_TRAIT_DEF(pseudo_exit)
  67. BOOST_MPL_HAS_XXX_TRAIT_DEF(concrete_exit_state)
  68. BOOST_MPL_HAS_XXX_TRAIT_DEF(composite_tag)
  69. BOOST_MPL_HAS_XXX_TRAIT_DEF(not_real_row_tag)
  70. BOOST_MPL_HAS_XXX_TRAIT_DEF(event_blocking_flag)
  71. BOOST_MPL_HAS_XXX_TRAIT_DEF(explicit_entry_state)
  72. BOOST_MPL_HAS_XXX_TRAIT_DEF(completion_event)
  73. BOOST_MPL_HAS_XXX_TRAIT_DEF(no_exception_thrown)
  74. BOOST_MPL_HAS_XXX_TRAIT_DEF(no_message_queue)
  75. BOOST_MPL_HAS_XXX_TRAIT_DEF(activate_deferred_events)
  76. BOOST_MPL_HAS_XXX_TRAIT_DEF(wrapped_entry)
  77. BOOST_MPL_HAS_XXX_TRAIT_DEF(active_state_switch_policy)
  78. namespace boost { namespace msm { namespace back11
  79. {
  80. template <typename Sequence, typename Range>
  81. struct set_insert_range
  82. {
  83. typedef typename ::boost::mpl::fold<
  84. Range,Sequence,
  85. ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >
  86. >::type type;
  87. };
  88. // returns the current state type of a transition
  89. template <class Transition>
  90. struct transition_source_type
  91. {
  92. typedef typename Transition::current_state_type type;
  93. };
  94. // returns the target state type of a transition
  95. template <class Transition>
  96. struct transition_target_type
  97. {
  98. typedef typename Transition::next_state_type type;
  99. };
  100. // helper functions for generate_state_ids
  101. // create a pair of a state and a passed id for source and target states
  102. template <class Id,class Transition>
  103. struct make_pair_source_state_id
  104. {
  105. typedef typename ::boost::fusion::pair<typename Transition::current_state_type,Id> type;
  106. };
  107. template <class Id,class Transition>
  108. struct make_pair_target_state_id
  109. {
  110. typedef typename ::boost::fusion::pair<typename Transition::next_state_type,Id> type;
  111. };
  112. // iterates through a transition table and automatically generates ids starting at 0
  113. // first the source states, transition up to down
  114. // then the target states, up to down
  115. template <class stt>
  116. struct generate_state_ids
  117. {
  118. typedef typename
  119. ::boost::mpl::fold<
  120. stt,::boost::mpl::pair< ::boost::fusion::map< >, ::boost::mpl::int_<0> >,
  121. ::boost::mpl::pair<
  122. ::boost::mpl::if_<
  123. ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
  124. transition_source_type< ::boost::mpl::placeholders::_2> >,
  125. ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
  126. boost::fusion::result_of::as_map<boost::fusion::result_of::insert<
  127. ::boost::mpl::first<mpl::placeholders::_1>,
  128. ::boost::fusion::result_of::end<::boost::mpl::first<mpl::placeholders::_1> >,
  129. make_pair_source_state_id< ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
  130. ::boost::mpl::placeholders::_2> > >
  131. >,
  132. ::boost::mpl::if_<
  133. ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
  134. transition_source_type< ::boost::mpl::placeholders::_2> >,
  135. ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
  136. ::boost::mpl::next< ::boost::mpl::second<mpl::placeholders::_1 > >
  137. >
  138. > //pair
  139. >::type source_state_ids;
  140. typedef typename ::boost::mpl::first<source_state_ids>::type source_state_map;
  141. typedef typename ::boost::mpl::second<source_state_ids>::type highest_state_id;
  142. typedef typename
  143. ::boost::mpl::fold<
  144. stt,::boost::mpl::pair< source_state_map, highest_state_id >,
  145. ::boost::mpl::pair<
  146. ::boost::mpl::if_<
  147. ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
  148. transition_target_type< ::boost::mpl::placeholders::_2> >,
  149. ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
  150. boost::fusion::result_of::as_map<boost::fusion::result_of::insert<
  151. ::boost::mpl::first<mpl::placeholders::_1>,
  152. ::boost::fusion::result_of::end<::boost::mpl::first<mpl::placeholders::_1> >,
  153. make_pair_target_state_id< ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
  154. ::boost::mpl::placeholders::_2> > >
  155. >,
  156. ::boost::mpl::if_<
  157. ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
  158. transition_target_type< ::boost::mpl::placeholders::_2> >,
  159. ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
  160. ::boost::mpl::next< ::boost::mpl::second<mpl::placeholders::_1 > >
  161. >
  162. > //pair
  163. >::type all_state_ids;
  164. typedef typename ::boost::mpl::first<all_state_ids>::type type;
  165. };
  166. template <class Fsm>
  167. struct get_active_state_switch_policy_helper
  168. {
  169. typedef typename Fsm::active_state_switch_policy type;
  170. };
  171. template <class Iter>
  172. struct get_active_state_switch_policy_helper2
  173. {
  174. typedef typename boost::mpl::deref<Iter>::type Fsm;
  175. typedef typename Fsm::active_state_switch_policy type;
  176. };
  177. // returns the active state switching policy
  178. template <class Fsm>
  179. struct get_active_state_switch_policy
  180. {
  181. typedef typename ::boost::mpl::find_if<
  182. typename Fsm::configuration,
  183. has_active_state_switch_policy< ::boost::mpl::placeholders::_1 > >::type iter;
  184. typedef typename ::boost::mpl::eval_if<
  185. typename ::boost::is_same<
  186. iter,
  187. typename ::boost::mpl::end<typename Fsm::configuration>::type
  188. >::type,
  189. get_active_state_switch_policy_helper<Fsm>,
  190. get_active_state_switch_policy_helper2< iter >
  191. >::type type;
  192. };
  193. // returns the id of a given state
  194. template <class stt,class State>
  195. struct get_state_id
  196. {
  197. typedef typename ::boost::fusion::result_of::value_at_key<typename generate_state_ids<stt>::type,State>::type type;
  198. enum {value = type::value};
  199. };
  200. // returns a fusion::vector containing the init states of a state machine
  201. template <class States>
  202. struct get_initial_states
  203. {
  204. typedef typename ::boost::mpl::if_<
  205. ::boost::mpl::is_sequence<States>,
  206. States,
  207. typename ::boost::mpl::push_back< ::boost::fusion::vector<>,States>::type >::type type;
  208. };
  209. // returns a mpl::int_ containing the size of a region. If the argument is not a sequence, returns 1
  210. template <class region>
  211. struct get_number_of_regions
  212. {
  213. typedef typename mpl::if_<
  214. ::boost::mpl::is_sequence<region>,
  215. ::boost::mpl::size<region>,
  216. ::boost::mpl::int_<1> >::type type;
  217. };
  218. // builds a fusion::vector of initial states
  219. //TODO remove duplicate from get_initial_states
  220. template <class region>
  221. struct get_regions_as_sequence
  222. {
  223. typedef typename ::boost::mpl::if_<
  224. ::boost::mpl::is_sequence<region>,
  225. region,
  226. typename ::boost::mpl::push_back< ::boost::fusion::vector0<>,region>::type >::type type;
  227. };
  228. template <class ToCreateSeq>
  229. struct get_explicit_creation_as_sequence
  230. {
  231. typedef typename ::boost::mpl::if_<
  232. ::boost::mpl::is_sequence<ToCreateSeq>,
  233. ToCreateSeq,
  234. typename ::boost::mpl::push_back< ::boost::fusion::vector0<>,ToCreateSeq>::type >::type type;
  235. };
  236. // returns true if 2 transitions have the same source (used to remove duplicates in search of composite states)
  237. template <class stt,class Transition1,class Transition2>
  238. struct have_same_source
  239. {
  240. enum {current_state1 = get_state_id<stt,typename Transition1::current_state_type >::type::value};
  241. enum {current_state2 = get_state_id<stt,typename Transition2::current_state_type >::type::value};
  242. enum {value = ((int)current_state1 == (int)current_state2) };
  243. };
  244. // A metafunction that returns the Event associated with a transition.
  245. template <class Transition>
  246. struct transition_event
  247. {
  248. typedef typename Transition::transition_event type;
  249. };
  250. // returns true for composite states
  251. template <class State>
  252. struct is_composite_state
  253. {
  254. enum {value = has_composite_tag<State>::type::value};
  255. typedef typename has_composite_tag<State>::type type;
  256. };
  257. // transform a transition table in a container of source states
  258. template <class stt>
  259. struct keep_source_names
  260. {
  261. // instead of the rows we want only the names of the states (from source)
  262. typedef typename
  263. ::boost::mpl::transform<
  264. stt,transition_source_type< ::boost::mpl::placeholders::_1> >::type type;
  265. };
  266. // transform a transition table in a container of target states
  267. template <class stt>
  268. struct keep_target_names
  269. {
  270. // instead of the rows we want only the names of the states (from source)
  271. typedef typename
  272. ::boost::mpl::transform<
  273. stt,transition_target_type< ::boost::mpl::placeholders::_1> >::type type;
  274. };
  275. // fusion sets do not guarantee uniqueness so we need to check this before insertion
  276. template <class Set, class T>
  277. struct set_unique_insert
  278. {
  279. typedef typename ::boost::mpl::if_<
  280. ::boost::fusion::result_of::has_key<Set, T>,
  281. Set,
  282. typename ::boost::mpl::push_back<Set, T>::type
  283. >::type type;
  284. };
  285. template <class stt>
  286. struct generate_state_set
  287. {
  288. // keep in the original transition table only the source/target state types
  289. typedef typename keep_source_names<stt>::type sources;
  290. typedef typename keep_target_names<stt>::type targets;
  291. typedef typename
  292. ::boost::mpl::fold<
  293. sources,
  294. boost::fusion::set<>,
  295. boost::msm::back11::set_unique_insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2>
  296. >::type source_set;
  297. typedef typename
  298. ::boost::mpl::fold<
  299. targets,
  300. source_set,
  301. boost::msm::back11::set_unique_insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2>
  302. >::type type;
  303. };
  304. // iterates through the transition table and generate a fusion::set<> containing all the events
  305. template <class stt>
  306. struct generate_event_set
  307. {
  308. typedef typename
  309. ::boost::mpl::fold<
  310. stt, ::boost::fusion::set<>,
  311. ::boost::mpl::if_<
  312. ::boost::mpl::has_key< ::boost::mpl::placeholders::_1,
  313. transition_event< ::boost::mpl::placeholders::_2> >,
  314. ::boost::mpl::placeholders::_1,
  315. ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
  316. transition_event< ::boost::mpl::placeholders::_2> > >
  317. >::type type;
  318. };
  319. // returns a mpl::bool_<true> if State has Event as deferred event
  320. template <class State, class Event>
  321. struct has_state_delayed_event
  322. {
  323. typedef typename ::boost::mpl::find<typename State::deferred_events,Event>::type found;
  324. typedef typename ::boost::mpl::if_<
  325. ::boost::is_same<found,typename ::boost::mpl::end<typename State::deferred_events>::type >,
  326. ::boost::mpl::bool_<false>,
  327. ::boost::mpl::bool_<true> >::type type;
  328. };
  329. // returns a mpl::bool_<true> if State has any deferred event
  330. template <class State>
  331. struct has_state_delayed_events
  332. {
  333. typedef typename ::boost::mpl::if_<
  334. ::boost::mpl::empty<typename State::deferred_events>,
  335. ::boost::mpl::bool_<false>,
  336. ::boost::mpl::bool_<true> >::type type;
  337. };
  338. // Template used to create dummy entries for initial states not found in the stt.
  339. template< typename T1 >
  340. struct not_a_row
  341. {
  342. typedef int not_real_row_tag;
  343. struct dummy_event
  344. {
  345. };
  346. typedef T1 current_state_type;
  347. typedef T1 next_state_type;
  348. typedef dummy_event transition_event;
  349. };
  350. // metafunctions used to find out if a state is entry, exit or something else
  351. template <class State>
  352. struct is_pseudo_entry
  353. {
  354. typedef typename ::boost::mpl::if_< typename has_pseudo_entry<State>::type,
  355. ::boost::mpl::bool_<true>,::boost::mpl::bool_<false>
  356. >::type type;
  357. };
  358. // says if a state is an exit pseudo state
  359. template <class State>
  360. struct is_pseudo_exit
  361. {
  362. typedef typename ::boost::mpl::if_< typename has_pseudo_exit<State>::type,
  363. ::boost::mpl::bool_<true>, ::boost::mpl::bool_<false>
  364. >::type type;
  365. };
  366. // says if a state is an entry pseudo state or an explicit entry
  367. template <class State>
  368. struct is_direct_entry
  369. {
  370. typedef typename ::boost::mpl::if_< typename has_explicit_entry_state<State>::type,
  371. ::boost::mpl::bool_<true>, ::boost::mpl::bool_<false>
  372. >::type type;
  373. };
  374. //converts a "fake" (simulated in a state_machine_ description )state into one which will really get created
  375. template <class StateType,class CompositeType>
  376. struct convert_fake_state
  377. {
  378. // converts a state (explicit entry) into the state we really are going to create (explicit<>)
  379. typedef typename ::boost::mpl::if_<
  380. typename is_direct_entry<StateType>::type,
  381. typename CompositeType::template direct<StateType>,
  382. typename ::boost::mpl::identity<StateType>::type
  383. >::type type;
  384. };
  385. template <class StateType>
  386. struct get_explicit_creation
  387. {
  388. typedef typename StateType::explicit_creation type;
  389. };
  390. template <class StateType>
  391. struct get_wrapped_entry
  392. {
  393. typedef typename StateType::wrapped_entry type;
  394. };
  395. // used for states created with explicit_creation
  396. // if the state is an explicit entry, we reach for the wrapped state
  397. // otherwise, this returns the state itself
  398. template <class StateType>
  399. struct get_wrapped_state
  400. {
  401. typedef typename ::boost::mpl::eval_if<
  402. typename has_wrapped_entry<StateType>::type,
  403. get_wrapped_entry<StateType>,
  404. ::boost::mpl::identity<StateType> >::type type;
  405. };
  406. template <class Derived>
  407. struct create_stt
  408. {
  409. //typedef typename Derived::transition_table stt;
  410. typedef typename Derived::real_transition_table Stt;
  411. // get the state set
  412. typedef typename generate_state_set<Stt>::type states;
  413. // transform the initial region(s) in a sequence
  414. typedef typename get_regions_as_sequence<typename Derived::initial_state>::type init_states;
  415. // iterate through the initial states and add them in the stt if not already there
  416. typedef typename
  417. ::boost::mpl::fold<
  418. init_states,Stt,
  419. ::boost::mpl::if_<
  420. ::boost::mpl::has_key<states, ::boost::mpl::placeholders::_2>,
  421. ::boost::mpl::placeholders::_1,
  422. ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
  423. not_a_row< get_wrapped_state< ::boost::mpl::placeholders::_2> > >
  424. >
  425. >::type with_init;
  426. // do the same for states marked as explicitly created
  427. typedef typename get_explicit_creation_as_sequence<
  428. typename ::boost::mpl::eval_if<
  429. typename has_explicit_creation<Derived>::type,
  430. get_explicit_creation<Derived>,
  431. boost::fusion::result_of::make_vector<> >::type
  432. >::type fake_explicit_created;
  433. typedef typename
  434. ::boost::mpl::transform<
  435. fake_explicit_created,convert_fake_state< ::boost::mpl::placeholders::_1,Derived> >::type explicit_created;
  436. typedef typename
  437. ::boost::mpl::fold<
  438. explicit_created,with_init,
  439. ::boost::mpl::if_<
  440. ::boost::mpl::has_key<states, ::boost::mpl::placeholders::_2>,
  441. ::boost::mpl::placeholders::_1,
  442. ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
  443. not_a_row< get_wrapped_state< ::boost::mpl::placeholders::_2> > >
  444. >
  445. >::type type;
  446. };
  447. // returns the transition table of a Composite state
  448. template <class Composite>
  449. struct get_transition_table
  450. {
  451. typedef typename create_stt<Composite>::type type;
  452. };
  453. // recursively builds an internal table including those of substates, sub-substates etc.
  454. // variant for submachines
  455. template <class StateType,class IsComposite>
  456. struct recursive_get_internal_transition_table
  457. {
  458. // get the composite's internal table
  459. typedef typename StateType::internal_transition_table11 composite_table;
  460. // and for every substate (state of submachine), recursively get the internal transition table
  461. typedef typename generate_state_set<typename StateType::stt>::type composite_states;
  462. typedef typename ::boost::mpl::fold<
  463. composite_states, composite_table,
  464. ::boost::fusion::result_of::as_vector<
  465. ::boost::fusion::result_of::insert_range<
  466. ::boost::mpl::placeholders::_1,
  467. ::boost::fusion::result_of::end< ::boost::mpl::placeholders::_1>,
  468. recursive_get_internal_transition_table< ::boost::mpl::placeholders::_2, is_composite_state< ::boost::mpl::placeholders::_2> >
  469. >
  470. >
  471. >::type type;
  472. };
  473. // stop iterating on leafs (simple states)
  474. template <class StateType>
  475. struct recursive_get_internal_transition_table<StateType, ::boost::mpl::false_ >
  476. {
  477. typedef typename StateType::internal_transition_table11 type;
  478. };
  479. // recursively get a transition table for a given composite state.
  480. // returns the transition table for this state + the tables of all composite sub states recursively
  481. template <class Composite>
  482. struct recursive_get_transition_table
  483. {
  484. // get the transition table of the state if it's a state machine
  485. typedef typename ::boost::mpl::eval_if<typename is_composite_state<Composite>::type,
  486. get_transition_table<Composite>,
  487. boost::fusion::result_of::make_vector<>
  488. >::type org_table;
  489. typedef typename generate_state_set<org_table>::type states;
  490. // and for every substate, recursively get the transition table if it's a state machine
  491. // typedef typename ::boost::mpl::fold<
  492. // states,org_table,
  493. // ::boost::mpl::insert_range< ::boost::mpl::placeholders::_1, ::boost::mpl::end<mpl::placeholders::_1>,
  494. // recursive_get_transition_table< ::boost::mpl::placeholders::_2 > >
  495. // >::type type;
  496. typedef typename ::boost::mpl::fold<
  497. states,org_table,
  498. ::boost::fusion::result_of::as_vector<
  499. ::boost::fusion::result_of::insert_range<
  500. ::boost::mpl::placeholders::_1,
  501. ::boost::fusion::result_of::end<mpl::placeholders::_1>,
  502. recursive_get_transition_table< ::boost::mpl::placeholders::_2 >
  503. >
  504. >
  505. >::type type;
  506. };
  507. // metafunction used to say if a SM has pseudo exit states
  508. template <class Derived>
  509. struct has_fsm_deferred_events
  510. {
  511. typedef typename create_stt<Derived>::type Stt;
  512. typedef typename generate_state_set<Stt>::type state_list;
  513. typedef typename ::boost::mpl::or_<
  514. typename has_activate_deferred_events<Derived>::type,
  515. ::boost::mpl::bool_< ::boost::mpl::count_if<
  516. typename Derived::configuration,
  517. has_activate_deferred_events< ::boost::mpl::placeholders::_1 > >::value != 0>
  518. >::type found_in_fsm;
  519. typedef typename ::boost::mpl::or_<
  520. found_in_fsm,
  521. ::boost::mpl::bool_< ::boost::mpl::count_if<
  522. state_list,has_state_delayed_events<
  523. ::boost::mpl::placeholders::_1 > >::value != 0>
  524. >::type type;
  525. };
  526. // returns a mpl::bool_<true> if State has any delayed event
  527. template <class Event>
  528. struct is_completion_event
  529. {
  530. typedef typename ::boost::mpl::if_<
  531. has_completion_event<Event>,
  532. ::boost::mpl::bool_<true>,
  533. ::boost::mpl::bool_<false> >::type type;
  534. };
  535. // metafunction used to say if a SM has eventless transitions
  536. template <class Derived>
  537. struct has_fsm_eventless_transition
  538. {
  539. typedef typename create_stt<Derived>::type Stt;
  540. typedef typename generate_event_set<Stt>::type event_list;
  541. typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
  542. event_list,is_completion_event< ::boost::mpl::placeholders::_1 > >::value != 0> type;
  543. };
  544. template <class Derived>
  545. struct find_completion_events
  546. {
  547. typedef typename create_stt<Derived>::type Stt;
  548. typedef typename generate_event_set<Stt>::type event_list;
  549. typedef typename ::boost::mpl::fold<
  550. event_list, ::boost::fusion::set<>,
  551. ::boost::mpl::if_<
  552. is_completion_event< ::boost::mpl::placeholders::_2>,
  553. boost::msm::back11::set_unique_insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >,
  554. ::boost::mpl::placeholders::_1 >
  555. >::type type;
  556. };
  557. template <class Transition>
  558. struct make_vector
  559. {
  560. typedef ::boost::fusion::vector<Transition> type;
  561. };
  562. template< typename Entry >
  563. struct get_first_element_pair_second
  564. {
  565. typedef typename ::boost::mpl::front<typename Entry::second>::type type;
  566. };
  567. template< typename Entry >
  568. struct get_first_element_pair_second2
  569. {
  570. //typedef typename ::boost::mpl::front<typename Entry::second>::type type;
  571. typedef typename ::boost::remove_reference<typename ::boost::fusion::result_of::front<
  572. typename ::boost::fusion::result_of::second<Entry>::type >::type>::type type;
  573. };
  574. //returns the owner of an explicit_entry state
  575. //which is the containing SM if the transition originates from outside the containing SM
  576. //or else the explicit_entry state itself
  577. template <class State,class ContainingSM>
  578. struct get_owner
  579. {
  580. typedef typename ::boost::mpl::if_<
  581. typename ::boost::mpl::not_<typename ::boost::is_same<typename State::owner,
  582. ContainingSM >::type>::type,
  583. typename State::owner,
  584. State >::type type;
  585. };
  586. template <class Sequence,class ContainingSM>
  587. struct get_fork_owner
  588. {
  589. typedef typename ::boost::mpl::front<Sequence>::type seq_front;
  590. typedef typename ::boost::mpl::if_<
  591. typename ::boost::mpl::not_<
  592. typename ::boost::is_same<typename seq_front::owner,ContainingSM>::type>::type,
  593. typename seq_front::owner,
  594. seq_front >::type type;
  595. };
  596. template <class StateType,class ContainingSM>
  597. struct make_exit
  598. {
  599. typedef typename ::boost::mpl::if_<
  600. typename is_pseudo_exit<StateType>::type ,
  601. typename ContainingSM::template exit_pt<StateType>,
  602. typename ::boost::mpl::identity<StateType>::type
  603. >::type type;
  604. };
  605. template <class StateType,class ContainingSM>
  606. struct make_entry
  607. {
  608. typedef typename ::boost::mpl::if_<
  609. typename is_pseudo_entry<StateType>::type ,
  610. typename ContainingSM::template entry_pt<StateType>,
  611. typename ::boost::mpl::if_<
  612. typename is_direct_entry<StateType>::type,
  613. typename ContainingSM::template direct<StateType>,
  614. typename ::boost::mpl::identity<StateType>::type
  615. >::type
  616. >::type type;
  617. };
  618. // metafunction used to say if a SM has pseudo exit states
  619. template <class StateType>
  620. struct has_exit_pseudo_states_helper
  621. {
  622. typedef typename StateType::stt Stt;
  623. typedef typename generate_state_set<Stt>::type state_list;
  624. typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
  625. state_list,is_pseudo_exit< ::boost::mpl::placeholders::_1> >::value != 0> type;
  626. };
  627. template <class StateType>
  628. struct has_exit_pseudo_states
  629. {
  630. typedef typename ::boost::mpl::eval_if<typename is_composite_state<StateType>::type,
  631. has_exit_pseudo_states_helper<StateType>,
  632. ::boost::mpl::bool_<false> >::type type;
  633. };
  634. // builds flags (add internal_flag_list and flag_list). internal_flag_list is used for terminate/interrupt states
  635. template <class StateType>
  636. struct get_flag_list
  637. {
  638. typedef typename ::boost::fusion::result_of::as_vector<
  639. typename ::boost::fusion::result_of::insert_range<
  640. typename StateType::flag_list,
  641. typename ::boost::fusion::result_of::end< typename StateType::flag_list >::type,
  642. typename StateType::internal_flag_list
  643. >::type
  644. >::type type;
  645. };
  646. template <class StateType>
  647. struct is_state_blocking
  648. {
  649. typedef typename ::boost::mpl::fold<
  650. typename get_flag_list<StateType>::type, ::boost::fusion::set<>,
  651. ::boost::mpl::if_<
  652. has_event_blocking_flag< ::boost::mpl::placeholders::_2>,
  653. boost::msm::back11::set_unique_insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >,
  654. ::boost::mpl::placeholders::_1 >
  655. >::type blocking_flags;
  656. typedef typename ::boost::mpl::if_<
  657. ::boost::mpl::empty<blocking_flags>,
  658. ::boost::mpl::bool_<false>,
  659. ::boost::mpl::bool_<true> >::type type;
  660. };
  661. // returns a mpl::bool_<true> if fsm has an event blocking flag in one of its substates
  662. template <class StateType>
  663. struct has_fsm_blocking_states
  664. {
  665. typedef typename create_stt<StateType>::type Stt;
  666. typedef typename generate_state_set<Stt>::type state_list;
  667. typedef typename ::boost::mpl::fold<
  668. state_list, ::boost::fusion::set<>,
  669. ::boost::mpl::if_<
  670. is_state_blocking< ::boost::mpl::placeholders::_2>,
  671. ::boost::mpl::push_back< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >,
  672. ::boost::mpl::placeholders::_1 >
  673. >::type blocking_states;
  674. typedef typename ::boost::mpl::if_<
  675. ::boost::mpl::empty<blocking_states>,
  676. ::boost::mpl::bool_<false>,
  677. ::boost::mpl::bool_<true> >::type type;
  678. };
  679. template <class StateType>
  680. struct is_no_exception_thrown
  681. {
  682. typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
  683. typename StateType::configuration,
  684. has_no_exception_thrown< ::boost::mpl::placeholders::_1 > >::value != 0> found;
  685. typedef typename ::boost::mpl::or_<
  686. typename has_no_exception_thrown<StateType>::type,
  687. found
  688. >::type type;
  689. };
  690. template <class StateType>
  691. struct is_no_message_queue
  692. {
  693. typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
  694. typename StateType::configuration,
  695. has_no_message_queue< ::boost::mpl::placeholders::_1 > >::value != 0> found;
  696. typedef typename ::boost::mpl::or_<
  697. typename has_no_message_queue<StateType>::type,
  698. found
  699. >::type type;
  700. };
  701. template <class StateType>
  702. struct is_active_state_switch_policy
  703. {
  704. typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
  705. typename StateType::configuration,
  706. has_active_state_switch_policy< ::boost::mpl::placeholders::_1 > >::value != 0> found;
  707. typedef typename ::boost::mpl::or_<
  708. typename has_active_state_switch_policy<StateType>::type,
  709. found
  710. >::type type;
  711. };
  712. template <class StateType>
  713. struct get_initial_event
  714. {
  715. typedef typename StateType::initial_event type;
  716. };
  717. template <class StateType>
  718. struct get_final_event
  719. {
  720. typedef typename StateType::final_event type;
  721. };
  722. template <class TransitionTable, class InitState>
  723. struct build_one_orthogonal_region
  724. {
  725. template<typename Row>
  726. struct row_to_incidence :
  727. ::boost::fusion::vector<
  728. ::boost::mpl::pair<
  729. typename Row::next_state_type,
  730. typename Row::transition_event>,
  731. typename Row::current_state_type,
  732. typename Row::next_state_type
  733. > {};
  734. template <class Seq, class Elt>
  735. struct transition_incidence_list_helper
  736. {
  737. typedef typename ::boost::mpl::push_back< Seq, row_to_incidence< Elt > >::type type;
  738. };
  739. typedef typename ::boost::mpl::fold<
  740. TransitionTable,
  741. ::boost::fusion::vector<>,
  742. transition_incidence_list_helper< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2>
  743. >::type transition_incidence_list;
  744. typedef ::boost::msm::mpl_graph::incidence_list_graph<transition_incidence_list>
  745. transition_graph;
  746. struct preordering_dfs_visitor :
  747. ::boost::msm::mpl_graph::dfs_default_visitor_operations
  748. {
  749. template<typename Node, typename Graph, typename State>
  750. struct discover_vertex :
  751. ::boost::mpl::insert<State, Node>
  752. {};
  753. };
  754. typedef typename mpl::first<
  755. typename ::boost::msm::mpl_graph::depth_first_search<
  756. transition_graph,
  757. preordering_dfs_visitor,
  758. ::boost::fusion::set<>,
  759. InitState
  760. >::type
  761. >::type type;
  762. };
  763. template <class Fsm>
  764. struct find_entry_states
  765. {
  766. typedef typename ::boost::mpl::copy<
  767. typename Fsm::substate_list,
  768. ::boost::mpl::inserter<
  769. ::boost::fusion::set<>,
  770. ::boost::mpl::if_<
  771. has_explicit_entry_state< ::boost::mpl::placeholders::_2 >,
  772. boost::msm::back11::set_unique_insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2>,
  773. ::boost::mpl::placeholders::_1
  774. >
  775. >
  776. >::type type;
  777. };
  778. template <class Set1, class Set2>
  779. struct is_common_element
  780. {
  781. typedef typename ::boost::mpl::fold<
  782. Set1, ::boost::mpl::false_,
  783. ::boost::mpl::if_<
  784. ::boost::mpl::has_key<
  785. Set2,
  786. ::boost::mpl::placeholders::_2
  787. >,
  788. ::boost::mpl::true_,
  789. ::boost::mpl::placeholders::_1
  790. >
  791. >::type type;
  792. };
  793. template <class EntryRegion, class AllRegions>
  794. struct add_entry_region
  795. {
  796. typedef typename ::boost::mpl::transform<
  797. AllRegions,
  798. ::boost::mpl::if_<
  799. is_common_element<EntryRegion, ::boost::mpl::placeholders::_1>,
  800. set_insert_range< ::boost::mpl::placeholders::_1, EntryRegion>,
  801. ::boost::mpl::placeholders::_1
  802. >
  803. >::type type;
  804. };
  805. // build a vector of regions states (as a set)
  806. // one set of states for every region
  807. template <class Fsm, class InitStates>
  808. struct build_orthogonal_regions
  809. {
  810. typedef typename
  811. ::boost::mpl::fold<
  812. InitStates, ::boost::fusion::vector0<>,
  813. ::boost::mpl::push_back<
  814. ::boost::mpl::placeholders::_1,
  815. build_one_orthogonal_region< typename Fsm::stt, ::boost::mpl::placeholders::_2 > >
  816. >::type without_entries;
  817. typedef typename
  818. ::boost::mpl::fold<
  819. typename find_entry_states<Fsm>::type, ::boost::fusion::vector0<>,
  820. ::boost::mpl::push_back<
  821. ::boost::mpl::placeholders::_1,
  822. build_one_orthogonal_region< typename Fsm::stt, ::boost::mpl::placeholders::_2 > >
  823. >::type only_entries;
  824. typedef typename ::boost::mpl::fold<
  825. only_entries , without_entries,
  826. add_entry_region< ::boost::mpl::placeholders::_2, ::boost::mpl::placeholders::_1>
  827. >::type type;
  828. };
  829. template <class GraphAsSeqOfSets, class StateType>
  830. struct find_region_index
  831. {
  832. typedef typename
  833. ::boost::mpl::fold<
  834. GraphAsSeqOfSets, ::boost::mpl::pair< ::boost::mpl::int_< -1 > /*res*/, ::boost::mpl::int_<0> /*counter*/ >,
  835. ::boost::mpl::if_<
  836. ::boost::mpl::has_key< ::boost::mpl::placeholders::_2, StateType >,
  837. ::boost::mpl::pair<
  838. ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
  839. ::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > >
  840. >,
  841. ::boost::mpl::pair<
  842. ::boost::mpl::first< ::boost::mpl::placeholders::_1 >,
  843. ::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > >
  844. >
  845. >
  846. >::type result_pair;
  847. typedef typename ::boost::mpl::first<result_pair>::type type;
  848. enum {value = type::value};
  849. };
  850. template <class Fsm>
  851. struct check_regions_orthogonality
  852. {
  853. typedef typename build_orthogonal_regions< Fsm,typename Fsm::initial_states>::type regions;
  854. typedef typename ::boost::mpl::fold<
  855. regions, ::boost::mpl::int_<0>,
  856. ::boost::mpl::plus< ::boost::mpl::placeholders::_1 , ::boost::mpl::size< ::boost::mpl::placeholders::_2> >
  857. >::type number_of_states_in_regions;
  858. typedef typename ::boost::mpl::fold<
  859. regions,mpl::set0<>,
  860. set_insert_range<
  861. ::boost::mpl::placeholders::_1,
  862. ::boost::mpl::placeholders::_2 >
  863. >::type one_big_states_set;
  864. enum {states_in_regions_raw = number_of_states_in_regions::value};
  865. enum {cumulated_states_in_regions_raw = ::boost::mpl::size<one_big_states_set>::value};
  866. };
  867. template <class Fsm>
  868. struct check_no_unreachable_state
  869. {
  870. typedef typename check_regions_orthogonality<Fsm>::one_big_states_set states_in_regions;
  871. typedef typename set_insert_range<
  872. states_in_regions,
  873. typename ::boost::mpl::eval_if<
  874. typename has_explicit_creation<Fsm>::type,
  875. get_explicit_creation<Fsm>,
  876. ::boost::fusion::result_of::make_vector<>
  877. >::type
  878. >::type with_explicit_creation;
  879. enum {states_in_fsm = ::boost::mpl::size< typename Fsm::substate_list >::value};
  880. enum {cumulated_states_in_regions = ::boost::mpl::size< with_explicit_creation >::value};
  881. };
  882. // helper to find out if a SM has an active exit state and is therefore waiting for exiting
  883. template <class StateType,class OwnerFct,class FSM>
  884. inline
  885. typename ::boost::enable_if<typename ::boost::mpl::and_<typename is_composite_state<FSM>::type,
  886. typename is_pseudo_exit<StateType>::type>,bool >::type
  887. is_exit_state_active(FSM& fsm)
  888. {
  889. typedef typename OwnerFct::type Composite;
  890. //typedef typename create_stt<Composite>::type stt;
  891. typedef typename Composite::stt stt;
  892. int state_id = get_state_id<stt,StateType>::type::value;
  893. Composite& comp = fsm.template get_state<Composite&>();
  894. return (std::find(comp.current_state(),comp.current_state()+Composite::nr_regions::value,state_id)
  895. !=comp.current_state()+Composite::nr_regions::value);
  896. }
  897. template <class StateType,class OwnerFct,class FSM>
  898. inline
  899. typename ::boost::disable_if<typename ::boost::mpl::and_<typename is_composite_state<FSM>::type,
  900. typename is_pseudo_exit<StateType>::type>,bool >::type
  901. is_exit_state_active(FSM&)
  902. {
  903. return false;
  904. }
  905. } } }//boost::msm::back11
  906. #endif // BOOST_MSM_BACK11_METAFUNCTIONS_H