metafunctions.hpp 36 KB

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