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