Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:38:24

0001 // Copyright 2008 Christophe Henry
0002 // henry UNDERSCORE christophe AT hotmail DOT com
0003 // This is an extended version of the state machine available in the boost::mpl library
0004 // Distributed under the same license as the original.
0005 // Copyright for the original version:
0006 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
0007 // under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at
0009 // http://www.boost.org/LICENSE_1_0.txt)
0010 
0011 #ifndef BOOST_MSM_BACK_METAFUNCTIONS_H
0012 #define BOOST_MSM_BACK_METAFUNCTIONS_H
0013 
0014 #include <algorithm>
0015 
0016 #include <boost/mpl/set.hpp>
0017 #include <boost/mpl/at.hpp>
0018 #include <boost/mpl/pair.hpp>
0019 #include <boost/mpl/map.hpp>
0020 #include <boost/mpl/int.hpp>
0021 #include <boost/mpl/has_xxx.hpp>
0022 #include <boost/mpl/find.hpp>
0023 #include <boost/mpl/count_if.hpp>
0024 #include <boost/mpl/fold.hpp>
0025 #include <boost/mpl/if.hpp>
0026 #include <boost/mpl/has_key.hpp>
0027 #include <boost/mpl/insert.hpp>
0028 #include <boost/mpl/next_prior.hpp>
0029 #include <boost/mpl/map.hpp>
0030 #include <boost/mpl/push_back.hpp>
0031 #include <boost/mpl/vector.hpp>
0032 #include <boost/mpl/is_sequence.hpp>
0033 #include <boost/mpl/size.hpp>
0034 #include <boost/mpl/transform.hpp>
0035 #include <boost/mpl/begin_end.hpp>
0036 #include <boost/mpl/bool.hpp>
0037 #include <boost/mpl/empty.hpp>
0038 #include <boost/mpl/identity.hpp>
0039 #include <boost/mpl/eval_if.hpp>
0040 #include <boost/mpl/insert_range.hpp>
0041 #include <boost/mpl/front.hpp>
0042 #include <boost/mpl/logical.hpp>
0043 #include <boost/mpl/plus.hpp>
0044 #include <boost/mpl/copy_if.hpp>
0045 #include <boost/mpl/back_inserter.hpp>
0046 #include <boost/mpl/transform.hpp>
0047 
0048 #include <boost/fusion/include/as_vector.hpp>
0049 #include <boost/fusion/include/insert_range.hpp>
0050 
0051 #include <boost/type_traits/is_same.hpp>
0052 #include <boost/utility/enable_if.hpp>
0053 
0054 #include <boost/msm/row_tags.hpp>
0055 
0056 // mpl_graph graph implementation and depth first search
0057 #include <boost/msm/mpl_graph/incidence_list_graph.hpp>
0058 #include <boost/msm/mpl_graph/depth_first_search.hpp>
0059 
0060 BOOST_MPL_HAS_XXX_TRAIT_DEF(explicit_creation)
0061 BOOST_MPL_HAS_XXX_TRAIT_DEF(pseudo_entry)
0062 BOOST_MPL_HAS_XXX_TRAIT_DEF(pseudo_exit)
0063 BOOST_MPL_HAS_XXX_TRAIT_DEF(concrete_exit_state)
0064 BOOST_MPL_HAS_XXX_TRAIT_DEF(composite_tag)
0065 BOOST_MPL_HAS_XXX_TRAIT_DEF(not_real_row_tag)
0066 BOOST_MPL_HAS_XXX_TRAIT_DEF(event_blocking_flag)
0067 BOOST_MPL_HAS_XXX_TRAIT_DEF(explicit_entry_state)
0068 BOOST_MPL_HAS_XXX_TRAIT_DEF(completion_event)
0069 BOOST_MPL_HAS_XXX_TRAIT_DEF(no_exception_thrown)
0070 BOOST_MPL_HAS_XXX_TRAIT_DEF(no_message_queue)
0071 BOOST_MPL_HAS_XXX_TRAIT_DEF(activate_deferred_events)
0072 BOOST_MPL_HAS_XXX_TRAIT_DEF(wrapped_entry)
0073 BOOST_MPL_HAS_XXX_TRAIT_DEF(active_state_switch_policy)
0074 
0075 namespace boost { namespace msm { namespace back
0076 {
0077 template <typename Sequence, typename Range>
0078 struct set_insert_range
0079 {
0080     typedef typename ::boost::mpl::fold<
0081         Range,Sequence, 
0082         ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >
0083     >::type type;
0084 };
0085 
0086 // returns the current state type of a transition
0087 template <class Transition>
0088 struct transition_source_type
0089 {
0090     typedef typename Transition::current_state_type type;
0091 };
0092 
0093 // returns the target state type of a transition
0094 template <class Transition>
0095 struct transition_target_type
0096 {
0097     typedef typename Transition::next_state_type type;
0098 };
0099 
0100 // helper functions for generate_state_ids
0101 // create a pair of a state and a passed id for source and target states
0102 template <class Id,class Transition>
0103 struct make_pair_source_state_id
0104 {
0105     typedef typename ::boost::mpl::pair<typename Transition::current_state_type,Id> type;
0106 };
0107 template <class Id,class Transition>
0108 struct make_pair_target_state_id
0109 {
0110     typedef typename ::boost::mpl::pair<typename Transition::next_state_type,Id> type;
0111 };
0112 
0113 // iterates through a transition table and automatically generates ids starting at 0
0114 // first the source states, transition up to down
0115 // then the target states, up to down
0116 template <class stt>
0117 struct generate_state_ids
0118 {
0119     typedef typename 
0120         ::boost::mpl::fold<
0121         stt,::boost::mpl::pair< ::boost::mpl::map< >, ::boost::mpl::int_<0> >,
0122         ::boost::mpl::pair<
0123             ::boost::mpl::if_<
0124                      ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
0125                                             transition_source_type< ::boost::mpl::placeholders::_2> >,
0126                      ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
0127                      ::boost::mpl::insert< ::boost::mpl::first<mpl::placeholders::_1>,
0128                                 make_pair_source_state_id< ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
0129                                                            ::boost::mpl::placeholders::_2> >
0130                       >,
0131             ::boost::mpl::if_<
0132                     ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
0133                                            transition_source_type< ::boost::mpl::placeholders::_2> >,
0134                     ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
0135                     ::boost::mpl::next< ::boost::mpl::second<mpl::placeholders::_1 > >
0136                     >
0137         > //pair
0138         >::type source_state_ids;
0139     typedef typename ::boost::mpl::first<source_state_ids>::type source_state_map;
0140     typedef typename ::boost::mpl::second<source_state_ids>::type highest_state_id;
0141 
0142 
0143     typedef typename 
0144         ::boost::mpl::fold<
0145         stt,::boost::mpl::pair<source_state_map,highest_state_id >,
0146         ::boost::mpl::pair<
0147             ::boost::mpl::if_<
0148                      ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
0149                                             transition_target_type< ::boost::mpl::placeholders::_2> >,
0150                      ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
0151                      ::boost::mpl::insert< ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
0152                                 make_pair_target_state_id< ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
0153                                 ::boost::mpl::placeholders::_2> >
0154                      >,
0155             ::boost::mpl::if_<
0156                     ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>,
0157                                            transition_target_type< ::boost::mpl::placeholders::_2> >,
0158                     ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
0159                     ::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > >
0160                     >
0161         > //pair
0162         >::type all_state_ids;
0163     typedef typename ::boost::mpl::first<all_state_ids>::type type;
0164 };
0165 
0166 template <class Fsm>
0167 struct get_active_state_switch_policy_helper
0168 {
0169     typedef typename Fsm::active_state_switch_policy type;
0170 };
0171 template <class Iter>
0172 struct get_active_state_switch_policy_helper2
0173 {
0174     typedef typename boost::mpl::deref<Iter>::type Fsm;
0175     typedef typename Fsm::active_state_switch_policy type;
0176 };
0177 // returns the active state switching policy
0178 template <class Fsm>
0179 struct get_active_state_switch_policy
0180 {
0181     typedef typename ::boost::mpl::find_if<
0182         typename Fsm::configuration,
0183         has_active_state_switch_policy< ::boost::mpl::placeholders::_1 > >::type iter;
0184 
0185     typedef typename ::boost::mpl::eval_if<
0186         typename ::boost::is_same<
0187             iter, 
0188             typename ::boost::mpl::end<typename Fsm::configuration>::type
0189         >::type,
0190         get_active_state_switch_policy_helper<Fsm>,
0191         get_active_state_switch_policy_helper2< iter >
0192     >::type type;
0193 };
0194 
0195 // returns the id of a given state
0196 template <class stt,class State>
0197 struct get_state_id
0198 {
0199     typedef typename ::boost::mpl::at<typename generate_state_ids<stt>::type,State>::type type;
0200     enum {value = type::value};
0201 };
0202 
0203 // returns a mpl::vector containing the init states of a state machine
0204 template <class States>
0205 struct get_initial_states 
0206 {
0207     typedef typename ::boost::mpl::if_<
0208         ::boost::mpl::is_sequence<States>,
0209         States,
0210         typename ::boost::mpl::push_back< ::boost::mpl::vector0<>,States>::type >::type type;
0211 };
0212 // returns a mpl::int_ containing the size of a region. If the argument is not a sequence, returns 1
0213 template <class region>
0214 struct get_number_of_regions 
0215 {
0216     typedef typename mpl::if_<
0217         ::boost::mpl::is_sequence<region>,
0218         ::boost::mpl::size<region>,
0219         ::boost::mpl::int_<1> >::type type;
0220 };
0221 
0222 // builds a mpl::vector of initial states
0223 //TODO remove duplicate from get_initial_states
0224 template <class region>
0225 struct get_regions_as_sequence 
0226 {
0227     typedef typename ::boost::mpl::if_<
0228         ::boost::mpl::is_sequence<region>,
0229         region,
0230         typename ::boost::mpl::push_back< ::boost::mpl::vector0<>,region>::type >::type type;
0231 };
0232 
0233 template <class ToCreateSeq>
0234 struct get_explicit_creation_as_sequence 
0235 {
0236     typedef typename ::boost::mpl::if_<
0237         ::boost::mpl::is_sequence<ToCreateSeq>,
0238         ToCreateSeq,
0239         typename ::boost::mpl::push_back< ::boost::mpl::vector0<>,ToCreateSeq>::type >::type type;
0240 };
0241 
0242 // returns true if 2 transitions have the same source (used to remove duplicates in search of composite states)
0243 template <class stt,class Transition1,class Transition2>
0244 struct have_same_source
0245 {
0246     enum {current_state1 = get_state_id<stt,typename Transition1::current_state_type >::type::value};
0247     enum {current_state2 = get_state_id<stt,typename Transition2::current_state_type >::type::value};
0248     enum {value = ((int)current_state1 == (int)current_state2) };
0249 };
0250 
0251 
0252 // A metafunction that returns the Event associated with a transition.
0253 template <class Transition>
0254 struct transition_event
0255 {
0256     typedef typename Transition::transition_event type;
0257 };
0258 
0259 // returns true for composite states
0260 template <class State>
0261 struct is_composite_state
0262 {
0263     enum {value = has_composite_tag<State>::type::value};
0264     typedef typename has_composite_tag<State>::type type;
0265 };
0266 
0267 // transform a transition table in a container of source states
0268 template <class stt>
0269 struct keep_source_names
0270 {
0271     // instead of the rows we want only the names of the states (from source)
0272     typedef typename 
0273         ::boost::mpl::transform<
0274         stt,transition_source_type< ::boost::mpl::placeholders::_1> >::type type;
0275 };
0276 
0277 // transform a transition table in a container of target states
0278 template <class stt>
0279 struct keep_target_names
0280 {
0281     // instead of the rows we want only the names of the states (from source)
0282     typedef typename 
0283         ::boost::mpl::transform<
0284         stt,transition_target_type< ::boost::mpl::placeholders::_1> >::type type;
0285 };
0286 
0287 template <class stt>
0288 struct generate_state_set
0289 {
0290     // keep in the original transition table only the source/target state types
0291     typedef typename keep_source_names<stt>::type sources;
0292     typedef typename keep_target_names<stt>::type targets;
0293     typedef typename 
0294         ::boost::mpl::fold<
0295         sources, ::boost::mpl::set<>,
0296         ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2>
0297         >::type source_set;
0298     typedef typename 
0299         ::boost::mpl::fold<
0300         targets,source_set,
0301         ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2>
0302         >::type type;
0303 };
0304 
0305 // iterates through the transition table and generate a mpl::set<> containing all the events
0306 template <class stt>
0307 struct generate_event_set
0308 {
0309     typedef typename 
0310         ::boost::mpl::fold<
0311             stt, ::boost::mpl::set<>,
0312             ::boost::mpl::if_<
0313                 ::boost::mpl::has_key< ::boost::mpl::placeholders::_1, 
0314                                        transition_event< ::boost::mpl::placeholders::_2> >,
0315                 ::boost::mpl::placeholders::_1,
0316                 ::boost::mpl::insert< ::boost::mpl::placeholders::_1,
0317                                       transition_event< ::boost::mpl::placeholders::_2> > >
0318         >::type type;
0319 };
0320 
0321 // returns a mpl::bool_<true> if State has Event as deferred event
0322 template <class State, class Event>
0323 struct has_state_delayed_event  
0324 {
0325     typedef typename ::boost::mpl::find<typename State::deferred_events,Event>::type found;
0326     typedef typename ::boost::mpl::if_<
0327         ::boost::is_same<found,typename ::boost::mpl::end<typename State::deferred_events>::type >,
0328         ::boost::mpl::bool_<false>,
0329         ::boost::mpl::bool_<true> >::type type;
0330 };
0331 // returns a mpl::bool_<true> if State has any deferred event
0332 template <class State>
0333 struct has_state_delayed_events  
0334 {
0335     typedef typename ::boost::mpl::if_<
0336         ::boost::mpl::empty<typename State::deferred_events>,
0337         ::boost::mpl::bool_<false>,
0338         ::boost::mpl::bool_<true> >::type type;
0339 };
0340 
0341 // Template used to create dummy entries for initial states not found in the stt.
0342 template< typename T1 >
0343 struct not_a_row
0344 {
0345     typedef int not_real_row_tag;
0346     struct dummy_event 
0347     {
0348     };
0349     typedef T1                  current_state_type;
0350     typedef T1                  next_state_type;
0351     typedef dummy_event         transition_event;
0352 };
0353 
0354 // metafunctions used to find out if a state is entry, exit or something else
0355 template <class State>
0356 struct is_pseudo_entry 
0357 {
0358     typedef typename ::boost::mpl::if_< typename has_pseudo_entry<State>::type,
0359         ::boost::mpl::bool_<true>,::boost::mpl::bool_<false> 
0360     >::type type;
0361 };
0362 // says if a state is an exit pseudo state
0363 template <class State>
0364 struct is_pseudo_exit 
0365 {
0366     typedef typename ::boost::mpl::if_< typename has_pseudo_exit<State>::type,
0367         ::boost::mpl::bool_<true>, ::boost::mpl::bool_<false> 
0368     >::type type;
0369 };
0370 // says if a state is an entry pseudo state or an explicit entry
0371 template <class State>
0372 struct is_direct_entry 
0373 {
0374     typedef typename ::boost::mpl::if_< typename has_explicit_entry_state<State>::type,
0375         ::boost::mpl::bool_<true>, ::boost::mpl::bool_<false> 
0376     >::type type;
0377 };
0378 
0379 //converts a "fake" (simulated in a state_machine_ description )state into one which will really get created
0380 template <class StateType,class CompositeType>
0381 struct convert_fake_state
0382 {
0383     // converts a state (explicit entry) into the state we really are going to create (explicit<>)
0384     typedef typename ::boost::mpl::if_<
0385         typename is_direct_entry<StateType>::type,
0386         typename CompositeType::template direct<StateType>,
0387         typename ::boost::mpl::identity<StateType>::type
0388     >::type type;
0389 };
0390 
0391 template <class StateType>
0392 struct get_explicit_creation 
0393 {
0394     typedef typename StateType::explicit_creation type;
0395 };
0396 
0397 template <class StateType>
0398 struct get_wrapped_entry 
0399 {
0400     typedef typename StateType::wrapped_entry type;
0401 };
0402 // used for states created with explicit_creation
0403 // if the state is an explicit entry, we reach for the wrapped state
0404 // otherwise, this returns the state itself
0405 template <class StateType>
0406 struct get_wrapped_state 
0407 {
0408     typedef typename ::boost::mpl::eval_if<
0409                 typename has_wrapped_entry<StateType>::type,
0410                 get_wrapped_entry<StateType>,
0411                 ::boost::mpl::identity<StateType> >::type type;
0412 };
0413 
0414 template <class Derived>
0415 struct create_stt 
0416 {
0417     //typedef typename Derived::transition_table stt;
0418     typedef typename Derived::real_transition_table Stt;
0419     // get the state set
0420     typedef typename generate_state_set<Stt>::type states;
0421     // transform the initial region(s) in a sequence
0422     typedef typename get_regions_as_sequence<typename Derived::initial_state>::type init_states;
0423     // iterate through the initial states and add them in the stt if not already there
0424     typedef typename 
0425         ::boost::mpl::fold<
0426         init_states,Stt,
0427         ::boost::mpl::if_<
0428                  ::boost::mpl::has_key<states, ::boost::mpl::placeholders::_2>,
0429                  ::boost::mpl::placeholders::_1,
0430                  ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::end< ::boost::mpl::placeholders::_1>,
0431                              not_a_row< get_wrapped_state< ::boost::mpl::placeholders::_2> > > 
0432                   >
0433         >::type with_init;
0434     // do the same for states marked as explicitly created
0435     typedef typename get_explicit_creation_as_sequence<
0436        typename ::boost::mpl::eval_if<
0437             typename has_explicit_creation<Derived>::type,
0438             get_explicit_creation<Derived>,
0439             ::boost::mpl::vector0<> >::type
0440         >::type fake_explicit_created;
0441 
0442     typedef typename 
0443         ::boost::mpl::transform<
0444         fake_explicit_created,convert_fake_state< ::boost::mpl::placeholders::_1,Derived> >::type explicit_created;
0445 
0446     typedef typename 
0447         ::boost::mpl::fold<
0448         explicit_created,with_init,
0449         ::boost::mpl::if_<
0450                  ::boost::mpl::has_key<states, ::boost::mpl::placeholders::_2>,
0451                  ::boost::mpl::placeholders::_1,
0452                  ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::end<mpl::placeholders::_1>,
0453                              not_a_row< get_wrapped_state< ::boost::mpl::placeholders::_2> > > 
0454                   >
0455         >::type type;
0456 };
0457 
0458 // returns the transition table of a Composite state
0459 template <class Composite>
0460 struct get_transition_table
0461 {
0462     typedef typename create_stt<Composite>::type type;
0463 };
0464 
0465 // recursively builds an internal table including those of substates, sub-substates etc.
0466 // variant for submachines
0467 template <class StateType,class IsComposite>
0468 struct recursive_get_internal_transition_table
0469 {
0470     // get the composite's internal table
0471     typedef typename StateType::internal_transition_table composite_table;
0472     // and for every substate (state of submachine), recursively get the internal transition table
0473     typedef typename generate_state_set<typename StateType::stt>::type composite_states;
0474     typedef typename ::boost::mpl::fold<
0475             composite_states, composite_table,
0476             ::boost::mpl::insert_range< ::boost::mpl::placeholders::_1, ::boost::mpl::end< ::boost::mpl::placeholders::_1>,
0477              recursive_get_internal_transition_table< ::boost::mpl::placeholders::_2, is_composite_state< ::boost::mpl::placeholders::_2> >
0478              >
0479     >::type type;
0480 };
0481 // stop iterating on leafs (simple states)
0482 template <class StateType>
0483 struct recursive_get_internal_transition_table<StateType, ::boost::mpl::false_ >
0484 {
0485     typedef typename StateType::internal_transition_table type;
0486 };
0487 // recursively get a transition table for a given composite state.
0488 // returns the transition table for this state + the tables of all composite sub states recursively
0489 template <class Composite>
0490 struct recursive_get_transition_table
0491 {
0492     // get the transition table of the state if it's a state machine
0493     typedef typename ::boost::mpl::eval_if<typename is_composite_state<Composite>::type,
0494         get_transition_table<Composite>,
0495         ::boost::mpl::vector0<>
0496     >::type org_table;
0497 
0498     typedef typename generate_state_set<org_table>::type states;
0499 
0500     // and for every substate, recursively get the transition table if it's a state machine
0501     typedef typename ::boost::mpl::fold<
0502         states,org_table,
0503         ::boost::mpl::insert_range< ::boost::mpl::placeholders::_1, ::boost::mpl::end<mpl::placeholders::_1>,
0504         recursive_get_transition_table< ::boost::mpl::placeholders::_2 > >
0505     >::type type;
0506 
0507 };
0508 
0509 // metafunction used to say if a SM has pseudo exit states
0510 template <class Derived>
0511 struct has_fsm_deferred_events 
0512 {
0513     typedef typename create_stt<Derived>::type Stt;
0514     typedef typename generate_state_set<Stt>::type state_list;
0515 
0516     typedef typename ::boost::mpl::or_<
0517         typename has_activate_deferred_events<Derived>::type,
0518         ::boost::mpl::bool_< ::boost::mpl::count_if<
0519                 typename Derived::configuration,
0520                 has_activate_deferred_events< ::boost::mpl::placeholders::_1 > >::value != 0> 
0521     >::type found_in_fsm;
0522 
0523     typedef typename ::boost::mpl::or_<
0524             found_in_fsm,
0525             ::boost::mpl::bool_< ::boost::mpl::count_if<
0526                 state_list,has_state_delayed_events<
0527                     ::boost::mpl::placeholders::_1 > >::value != 0>
0528             >::type type;
0529 };
0530 
0531 // returns a mpl::bool_<true> if State has any delayed event
0532 template <class Event>
0533 struct is_completion_event  
0534 {
0535     typedef typename ::boost::mpl::if_<
0536         has_completion_event<Event>,
0537         ::boost::mpl::bool_<true>,
0538         ::boost::mpl::bool_<false> >::type type;
0539 };
0540 // metafunction used to say if a SM has eventless transitions
0541 template <class Derived>
0542 struct has_fsm_eventless_transition 
0543 {
0544     typedef typename create_stt<Derived>::type Stt;
0545     typedef typename generate_event_set<Stt>::type event_list;
0546 
0547     typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
0548         event_list,is_completion_event< ::boost::mpl::placeholders::_1 > >::value != 0> type;
0549 };
0550 template <class Derived>
0551 struct find_completion_events 
0552 {
0553     typedef typename create_stt<Derived>::type Stt;
0554     typedef typename generate_event_set<Stt>::type event_list;
0555 
0556     typedef typename ::boost::mpl::fold<
0557         event_list, ::boost::mpl::set<>,
0558         ::boost::mpl::if_<
0559                  is_completion_event< ::boost::mpl::placeholders::_2>,
0560                  ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >, 
0561                  ::boost::mpl::placeholders::_1 >
0562     >::type type;
0563 };
0564 
0565 template <class Transition>
0566 struct make_vector 
0567 {
0568     typedef ::boost::mpl::vector<Transition> type;
0569 };
0570 template< typename Entry > 
0571 struct get_first_element_pair_second
0572 { 
0573     typedef typename ::boost::mpl::front<typename Entry::second>::type type;
0574 }; 
0575 
0576  //returns the owner of an explicit_entry state
0577  //which is the containing SM if the transition originates from outside the containing SM
0578  //or else the explicit_entry state itself
0579 template <class State,class ContainingSM>
0580 struct get_owner 
0581 {
0582     typedef typename ::boost::mpl::if_<
0583         typename ::boost::mpl::not_<typename ::boost::is_same<typename State::owner,
0584                                                               ContainingSM >::type>::type,
0585         typename State::owner, 
0586         State >::type type;
0587 };
0588 
0589 template <class Sequence,class ContainingSM>
0590 struct get_fork_owner 
0591 {
0592     typedef typename ::boost::mpl::front<Sequence>::type seq_front;
0593     typedef typename ::boost::mpl::if_<
0594                     typename ::boost::mpl::not_<
0595                         typename ::boost::is_same<typename seq_front::owner,ContainingSM>::type>::type,
0596                     typename seq_front::owner, 
0597                     seq_front >::type type;
0598 };
0599 
0600 template <class StateType,class ContainingSM>
0601 struct make_exit 
0602 {
0603     typedef typename ::boost::mpl::if_<
0604              typename is_pseudo_exit<StateType>::type ,
0605              typename ContainingSM::template exit_pt<StateType>,
0606              typename ::boost::mpl::identity<StateType>::type
0607             >::type type;
0608 };
0609 
0610 template <class StateType,class ContainingSM>
0611 struct make_entry 
0612 {
0613     typedef typename ::boost::mpl::if_<
0614         typename is_pseudo_entry<StateType>::type ,
0615         typename ContainingSM::template entry_pt<StateType>,
0616         typename ::boost::mpl::if_<
0617                 typename is_direct_entry<StateType>::type,
0618                 typename ContainingSM::template direct<StateType>,
0619                 typename ::boost::mpl::identity<StateType>::type
0620                 >::type
0621         >::type type;
0622 };
0623 // metafunction used to say if a SM has pseudo exit states
0624 template <class StateType>
0625 struct has_exit_pseudo_states_helper 
0626 {
0627     typedef typename StateType::stt Stt;
0628     typedef typename generate_state_set<Stt>::type state_list;
0629 
0630     typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
0631                 state_list,is_pseudo_exit< ::boost::mpl::placeholders::_1> >::value != 0> type;
0632 };
0633 template <class StateType>
0634 struct has_exit_pseudo_states 
0635 {
0636     typedef typename ::boost::mpl::eval_if<typename is_composite_state<StateType>::type,
0637         has_exit_pseudo_states_helper<StateType>,
0638         ::boost::mpl::bool_<false> >::type type;
0639 };
0640 
0641 // builds flags (add internal_flag_list and flag_list). internal_flag_list is used for terminate/interrupt states
0642 //template <class StateType>
0643 //struct get_flag_list
0644 //{
0645 //    typedef typename ::boost::mpl::insert_range<
0646 //        typename StateType::flag_list,
0647 //        typename ::boost::mpl::end< typename StateType::flag_list >::type,
0648 //        typename StateType::internal_flag_list
0649 //    >::type type;
0650 //};
0651 template <class StateType>
0652 struct get_flag_list
0653 {
0654     typedef typename ::boost::fusion::result_of::as_vector<
0655         typename ::boost::fusion::result_of::insert_range<
0656             typename StateType::flag_list,
0657             typename ::boost::fusion::result_of::end< typename StateType::flag_list >::type,
0658             typename StateType::internal_flag_list
0659         >::type
0660     >::type type;
0661 };
0662 
0663 template <class StateType>
0664 struct is_state_blocking 
0665 {
0666     typedef typename ::boost::mpl::fold<
0667         typename get_flag_list<StateType>::type, ::boost::mpl::set<>,
0668         ::boost::mpl::if_<
0669                  has_event_blocking_flag< ::boost::mpl::placeholders::_2>,
0670                  ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >, 
0671                  ::boost::mpl::placeholders::_1 >
0672     >::type blocking_flags;
0673 
0674     typedef typename ::boost::mpl::if_<
0675         ::boost::mpl::empty<blocking_flags>,
0676         ::boost::mpl::bool_<false>,
0677         ::boost::mpl::bool_<true> >::type type;
0678 };
0679 // returns a mpl::bool_<true> if fsm has an event blocking flag in one of its substates
0680 template <class StateType>
0681 struct has_fsm_blocking_states  
0682 {
0683     typedef typename create_stt<StateType>::type Stt;
0684     typedef typename generate_state_set<Stt>::type state_list;
0685 
0686     typedef typename ::boost::mpl::fold<
0687         state_list, ::boost::mpl::set<>,
0688         ::boost::mpl::if_<
0689                  is_state_blocking< ::boost::mpl::placeholders::_2>,
0690                  ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >, 
0691                  ::boost::mpl::placeholders::_1 >
0692     >::type blocking_states;
0693 
0694     typedef typename ::boost::mpl::if_<
0695         ::boost::mpl::empty<blocking_states>,
0696         ::boost::mpl::bool_<false>,
0697         ::boost::mpl::bool_<true> >::type type;
0698 };
0699 
0700 template <class StateType>
0701 struct is_no_exception_thrown
0702 {
0703     typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
0704         typename StateType::configuration,
0705         has_no_exception_thrown< ::boost::mpl::placeholders::_1 > >::value != 0> found;
0706 
0707     typedef typename ::boost::mpl::or_<
0708         typename has_no_exception_thrown<StateType>::type,
0709         found
0710     >::type type;
0711 };
0712 
0713 template <class StateType>
0714 struct is_no_message_queue
0715 {
0716     typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
0717         typename StateType::configuration,
0718         has_no_message_queue< ::boost::mpl::placeholders::_1 > >::value != 0> found;
0719 
0720     typedef typename ::boost::mpl::or_<
0721         typename has_no_message_queue<StateType>::type,
0722         found
0723     >::type type;
0724 };
0725 
0726 template <class StateType>
0727 struct is_active_state_switch_policy 
0728 {
0729     typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
0730         typename StateType::configuration,
0731         has_active_state_switch_policy< ::boost::mpl::placeholders::_1 > >::value != 0> found;
0732 
0733     typedef typename ::boost::mpl::or_<
0734         typename has_active_state_switch_policy<StateType>::type,
0735         found
0736     >::type type;
0737 };
0738 
0739 template <class StateType>
0740 struct get_initial_event 
0741 {
0742     typedef typename StateType::initial_event type;
0743 };
0744 
0745 template <class StateType>
0746 struct get_final_event 
0747 {
0748     typedef typename StateType::final_event type;
0749 };
0750 
0751 template <class TransitionTable, class InitState>
0752 struct build_one_orthogonal_region 
0753 {
0754      template<typename Row>
0755      struct row_to_incidence :
0756          ::boost::mpl::vector<
0757                 ::boost::mpl::pair<
0758                     typename Row::next_state_type, 
0759                     typename Row::transition_event>, 
0760                 typename Row::current_state_type, 
0761                 typename Row::next_state_type
0762          > {};
0763 
0764      template <class Seq, class Elt>
0765      struct transition_incidence_list_helper 
0766      {
0767          typedef typename ::boost::mpl::push_back< Seq, row_to_incidence< Elt > >::type type;
0768      };
0769 
0770      typedef typename ::boost::mpl::fold<
0771          TransitionTable,
0772          ::boost::mpl::vector<>,
0773          transition_incidence_list_helper< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2>
0774      >::type transition_incidence_list;
0775 
0776      typedef ::boost::msm::mpl_graph::incidence_list_graph<transition_incidence_list>
0777          transition_graph;
0778 
0779      struct preordering_dfs_visitor : 
0780          ::boost::msm::mpl_graph::dfs_default_visitor_operations 
0781      {    
0782          template<typename Node, typename Graph, typename State>
0783          struct discover_vertex :
0784              ::boost::mpl::insert<State, Node>
0785          {};
0786      };
0787 
0788      typedef typename mpl::first< 
0789          typename ::boost::msm::mpl_graph::depth_first_search<
0790             transition_graph, 
0791             preordering_dfs_visitor,
0792             ::boost::mpl::set<>,
0793             InitState
0794          >::type
0795      >::type type;
0796 };
0797 
0798 template <class Fsm>
0799 struct find_entry_states 
0800 {
0801     typedef typename ::boost::mpl::copy<
0802         typename Fsm::substate_list,
0803         ::boost::mpl::inserter< 
0804             ::boost::mpl::set0<>,
0805             ::boost::mpl::if_<
0806                 has_explicit_entry_state< ::boost::mpl::placeholders::_2 >,
0807                 ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2>,
0808                 ::boost::mpl::placeholders::_1
0809             >
0810         >
0811     >::type type;
0812 };
0813 
0814 template <class Set1, class Set2>
0815 struct is_common_element 
0816 {
0817     typedef typename ::boost::mpl::fold<
0818         Set1, ::boost::mpl::false_,
0819         ::boost::mpl::if_<
0820             ::boost::mpl::has_key<
0821                 Set2,
0822                 ::boost::mpl::placeholders::_2
0823             >,
0824             ::boost::mpl::true_,
0825             ::boost::mpl::placeholders::_1
0826         >
0827     >::type type;
0828 };
0829 
0830 template <class EntryRegion, class AllRegions>
0831 struct add_entry_region 
0832 {
0833     typedef typename ::boost::mpl::transform<
0834         AllRegions, 
0835         ::boost::mpl::if_<
0836             is_common_element<EntryRegion, ::boost::mpl::placeholders::_1>,
0837             set_insert_range< ::boost::mpl::placeholders::_1, EntryRegion>,
0838             ::boost::mpl::placeholders::_1
0839         >
0840     >::type type;
0841 };
0842 
0843 // build a vector of regions states (as a set)
0844 // one set of states for every region
0845 template <class Fsm, class InitStates>
0846 struct build_orthogonal_regions 
0847 {
0848     typedef typename 
0849         ::boost::mpl::fold<
0850             InitStates, ::boost::mpl::vector0<>,
0851             ::boost::mpl::push_back< 
0852                 ::boost::mpl::placeholders::_1, 
0853                 build_one_orthogonal_region< typename Fsm::stt, ::boost::mpl::placeholders::_2 > >
0854         >::type without_entries;
0855 
0856     typedef typename 
0857         ::boost::mpl::fold<
0858         typename find_entry_states<Fsm>::type, ::boost::mpl::vector0<>,
0859             ::boost::mpl::push_back< 
0860                 ::boost::mpl::placeholders::_1, 
0861                 build_one_orthogonal_region< typename Fsm::stt, ::boost::mpl::placeholders::_2 > >
0862         >::type only_entries;
0863 
0864     typedef typename ::boost::mpl::fold<
0865         only_entries , without_entries,
0866         add_entry_region< ::boost::mpl::placeholders::_2, ::boost::mpl::placeholders::_1>
0867     >::type type;
0868 };
0869 
0870 template <class GraphAsSeqOfSets, class StateType>
0871 struct find_region_index
0872 {
0873     typedef typename 
0874         ::boost::mpl::fold<
0875             GraphAsSeqOfSets, ::boost::mpl::pair< ::boost::mpl::int_< -1 > /*res*/, ::boost::mpl::int_<0> /*counter*/ >,
0876             ::boost::mpl::if_<
0877                 ::boost::mpl::has_key< ::boost::mpl::placeholders::_2, StateType >,
0878                 ::boost::mpl::pair< 
0879                     ::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
0880                     ::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > >
0881                 >,
0882                 ::boost::mpl::pair< 
0883                     ::boost::mpl::first< ::boost::mpl::placeholders::_1 >,
0884                     ::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > >
0885                 >
0886             >
0887         >::type result_pair;
0888     typedef typename ::boost::mpl::first<result_pair>::type type;
0889     enum {value = type::value};
0890 };
0891 
0892 template <class Fsm>
0893 struct check_regions_orthogonality
0894 {
0895     typedef typename build_orthogonal_regions< Fsm,typename Fsm::initial_states>::type regions;
0896     
0897     typedef typename ::boost::mpl::fold<
0898         regions, ::boost::mpl::int_<0>,
0899         ::boost::mpl::plus< ::boost::mpl::placeholders::_1 , ::boost::mpl::size< ::boost::mpl::placeholders::_2> >
0900     >::type number_of_states_in_regions;
0901 
0902     typedef typename ::boost::mpl::fold<
0903             regions,mpl::set0<>,
0904             set_insert_range< 
0905                     ::boost::mpl::placeholders::_1, 
0906                     ::boost::mpl::placeholders::_2 > 
0907     >::type one_big_states_set;
0908 
0909     enum {states_in_regions_raw = number_of_states_in_regions::value};
0910     enum {cumulated_states_in_regions_raw = ::boost::mpl::size<one_big_states_set>::value};
0911 };
0912 
0913 template <class Fsm>
0914 struct check_no_unreachable_state
0915 {
0916     typedef typename check_regions_orthogonality<Fsm>::one_big_states_set states_in_regions;
0917 
0918     typedef typename set_insert_range<
0919         states_in_regions, 
0920         typename ::boost::mpl::eval_if<
0921             typename has_explicit_creation<Fsm>::type,
0922             get_explicit_creation<Fsm>,
0923             ::boost::mpl::vector0<>
0924         >::type
0925     >::type with_explicit_creation;
0926 
0927     enum {states_in_fsm = ::boost::mpl::size< typename Fsm::substate_list >::value};
0928     enum {cumulated_states_in_regions = ::boost::mpl::size< with_explicit_creation >::value};
0929 };
0930 
0931 // helper to find out if a SM has an active exit state and is therefore waiting for exiting
0932 template <class StateType,class OwnerFct,class FSM>
0933 inline
0934 typename ::boost::enable_if<typename ::boost::mpl::and_<typename is_composite_state<FSM>::type,
0935                                                         typename is_pseudo_exit<StateType>::type>,bool >::type
0936 is_exit_state_active(FSM& fsm)
0937 {
0938     typedef typename OwnerFct::type Composite;
0939     //typedef typename create_stt<Composite>::type stt;
0940     typedef typename Composite::stt stt;
0941     int state_id = get_state_id<stt,StateType>::type::value;
0942     Composite& comp = fsm.template get_state<Composite&>();
0943     return (std::find(comp.current_state(),comp.current_state()+Composite::nr_regions::value,state_id)
0944                             !=comp.current_state()+Composite::nr_regions::value);
0945 }
0946 template <class StateType,class OwnerFct,class FSM>
0947 inline
0948 typename ::boost::disable_if<typename ::boost::mpl::and_<typename is_composite_state<FSM>::type,
0949                                                          typename is_pseudo_exit<StateType>::type>,bool >::type
0950 is_exit_state_active(FSM&)
0951 {
0952     return false;
0953 }
0954 
0955 // transformation metafunction to end interrupt flags
0956 template <class Event>
0957 struct transform_to_end_interrupt 
0958 {
0959     typedef boost::msm::EndInterruptFlag<Event> type;
0960 };
0961 // transform a sequence of events into another one of EndInterruptFlag<Event>
0962 template <class Events>
0963 struct apply_end_interrupt_flag 
0964 {
0965     typedef typename 
0966         ::boost::mpl::transform<
0967         Events,transform_to_end_interrupt< ::boost::mpl::placeholders::_1> >::type type;
0968 };
0969 // returns a mpl vector containing all end interrupt events if sequence, otherwise the same event
0970 template <class Event>
0971 struct get_interrupt_events 
0972 {
0973     typedef typename ::boost::mpl::eval_if<
0974         ::boost::mpl::is_sequence<Event>,
0975         boost::msm::back::apply_end_interrupt_flag<Event>,
0976         boost::mpl::vector1<boost::msm::EndInterruptFlag<Event> > >::type type;
0977 };
0978 
0979 template <class Events>
0980 struct build_interrupt_state_flag_list
0981 {
0982     typedef ::boost::mpl::vector<boost::msm::InterruptedFlag> first_part;
0983     typedef typename ::boost::mpl::insert_range< 
0984         first_part, 
0985         typename ::boost::mpl::end< first_part >::type,
0986         Events
0987     >::type type;
0988 };
0989 
0990 } } }//boost::msm::back
0991 
0992 #endif // BOOST_MSM_BACK_METAFUNCTIONS_H
0993