metafunctions.hpp 35 KB

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