metafunctions.hpp 35 KB

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