metafunctions.hpp 35 KB

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