Chris@16: // Copyright 2008 Christophe Henry Chris@16: // henry UNDERSCORE christophe AT hotmail DOT com Chris@16: // This is an extended version of the state machine available in the boost::mpl library Chris@16: // Distributed under the same license as the original. Chris@16: // Copyright for the original version: Chris@16: // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed Chris@16: // under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_MSM_BACK_STATEMACHINE_H Chris@16: #define BOOST_MSM_BACK_STATEMACHINE_H Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #ifndef BOOST_NO_RTTI Chris@16: #include Chris@16: #endif Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(accept_sig) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(no_automatic_create) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(non_forwarding_flag) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(direct_entry) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(initial_event) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(final_event) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(do_serialize) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(history_policy) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(fsm_check) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(compile_policy) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(queue_container_policy) Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(using_declared_table) Chris@16: Chris@16: #ifndef BOOST_MSM_CONSTRUCTOR_ARG_SIZE Chris@16: #define BOOST_MSM_CONSTRUCTOR_ARG_SIZE 5 // default max number of arguments for constructors Chris@16: #endif Chris@16: Chris@16: namespace boost { namespace msm { namespace back Chris@16: { Chris@16: // event used internally for wrapping a direct entry Chris@16: template Chris@16: struct direct_entry_event Chris@16: { Chris@16: typedef int direct_entry; Chris@16: typedef StateType active_state; Chris@16: typedef Event contained_event; Chris@16: Chris@16: direct_entry_event(Event const& evt):m_event(evt){} Chris@16: Event const& m_event; Chris@16: }; Chris@16: Chris@16: // This declares the statically-initialized dispatch_table instance. Chris@16: template Chris@16: const boost::msm::back::dispatch_table Chris@16: dispatch_table::instance; Chris@16: Chris@16: BOOST_PARAMETER_TEMPLATE_KEYWORD(front_end) Chris@16: BOOST_PARAMETER_TEMPLATE_KEYWORD(history_policy) Chris@16: BOOST_PARAMETER_TEMPLATE_KEYWORD(compile_policy) Chris@16: BOOST_PARAMETER_TEMPLATE_KEYWORD(fsm_check_policy) Chris@16: BOOST_PARAMETER_TEMPLATE_KEYWORD(queue_container_policy) Chris@16: Chris@16: typedef ::boost::parameter::parameters< Chris@16: ::boost::parameter::required< ::boost::msm::back::tag::front_end > Chris@16: , ::boost::parameter::optional< Chris@16: ::boost::parameter::deduced< ::boost::msm::back::tag::history_policy>, has_history_policy< ::boost::mpl::_ > Chris@16: > Chris@16: , ::boost::parameter::optional< Chris@16: ::boost::parameter::deduced< ::boost::msm::back::tag::compile_policy>, has_compile_policy< ::boost::mpl::_ > Chris@16: > Chris@16: , ::boost::parameter::optional< Chris@16: ::boost::parameter::deduced< ::boost::msm::back::tag::fsm_check_policy>, has_fsm_check< ::boost::mpl::_ > Chris@16: > Chris@16: , ::boost::parameter::optional< Chris@16: ::boost::parameter::deduced< ::boost::msm::back::tag::queue_container_policy>, Chris@16: has_queue_container_policy< ::boost::mpl::_ > Chris@16: > Chris@16: > state_machine_signature; Chris@16: Chris@16: // just here to disable use of proto when not needed Chris@16: template Chris@16: struct make_euml_terminal; Chris@16: template Chris@16: struct make_euml_terminal >::type> Chris@16: {}; Chris@16: template Chris@16: struct make_euml_terminal >::type> Chris@16: : public proto::extends::type, T, boost::msm::state_domain> Chris@16: {}; Chris@16: Chris@16: // library-containing class for state machines. Pass the actual FSM class as Chris@16: // the Concrete parameter. Chris@16: // A0=Derived,A1=NoHistory,A2=CompilePolicy,A3=FsmCheckPolicy > Chris@16: template < Chris@16: class A0 Chris@16: , class A1 = parameter::void_ Chris@16: , class A2 = parameter::void_ Chris@16: , class A3 = parameter::void_ Chris@16: , class A4 = parameter::void_ Chris@16: > Chris@16: class state_machine : //public Derived Chris@16: public ::boost::parameter::binding< Chris@16: typename state_machine_signature::bind::type, ::boost::msm::back::tag::front_end Chris@16: >::type Chris@16: , public make_euml_terminal, Chris@16: typename ::boost::parameter::binding< Chris@16: typename state_machine_signature::bind::type, ::boost::msm::back::tag::front_end Chris@16: >::type Chris@16: > Chris@16: { Chris@16: public: Chris@16: // Create ArgumentPack Chris@16: typedef typename Chris@16: state_machine_signature::bind::type Chris@16: state_machine_args; Chris@16: Chris@16: // Extract first logical parameter. Chris@16: typedef typename ::boost::parameter::binding< Chris@16: state_machine_args, ::boost::msm::back::tag::front_end>::type Derived; Chris@16: Chris@16: typedef typename ::boost::parameter::binding< Chris@16: state_machine_args, ::boost::msm::back::tag::history_policy, NoHistory >::type HistoryPolicy; Chris@16: Chris@16: typedef typename ::boost::parameter::binding< Chris@16: state_machine_args, ::boost::msm::back::tag::compile_policy, favor_runtime_speed >::type CompilePolicy; Chris@16: Chris@16: typedef typename ::boost::parameter::binding< Chris@16: state_machine_args, ::boost::msm::back::tag::fsm_check_policy, no_fsm_check >::type FsmCheckPolicy; Chris@16: Chris@16: typedef typename ::boost::parameter::binding< Chris@16: state_machine_args, ::boost::msm::back::tag::queue_container_policy, Chris@16: queue_container_deque >::type QueueContainerPolicy; Chris@16: Chris@16: private: Chris@16: Chris@16: typedef boost::msm::back::state_machine< Chris@16: A0,A1,A2,A3,A4> library_sm; Chris@16: Chris@16: typedef ::boost::function< Chris@16: execute_return ()> transition_fct; Chris@16: typedef ::boost::function< Chris@16: execute_return () > deferred_fct; Chris@16: typedef typename QueueContainerPolicy:: Chris@16: template In< Chris@16: std::pair >::type deferred_events_queue_t; Chris@16: typedef typename QueueContainerPolicy:: Chris@16: template In::type events_queue_t; Chris@16: Chris@16: typedef typename boost::mpl::eval_if< Chris@16: typename is_active_state_switch_policy::type, Chris@16: get_active_state_switch_policy, Chris@16: // default Chris@16: ::boost::mpl::identity Chris@16: >::type active_state_switching; Chris@16: Chris@16: typedef bool (*flag_handler)(library_sm const&); Chris@16: Chris@16: // all state machines are friend with each other to allow embedding any of them in another fsm Chris@16: template friend class boost::msm::back::state_machine; Chris@16: Chris@16: // helper to add, if needed, visitors to all states Chris@16: // version without visitors Chris@16: template Chris@16: struct visitor_fct_helper Chris@16: { Chris@16: public: Chris@16: visitor_fct_helper(){} Chris@16: void fill_visitors(int) Chris@16: { Chris@16: } Chris@16: template Chris@16: void insert(int,FCT) Chris@16: { Chris@16: } Chris@16: template Chris@16: void execute(int,VISITOR) Chris@16: { Chris@16: } Chris@16: }; Chris@16: // version with visitors Chris@16: template Chris@16: struct visitor_fct_helper >::type> Chris@16: { Chris@16: public: Chris@16: visitor_fct_helper():m_state_visitors(){} Chris@16: void fill_visitors(int number_of_states) Chris@16: { Chris@16: m_state_visitors.resize(number_of_states); Chris@16: } Chris@16: template Chris@16: void insert(int index,FCT fct) Chris@16: { Chris@16: m_state_visitors[index]=fct; Chris@16: } Chris@16: void execute(int index) Chris@16: { Chris@16: m_state_visitors[index](); Chris@16: } Chris@16: Chris@16: #define MSM_VISITOR_HELPER_EXECUTE_SUB(z, n, unused) ARG ## n vis ## n Chris@16: #define MSM_VISITOR_HELPER_EXECUTE(z, n, unused) \ Chris@16: template \ Chris@16: void execute(int index BOOST_PP_COMMA_IF(n) \ Chris@16: BOOST_PP_ENUM(n, MSM_VISITOR_HELPER_EXECUTE_SUB, ~ ) ) \ Chris@16: { \ Chris@16: m_state_visitors[index](BOOST_PP_ENUM_PARAMS(n,vis)); \ Chris@16: } Chris@16: BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_VISITOR_HELPER_EXECUTE, ~) Chris@16: #undef MSM_VISITOR_HELPER_EXECUTE Chris@16: #undef MSM_VISITOR_HELPER_EXECUTE_SUB Chris@16: private: Chris@16: typedef typename StateType::accept_sig::type visitor_fct; Chris@16: typedef std::vector visitors; Chris@16: Chris@16: visitors m_state_visitors; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct deferred_msg_queue_helper Chris@16: { Chris@101: void clear(){} Chris@16: }; Chris@16: template Chris@16: struct deferred_msg_queue_helper::type,int >::type> Chris@16: { Chris@16: public: Chris@16: deferred_msg_queue_helper():m_deferred_events_queue(){} Chris@101: void clear() Chris@101: { Chris@101: m_deferred_events_queue.clear(); Chris@101: } Chris@16: deferred_events_queue_t m_deferred_events_queue; Chris@16: }; Chris@16: Chris@16: public: Chris@16: // tags Chris@16: typedef int composite_tag; Chris@16: Chris@16: // in case someone needs to know Chris@16: typedef HistoryPolicy history_policy; Chris@16: Chris@16: struct InitEvent { }; Chris@16: struct ExitEvent { }; Chris@16: // flag handling Chris@16: struct Flag_AND Chris@16: { Chris@16: typedef std::logical_and type; Chris@16: }; Chris@16: struct Flag_OR Chris@16: { Chris@16: typedef std::logical_or type; Chris@16: }; Chris@16: typedef typename Derived::BaseAllStates BaseState; Chris@16: typedef Derived ConcreteSM; Chris@16: Chris@16: // if the front-end fsm provides an initial_event typedef, replace InitEvent by this one Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename has_initial_event::type, Chris@16: get_initial_event, Chris@16: ::boost::mpl::identity Chris@16: >::type fsm_initial_event; Chris@16: Chris@16: // if the front-end fsm provides an exit_event typedef, replace ExitEvent by this one Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename has_final_event::type, Chris@16: get_final_event, Chris@16: ::boost::mpl::identity Chris@16: >::type fsm_final_event; Chris@16: Chris@16: template Chris@16: struct exit_pt : public ExitPoint Chris@16: { Chris@16: // tags Chris@16: typedef ExitPoint wrapped_exit; Chris@16: typedef int pseudo_exit; Chris@16: typedef library_sm owner; Chris@16: typedef int no_automatic_create; Chris@16: typedef typename Chris@16: ExitPoint::event Event; Chris@16: typedef ::boost::function Chris@16: forwarding_function; Chris@16: Chris@16: // forward event to the higher-level FSM Chris@16: template Chris@16: void forward_event(ForwardEvent const& incomingEvent) Chris@16: { Chris@16: // use helper to forward or not Chris@16: ForwardHelper< ::boost::is_convertible::value>::helper(incomingEvent,m_forward); Chris@16: } Chris@16: void set_forward_fct(::boost::function fct) Chris@16: { Chris@16: m_forward = fct; Chris@16: } Chris@16: exit_pt():m_forward(){} Chris@16: // by assignments, we keep our forwarding functor unchanged as our containing SM did not change Chris@16: template Chris@101: exit_pt(RHS&):m_forward(){} Chris@16: exit_pt& operator= (const exit_pt& ) Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: private: Chris@16: forwarding_function m_forward; Chris@16: Chris@16: // using partial specialization instead of enable_if because of VC8 bug Chris@16: template Chris@16: struct ForwardHelper Chris@16: { Chris@16: template Chris@16: static void helper(ForwardEvent const& ,forwarding_function& ) Chris@16: { Chris@16: // Not our event, assert Chris@16: BOOST_ASSERT(false); Chris@16: } Chris@16: }; Chris@16: template Chris@16: struct ForwardHelper Chris@16: { Chris@16: template Chris@16: static void helper(ForwardEvent const& incomingEvent,forwarding_function& forward_fct) Chris@16: { Chris@16: // call if handler set, if not, this state is simply a terminate state Chris@16: if (forward_fct) Chris@16: forward_fct(incomingEvent); Chris@16: } Chris@16: }; Chris@16: Chris@16: }; Chris@16: template Chris@16: struct entry_pt : public EntryPoint Chris@16: { Chris@16: // tags Chris@16: typedef EntryPoint wrapped_entry; Chris@16: typedef int pseudo_entry; Chris@16: typedef library_sm owner; Chris@16: typedef int no_automatic_create; Chris@16: }; Chris@16: template Chris@16: struct direct : public EntryPoint Chris@16: { Chris@16: // tags Chris@16: typedef EntryPoint wrapped_entry; Chris@16: typedef int explicit_entry_state; Chris@16: typedef library_sm owner; Chris@16: typedef int no_automatic_create; Chris@16: }; Chris@16: typedef typename get_number_of_regions::type nr_regions; Chris@16: // Template used to form rows in the transition table Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct row_ Chris@16: { Chris@16: //typedef typename ROW::Source T1; Chris@16: typedef typename make_entry::type T1; Chris@16: typedef typename make_exit::type T2; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: // if the source is an exit pseudo state, then Chris@16: // current_state_type becomes the result of get_owner Chris@16: // meaning the containing SM from which the exit occurs Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename has_pseudo_exit::type, Chris@16: get_owner, Chris@16: ::boost::mpl::identity >::type current_state_type; Chris@16: Chris@16: // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry Chris@16: // else if Target is an explicit_entry, next_state_type becomes the result of get_owner Chris@16: // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename ::boost::mpl::is_sequence::type, Chris@16: get_fork_owner, Chris@16: ::boost::mpl::eval_if< Chris@16: typename has_no_automatic_create::type, Chris@16: get_owner, Chris@16: ::boost::mpl::identity > Chris@16: >::type next_state_type; Chris@16: Chris@16: // if a guard condition is here, call it to check that the event is accepted Chris@16: static bool check_guard(library_sm& fsm,transition_event const& evt) Chris@16: { Chris@16: if ( ROW::guard_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list ) ) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt) Chris@16: { Chris@16: Chris@16: BOOST_STATIC_CONSTANT(int, current_state = (get_state_id::type::value)); Chris@16: BOOST_STATIC_CONSTANT(int, next_state = (get_state_id::type::value)); Chris@16: BOOST_ASSERT(state == (current_state)); Chris@16: // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active Chris@16: if (has_pseudo_exit::type::value && Chris@16: !is_exit_state_active >(fsm)) Chris@16: { Chris@16: return HANDLED_FALSE; Chris@16: } Chris@16: if (!check_guard(fsm,evt)) Chris@16: { Chris@16: // guard rejected the event, we stay in the current one Chris@16: return HANDLED_GUARD_REJECT; Chris@16: } Chris@16: fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state); Chris@16: Chris@16: // the guard condition has already been checked Chris@16: execute_exit Chris@16: (::boost::fusion::at_key(fsm.m_substate_list),evt,fsm); Chris@16: fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state); Chris@16: Chris@16: // then call the action method Chris@16: HandledEnum res = ROW::action_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list); Chris@16: fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state); Chris@16: Chris@16: // and finally the entry method of the new current state Chris@16: convert_event_and_execute_entry Chris@16: (::boost::fusion::at_key(fsm.m_substate_list),evt,fsm); Chris@16: fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state); Chris@16: return res; Chris@16: } Chris@16: }; Chris@16: Chris@16: // row having only a guard condition Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct g_row_ Chris@16: { Chris@16: //typedef typename ROW::Source T1; Chris@16: typedef typename make_entry::type T1; Chris@16: typedef typename make_exit::type T2; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: // if the source is an exit pseudo state, then Chris@16: // current_state_type becomes the result of get_owner Chris@16: // meaning the containing SM from which the exit occurs Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename has_pseudo_exit::type, Chris@16: get_owner, Chris@16: ::boost::mpl::identity >::type current_state_type; Chris@16: Chris@16: // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry Chris@16: // else if Target is an explicit_entry, next_state_type becomes the result of get_owner Chris@16: // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename ::boost::mpl::is_sequence::type, Chris@16: get_fork_owner, Chris@16: ::boost::mpl::eval_if< Chris@16: typename has_no_automatic_create::type, Chris@16: get_owner, Chris@16: ::boost::mpl::identity > Chris@16: >::type next_state_type; Chris@16: Chris@16: // if a guard condition is defined, call it to check that the event is accepted Chris@16: static bool check_guard(library_sm& fsm,transition_event const& evt) Chris@16: { Chris@16: if ( ROW::guard_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list )) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt) Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, current_state = (get_state_id::type::value)); Chris@16: BOOST_STATIC_CONSTANT(int, next_state = (get_state_id::type::value)); Chris@16: BOOST_ASSERT(state == (current_state)); Chris@16: // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active Chris@16: if (has_pseudo_exit::type::value && Chris@16: !is_exit_state_active >(fsm)) Chris@16: { Chris@16: return HANDLED_FALSE; Chris@16: } Chris@16: if (!check_guard(fsm,evt)) Chris@16: { Chris@16: // guard rejected the event, we stay in the current one Chris@16: return HANDLED_GUARD_REJECT; Chris@16: } Chris@16: fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state); Chris@16: Chris@16: // the guard condition has already been checked Chris@16: execute_exit Chris@16: (::boost::fusion::at_key(fsm.m_substate_list),evt,fsm); Chris@16: fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state); Chris@16: fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state); Chris@16: Chris@16: // and finally the entry method of the new current state Chris@16: convert_event_and_execute_entry Chris@16: (::boost::fusion::at_key(fsm.m_substate_list),evt,fsm); Chris@16: fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state); Chris@16: return HANDLED_TRUE; Chris@16: } Chris@16: }; Chris@16: Chris@16: // row having only an action method Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct a_row_ Chris@16: { Chris@16: //typedef typename ROW::Source T1; Chris@16: typedef typename make_entry::type T1; Chris@16: typedef typename make_exit::type T2; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: // if the source is an exit pseudo state, then Chris@16: // current_state_type becomes the result of get_owner Chris@16: // meaning the containing SM from which the exit occurs Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename has_pseudo_exit::type, Chris@16: get_owner, Chris@16: ::boost::mpl::identity >::type current_state_type; Chris@16: Chris@16: // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry Chris@16: // else if Target is an explicit_entry, next_state_type becomes the result of get_owner Chris@16: // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename ::boost::mpl::is_sequence::type, Chris@16: get_fork_owner, Chris@16: ::boost::mpl::eval_if< Chris@16: typename has_no_automatic_create::type, Chris@16: get_owner, Chris@16: ::boost::mpl::identity > Chris@16: >::type next_state_type; Chris@16: Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt) Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, current_state = (get_state_id::type::value)); Chris@16: BOOST_STATIC_CONSTANT(int, next_state = (get_state_id::type::value)); Chris@16: BOOST_ASSERT(state == (current_state)); Chris@16: Chris@16: // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active Chris@16: if (has_pseudo_exit::type::value && Chris@16: !is_exit_state_active >(fsm)) Chris@16: { Chris@16: return HANDLED_FALSE; Chris@16: } Chris@16: fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state); Chris@16: Chris@16: // no need to check the guard condition Chris@16: // first call the exit method of the current state Chris@16: execute_exit Chris@16: (::boost::fusion::at_key(fsm.m_substate_list),evt,fsm); Chris@16: fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state); Chris@16: Chris@16: // then call the action method Chris@16: HandledEnum res = ROW::action_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list); Chris@16: fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state); Chris@16: Chris@16: // and finally the entry method of the new current state Chris@16: convert_event_and_execute_entry Chris@16: (::boost::fusion::at_key(fsm.m_substate_list),evt,fsm); Chris@16: fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state); Chris@16: return res; Chris@16: } Chris@16: }; Chris@16: Chris@16: // row having no guard condition or action, simply transitions Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct _row_ Chris@16: { Chris@16: //typedef typename ROW::Source T1; Chris@16: typedef typename make_entry::type T1; Chris@16: typedef typename make_exit::type T2; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: // if the source is an exit pseudo state, then Chris@16: // current_state_type becomes the result of get_owner Chris@16: // meaning the containing SM from which the exit occurs Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename has_pseudo_exit::type, Chris@16: get_owner, Chris@16: ::boost::mpl::identity >::type current_state_type; Chris@16: Chris@16: // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry Chris@16: // else if Target is an explicit_entry, next_state_type becomes the result of get_owner Chris@16: // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename ::boost::mpl::is_sequence::type, Chris@16: get_fork_owner, Chris@16: ::boost::mpl::eval_if< Chris@16: typename has_no_automatic_create::type, Chris@16: get_owner, Chris@16: ::boost::mpl::identity > Chris@16: >::type next_state_type; Chris@16: Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt) Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, current_state = (get_state_id::type::value)); Chris@16: BOOST_STATIC_CONSTANT(int, next_state = (get_state_id::type::value)); Chris@16: BOOST_ASSERT(state == (current_state)); Chris@16: Chris@16: // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active Chris@16: if (has_pseudo_exit::type::value && Chris@16: !is_exit_state_active >(fsm)) Chris@16: { Chris@16: return HANDLED_FALSE; Chris@16: } Chris@16: fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state); Chris@16: Chris@16: // first call the exit method of the current state Chris@16: execute_exit Chris@16: (::boost::fusion::at_key(fsm.m_substate_list),evt,fsm); Chris@16: fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state); Chris@16: fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state); Chris@16: Chris@16: Chris@16: // and finally the entry method of the new current state Chris@16: convert_event_and_execute_entry Chris@16: (::boost::fusion::at_key(fsm.m_substate_list),evt,fsm); Chris@16: fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state); Chris@16: return HANDLED_TRUE; Chris@16: } Chris@16: }; Chris@16: // "i" rows are rows for internal transitions Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct irow_ Chris@16: { Chris@16: typedef typename make_entry::type T1; Chris@16: typedef typename make_exit::type T2; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: typedef typename ROW::Source current_state_type; Chris@16: typedef T2 next_state_type; Chris@16: Chris@16: // if a guard condition is here, call it to check that the event is accepted Chris@16: static bool check_guard(library_sm& fsm,transition_event const& evt) Chris@16: { Chris@16: if ( ROW::guard_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list)) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int , int state, transition_event const& evt) Chris@16: { Chris@16: Chris@16: BOOST_STATIC_CONSTANT(int, current_state = (get_state_id::type::value)); Chris@16: BOOST_ASSERT(state == (current_state)); Chris@16: if (!check_guard(fsm,evt)) Chris@16: { Chris@16: // guard rejected the event, we stay in the current one Chris@16: return HANDLED_GUARD_REJECT; Chris@16: } Chris@16: Chris@16: // call the action method Chris@16: HandledEnum res = ROW::action_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list); Chris@16: return res; Chris@16: } Chris@16: }; Chris@16: Chris@16: // row having only a guard condition Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct g_irow_ Chris@16: { Chris@16: typedef typename make_entry::type T1; Chris@16: typedef typename make_exit::type T2; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: typedef typename ROW::Source current_state_type; Chris@16: typedef T2 next_state_type; Chris@16: Chris@16: // if a guard condition is defined, call it to check that the event is accepted Chris@16: static bool check_guard(library_sm& fsm,transition_event const& evt) Chris@16: { Chris@16: if ( ROW::guard_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list) ) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int , int state, transition_event const& evt) Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, current_state = (get_state_id::type::value)); Chris@16: BOOST_ASSERT(state == (current_state)); Chris@16: if (!check_guard(fsm,evt)) Chris@16: { Chris@16: // guard rejected the event, we stay in the current one Chris@16: return HANDLED_GUARD_REJECT; Chris@16: } Chris@16: return HANDLED_TRUE; Chris@16: } Chris@16: }; Chris@16: Chris@16: // row having only an action method Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct a_irow_ Chris@16: { Chris@16: typedef typename make_entry::type T1; Chris@16: typedef typename make_exit::type T2; Chris@16: Chris@16: typedef typename ROW::Evt transition_event; Chris@16: typedef typename ROW::Source current_state_type; Chris@16: typedef T2 next_state_type; Chris@16: Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int , int state, transition_event const& evt) Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, current_state = (get_state_id::type::value)); Chris@16: BOOST_ASSERT(state == (current_state)); Chris@16: Chris@16: // call the action method Chris@16: HandledEnum res = ROW::action_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list); Chris@16: Chris@16: return res; Chris@16: } Chris@16: }; Chris@16: // row simply ignoring the event Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct _irow_ Chris@16: { Chris@16: typedef typename make_entry::type T1; Chris@16: typedef typename make_exit::type T2; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: typedef typename ROW::Source current_state_type; Chris@16: typedef T2 next_state_type; Chris@16: Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& , int , int state, transition_event const& ) Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, current_state = (get_state_id::type::value)); Chris@16: BOOST_ASSERT(state == (current_state)); Chris@16: return HANDLED_TRUE; Chris@16: } Chris@16: }; Chris@16: // transitions internal to this state machine (no substate involved) Chris@16: template< Chris@16: typename ROW, Chris@16: typename StateType Chris@16: > Chris@16: struct internal_ Chris@16: { Chris@16: typedef StateType current_state_type; Chris@16: typedef StateType next_state_type; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: Chris@16: // if a guard condition is here, call it to check that the event is accepted Chris@16: static bool check_guard(library_sm& fsm,transition_event const& evt) Chris@16: { Chris@16: if ( ROW::guard_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list) ) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int , int , transition_event const& evt) Chris@16: { Chris@16: if (!check_guard(fsm,evt)) Chris@16: { Chris@16: // guard rejected the event, we stay in the current one Chris@16: return HANDLED_GUARD_REJECT; Chris@16: } Chris@16: Chris@16: // then call the action method Chris@16: HandledEnum res = ROW::action_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list); Chris@16: return res; Chris@16: } Chris@16: }; Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct internal_ Chris@16: { Chris@16: typedef library_sm current_state_type; Chris@16: typedef library_sm next_state_type; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: Chris@16: // if a guard condition is here, call it to check that the event is accepted Chris@16: static bool check_guard(library_sm& fsm,transition_event const& evt) Chris@16: { Chris@16: if ( ROW::guard_call(fsm,evt, Chris@16: fsm, Chris@16: fsm, Chris@16: fsm.m_substate_list) ) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int , int , transition_event const& evt) Chris@16: { Chris@16: if (!check_guard(fsm,evt)) Chris@16: { Chris@16: // guard rejected the event, we stay in the current one Chris@16: return HANDLED_GUARD_REJECT; Chris@16: } Chris@16: Chris@16: // then call the action method Chris@16: HandledEnum res = ROW::action_call(fsm,evt, Chris@16: fsm, Chris@16: fsm, Chris@16: fsm.m_substate_list); Chris@16: return res; Chris@16: } Chris@16: }; Chris@16: Chris@16: template< Chris@16: typename ROW, Chris@16: typename StateType Chris@16: > Chris@16: struct a_internal_ Chris@16: { Chris@16: typedef StateType current_state_type; Chris@16: typedef StateType next_state_type; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt) Chris@16: { Chris@16: // then call the action method Chris@16: HandledEnum res = ROW::action_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list); Chris@16: return res; Chris@16: } Chris@16: }; Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct a_internal_ Chris@16: { Chris@16: typedef library_sm current_state_type; Chris@16: typedef library_sm next_state_type; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt) Chris@16: { Chris@16: // then call the action method Chris@16: HandledEnum res = ROW::action_call(fsm,evt, Chris@16: fsm, Chris@16: fsm, Chris@16: fsm.m_substate_list); Chris@16: return res; Chris@16: } Chris@16: }; Chris@16: template< Chris@16: typename ROW, Chris@16: typename StateType Chris@16: > Chris@16: struct g_internal_ Chris@16: { Chris@16: typedef StateType current_state_type; Chris@16: typedef StateType next_state_type; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: Chris@16: // if a guard condition is here, call it to check that the event is accepted Chris@16: static bool check_guard(library_sm& fsm,transition_event const& evt) Chris@16: { Chris@16: if ( ROW::guard_call(fsm,evt, Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: ::boost::fusion::at_key(fsm.m_substate_list), Chris@16: fsm.m_substate_list) ) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt) Chris@16: { Chris@16: if (!check_guard(fsm,evt)) Chris@16: { Chris@16: // guard rejected the event, we stay in the current one Chris@16: return HANDLED_GUARD_REJECT; Chris@16: } Chris@16: return HANDLED_TRUE; Chris@16: } Chris@16: }; Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct g_internal_ Chris@16: { Chris@16: typedef library_sm current_state_type; Chris@16: typedef library_sm next_state_type; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: Chris@16: // if a guard condition is here, call it to check that the event is accepted Chris@16: static bool check_guard(library_sm& fsm,transition_event const& evt) Chris@16: { Chris@16: if ( ROW::guard_call(fsm,evt, Chris@16: fsm, Chris@16: fsm, Chris@16: fsm.m_substate_list) ) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt) Chris@16: { Chris@16: if (!check_guard(fsm,evt)) Chris@16: { Chris@16: // guard rejected the event, we stay in the current one Chris@16: return HANDLED_GUARD_REJECT; Chris@16: } Chris@16: return HANDLED_TRUE; Chris@16: } Chris@16: }; Chris@16: template< Chris@16: typename ROW, Chris@16: typename StateType Chris@16: > Chris@16: struct _internal_ Chris@16: { Chris@16: typedef StateType current_state_type; Chris@16: typedef StateType next_state_type; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: static HandledEnum execute(library_sm& , int , int , transition_event const& ) Chris@16: { Chris@16: return HANDLED_TRUE; Chris@16: } Chris@16: }; Chris@16: template< Chris@16: typename ROW Chris@16: > Chris@16: struct _internal_ Chris@16: { Chris@16: typedef library_sm current_state_type; Chris@16: typedef library_sm next_state_type; Chris@16: typedef typename ROW::Evt transition_event; Chris@16: static HandledEnum execute(library_sm& , int , int , transition_event const& ) Chris@16: { Chris@16: return HANDLED_TRUE; Chris@16: } Chris@16: }; Chris@16: // Template used to form forwarding rows in the transition table for every row of a composite SM Chris@16: template< Chris@16: typename T1 Chris@16: , class Evt Chris@16: > Chris@16: struct frow Chris@16: { Chris@16: typedef T1 current_state_type; Chris@16: typedef T1 next_state_type; Chris@16: typedef Evt transition_event; Chris@16: // tag to find out if a row is a forwarding row Chris@16: typedef int is_frow; Chris@16: Chris@16: // Take the transition action and return the next state. Chris@16: static HandledEnum execute(library_sm& fsm, int region_index, int , transition_event const& evt) Chris@16: { Chris@16: // false as second parameter because this event is forwarded from outer fsm Chris@16: execute_return res = Chris@16: (::boost::fusion::at_key(fsm.m_substate_list)).process_event_internal(evt,false); Chris@16: fsm.m_states[region_index]=get_state_id::type::value; Chris@16: return res; Chris@16: } Chris@16: // helper metafunctions used by dispatch table and give the frow a new event Chris@16: // (used to avoid double entries in a table because of base events) Chris@16: template Chris@16: struct replace_event Chris@16: { Chris@16: typedef frow type; Chris@16: }; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef g_row_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef a_row_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt<_row_tag,Transition,StateType> Chris@16: { Chris@16: typedef _row_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef row_ type; Chris@16: }; Chris@16: // internal transitions Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef g_irow_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef a_irow_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef irow_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt<_irow_tag,Transition,StateType> Chris@16: { Chris@16: typedef _irow_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef a_internal_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef g_internal_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef internal_ type; Chris@16: }; Chris@16: template Chris@16: struct create_backend_stt Chris@16: { Chris@16: typedef _internal_ type; Chris@16: }; Chris@16: template Chris@16: struct make_row_tag Chris@16: { Chris@16: typedef typename create_backend_stt::type type; Chris@16: }; Chris@16: Chris@16: // add to the stt the initial states which could be missing (if not being involved in a transition) Chris@16: template Chris@16: struct create_real_stt Chris@16: { Chris@16: //typedef typename BaseType::transition_table stt_simulated; Chris@16: typedef typename ::boost::mpl::fold< Chris@16: stt_simulated,mpl::vector0<>, Chris@16: ::boost::mpl::push_back< ::boost::mpl::placeholders::_1, Chris@16: make_row_tag< ::boost::mpl::placeholders::_2 , BaseType > > Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct add_forwarding_row_helper Chris@16: { Chris@16: typedef typename generate_event_set::type all_events; Chris@16: typedef typename ::boost::mpl::fold< Chris@16: all_events, Intermediate, Chris@16: ::boost::mpl::push_back< ::boost::mpl::placeholders::_1, Chris@16: frow > >::type type; Chris@16: }; Chris@16: // gets the transition table from a composite and make from it a forwarding row Chris@16: template Chris@16: struct get_internal_transition_table Chris@16: { Chris@16: // first get the table of a composite Chris@16: typedef typename recursive_get_transition_table::type original_table; Chris@16: Chris@16: // we now look for the events the composite has in its internal transitions Chris@16: // the internal ones are searched recursively in sub-sub... states Chris@16: // we go recursively because our states can also have internal tables or substates etc. Chris@16: typedef typename recursive_get_internal_transition_table::type recursive_istt; Chris@16: typedef typename ::boost::mpl::fold< Chris@16: recursive_istt,::boost::mpl::vector0<>, Chris@16: ::boost::mpl::push_back< ::boost::mpl::placeholders::_1, Chris@16: make_row_tag< ::boost::mpl::placeholders::_2 , StateType> > Chris@16: >::type recursive_istt_with_tag; Chris@16: Chris@16: typedef typename ::boost::mpl::insert_range< original_table, typename ::boost::mpl::end::type, Chris@16: recursive_istt_with_tag>::type table_with_all_events; Chris@16: Chris@16: // and add for every event a forwarding row Chris@16: typedef typename ::boost::mpl::eval_if< Chris@16: typename CompilePolicy::add_forwarding_rows, Chris@16: add_forwarding_row_helper,StateType>, Chris@16: ::boost::mpl::identity< ::boost::mpl::vector0<> > Chris@16: >::type type; Chris@16: }; Chris@16: template Chris@16: struct get_internal_transition_table Chris@16: { Chris@16: typedef typename create_real_stt::type type; Chris@16: }; Chris@16: // typedefs used internally Chris@16: typedef typename create_real_stt::type real_transition_table; Chris@16: typedef typename create_stt::type stt; Chris@16: typedef typename get_initial_states::type initial_states; Chris@16: typedef typename generate_state_set::type state_list; Chris@16: typedef typename HistoryPolicy::template apply::type concrete_history; Chris@16: Chris@16: typedef typename ::boost::fusion::result_of::as_set::type substate_list; Chris@16: typedef typename ::boost::msm::back::generate_event_set< Chris@16: typename create_real_stt::type Chris@16: >::type processable_events_internal_table; Chris@16: Chris@16: // extends the transition table with rows from composite states Chris@16: template Chris@16: struct extend_table Chris@16: { Chris@16: // add the init states Chris@16: //typedef typename create_stt::type stt; Chris@16: typedef typename Composite::stt Stt; Chris@16: Chris@16: // add the internal events defined in the internal_transition_table Chris@16: // Note: these are added first because they must have a lesser prio Chris@16: // than the deeper transitions in the sub regions Chris@16: // table made of a stt + internal transitions of composite Chris@16: typedef typename ::boost::mpl::fold< Chris@16: typename Composite::internal_transition_table,::boost::mpl::vector0<>, Chris@16: ::boost::mpl::push_back< ::boost::mpl::placeholders::_1, Chris@16: make_row_tag< ::boost::mpl::placeholders::_2 , Composite> > Chris@16: >::type internal_stt; Chris@16: Chris@16: typedef typename ::boost::mpl::insert_range< Chris@16: Stt, Chris@16: typename ::boost::mpl::end::type, Chris@16: internal_stt Chris@16: //typename get_internal_transition_table::type Chris@16: >::type stt_plus_internal; Chris@16: Chris@16: // for every state, add its transition table (if any) Chris@16: // transformed as frow Chris@16: typedef typename ::boost::mpl::fold, Chris@16: get_internal_transition_table< Chris@16: ::boost::mpl::placeholders::_2, Chris@16: is_composite_state< ::boost::mpl::placeholders::_2> > > Chris@16: >::type type; Chris@16: }; Chris@16: // extend the table with tables from composite states Chris@16: typedef typename extend_table::type complete_table; Chris@16: // build a sequence of regions Chris@16: typedef typename get_regions_as_sequence::type seq_initial_states; Chris@16: // Member functions Chris@16: Chris@16: // start the state machine (calls entry of the initial state) Chris@16: void start() Chris@16: { Chris@16: // reinitialize our list of currently active states with the ones defined in Derived::initial_state Chris@16: ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap > Chris@16: (init_states(m_states)); Chris@16: // call on_entry on this SM Chris@16: (static_cast(this))->on_entry(fsm_initial_event(),*this); Chris@16: ::boost::mpl::for_each > Chris@16: (call_init(fsm_initial_event(),this)); Chris@16: // give a chance to handle an anonymous (eventless) transition Chris@16: handle_eventless_transitions_helper eventless_helper(this,true); Chris@16: eventless_helper.process_completion_event(); Chris@16: } Chris@16: Chris@16: // start the state machine (calls entry of the initial state passing incomingEvent to on_entry's) Chris@16: template Chris@16: void start(Event const& incomingEvent) Chris@16: { Chris@16: // reinitialize our list of currently active states with the ones defined in Derived::initial_state Chris@16: ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap > Chris@16: (init_states(m_states)); Chris@16: // call on_entry on this SM Chris@16: (static_cast(this))->on_entry(incomingEvent,*this); Chris@16: ::boost::mpl::for_each > Chris@16: (call_init(incomingEvent,this)); Chris@16: // give a chance to handle an anonymous (eventless) transition Chris@16: handle_eventless_transitions_helper eventless_helper(this,true); Chris@16: eventless_helper.process_completion_event(); Chris@16: } Chris@16: Chris@16: // stop the state machine (calls exit of the current state) Chris@16: void stop() Chris@16: { Chris@16: do_exit(fsm_final_event(),*this); Chris@16: } Chris@16: Chris@16: // stop the state machine (calls exit of the current state passing finalEvent to on_exit's) Chris@16: template Chris@16: void stop(Event const& finalEvent) Chris@16: { Chris@16: do_exit(finalEvent,*this); Chris@16: } Chris@16: Chris@16: // Main function used by clients of the derived FSM to make transitions. Chris@16: template Chris@16: execute_return process_event(Event const& evt) Chris@16: { Chris@16: return process_event_internal(evt,true); Chris@16: } Chris@16: Chris@16: template Chris@16: void enqueue_event_helper(EventType const& evt, ::boost::mpl::false_ const &) Chris@16: { Chris@16: execute_return (library_sm::*pf) (EventType const& evt) = Chris@16: &library_sm::process_event; Chris@16: Chris@16: transition_fct f = ::boost::bind(pf,this,evt); Chris@16: m_events_queue.m_events_queue.push_back(f); Chris@16: } Chris@16: template Chris@101: void enqueue_event_helper(EventType const& , ::boost::mpl::true_ const &) Chris@16: { Chris@16: // no queue Chris@16: } Chris@16: Chris@16: void execute_queued_events_helper(::boost::mpl::false_ const &) Chris@16: { Chris@101: while(!m_events_queue.m_events_queue.empty()) Chris@101: { Chris@101: transition_fct to_call = m_events_queue.m_events_queue.front(); Chris@101: m_events_queue.m_events_queue.pop_front(); Chris@101: to_call(); Chris@101: } Chris@16: } Chris@16: void execute_queued_events_helper(::boost::mpl::true_ const &) Chris@16: { Chris@16: // no queue required Chris@16: } Chris@101: void execute_single_queued_event_helper(::boost::mpl::false_ const &) Chris@101: { Chris@101: transition_fct to_call = m_events_queue.m_events_queue.front(); Chris@101: m_events_queue.m_events_queue.pop_front(); Chris@101: to_call(); Chris@101: } Chris@101: void execute_single_queued_event_helper(::boost::mpl::true_ const &) Chris@101: { Chris@101: // no queue required Chris@101: } Chris@16: // enqueues an event in the message queue Chris@16: // call execute_queued_events to process all queued events. Chris@16: // Be careful if you do this during event processing, the event will be processed immediately Chris@16: // and not kept in the queue Chris@16: template Chris@16: void enqueue_event(EventType const& evt) Chris@16: { Chris@16: enqueue_event_helper(evt, typename is_no_message_queue::type()); Chris@16: } Chris@16: Chris@16: // empty the queue and process events Chris@16: void execute_queued_events() Chris@16: { Chris@16: execute_queued_events_helper(typename is_no_message_queue::type()); Chris@16: } Chris@101: void execute_single_queued_event() Chris@101: { Chris@101: execute_single_queued_event_helper(typename is_no_message_queue::type()); Chris@101: } Chris@16: typename events_queue_t::size_type get_message_queue_size() const Chris@16: { Chris@16: return m_events_queue.m_events_queue.size(); Chris@16: } Chris@16: Chris@16: events_queue_t& get_message_queue() Chris@16: { Chris@16: return m_events_queue.m_events_queue; Chris@16: } Chris@16: Chris@16: const events_queue_t& get_message_queue() const Chris@16: { Chris@16: return m_events_queue.m_events_queue; Chris@16: } Chris@16: Chris@101: void clear_deferred_queue() Chris@101: { Chris@101: m_deferred_events_queue.clear(); Chris@101: } Chris@101: Chris@16: deferred_events_queue_t& get_deferred_queue() Chris@16: { Chris@16: return m_deferred_events_queue.m_deferred_events_queue; Chris@16: } Chris@16: Chris@16: const deferred_events_queue_t& get_deferred_queue() const Chris@16: { Chris@16: return m_deferred_events_queue.m_deferred_events_queue; Chris@16: } Chris@16: Chris@16: // Getter that returns the current state of the FSM Chris@16: const int* current_state() const Chris@16: { Chris@16: return this->m_states; Chris@16: } Chris@16: Chris@16: template Chris@16: struct serialize_state Chris@16: { Chris@16: serialize_state(Archive& ar):ar_(ar){} Chris@16: Chris@16: template Chris@16: typename ::boost::enable_if< Chris@16: typename ::boost::mpl::or_< Chris@16: typename has_do_serialize::type, Chris@16: typename is_composite_state::type Chris@16: >::type Chris@16: ,void Chris@16: >::type Chris@16: operator()(T& t) const Chris@16: { Chris@16: ar_ & t; Chris@16: } Chris@16: template Chris@16: typename ::boost::disable_if< Chris@16: typename ::boost::mpl::or_< Chris@16: typename has_do_serialize::type, Chris@16: typename is_composite_state::type Chris@16: >::type Chris@16: ,void Chris@16: >::type Chris@101: operator()(T&) const Chris@16: { Chris@16: // no state to serialize Chris@16: } Chris@16: Archive& ar_; Chris@16: }; Chris@16: Chris@16: template Chris@16: void serialize(Archive & ar, const unsigned int) Chris@16: { Chris@16: // invoke serialization of the base class Chris@16: (serialize_state(ar))(boost::serialization::base_object(*this)); Chris@16: // now our attributes Chris@16: ar & m_states; Chris@16: // queues cannot be serialized => skip Chris@16: ar & m_history; Chris@16: ar & m_event_processing; Chris@16: ar & m_is_included; Chris@16: // visitors cannot be serialized => skip Chris@16: ::boost::fusion::for_each(m_substate_list, serialize_state(ar)); Chris@16: } Chris@16: Chris@16: // linearly search for the state with the given id Chris@16: struct get_state_id_helper Chris@16: { Chris@16: get_state_id_helper(int id,const BaseState** res,const library_sm* self_): Chris@16: result_state(res),searched_id(id),self(self_) {} Chris@16: Chris@16: template Chris@16: void operator()(boost::msm::wrap const&) Chris@16: { Chris@16: // look for the state id until found Chris@16: BOOST_STATIC_CONSTANT(int, id = (get_state_id::value)); Chris@16: if (!*result_state && (id == searched_id)) Chris@16: { Chris@16: *result_state = &::boost::fusion::at_key(self->m_substate_list); Chris@16: } Chris@16: } Chris@16: const BaseState** result_state; Chris@16: int searched_id; Chris@16: const library_sm* self; Chris@16: }; Chris@16: // return the state whose id is passed or 0 if not found Chris@16: // caution if you need this, you probably need polymorphic states Chris@16: // complexity: O(number of states) Chris@16: BaseState* get_state_by_id(int id) Chris@16: { Chris@16: const BaseState* result_state=0; Chris@16: ::boost::mpl::for_each > (get_state_id_helper(id,&result_state,this)); Chris@16: return const_cast(result_state); Chris@16: } Chris@16: const BaseState* get_state_by_id(int id) const Chris@16: { Chris@16: const BaseState* result_state=0; Chris@16: ::boost::mpl::for_each > (get_state_id_helper(id,&result_state,this)); Chris@16: return result_state; Chris@16: } Chris@16: // true if the sm is used in another sm Chris@16: bool is_contained() const Chris@16: { Chris@16: return m_is_included; Chris@16: } Chris@16: // get the history policy class Chris@16: concrete_history& get_history() Chris@16: { Chris@16: return m_history; Chris@16: } Chris@16: concrete_history const& get_history() const Chris@16: { Chris@16: return m_history; Chris@16: } Chris@16: // get a state (const version) Chris@16: // as a pointer Chris@16: template Chris@16: typename ::boost::enable_if::type,State >::type Chris@16: get_state(::boost::msm::back::dummy<0> = 0) const Chris@16: { Chris@16: return const_cast Chris@16: (& Chris@16: (::boost::fusion::at_key< Chris@16: typename ::boost::remove_const::type>::type>(m_substate_list))); Chris@16: } Chris@16: // as a reference Chris@16: template Chris@16: typename ::boost::enable_if::type,State >::type Chris@16: get_state(::boost::msm::back::dummy<1> = 0) const Chris@16: { Chris@16: return const_cast Chris@16: ( ::boost::fusion::at_key< Chris@16: typename ::boost::remove_const::type>::type>(m_substate_list) ); Chris@16: } Chris@16: // get a state (non const version) Chris@16: // as a pointer Chris@16: template Chris@16: typename ::boost::enable_if::type,State >::type Chris@16: get_state(::boost::msm::back::dummy<0> = 0) Chris@16: { Chris@16: return &(static_cast::type>::type > Chris@16: (::boost::fusion::at_key::type>(m_substate_list))); Chris@16: } Chris@16: // as a reference Chris@16: template Chris@16: typename ::boost::enable_if::type,State >::type Chris@16: get_state(::boost::msm::back::dummy<1> = 0) Chris@16: { Chris@16: return ::boost::fusion::at_key::type>(m_substate_list); Chris@16: } Chris@16: // checks if a flag is active using the BinaryOp as folding function Chris@16: template Chris@16: bool is_flag_active() const Chris@16: { Chris@16: flag_handler* flags_entries = get_entries_for_flag(); Chris@16: bool res = (*flags_entries[ m_states[0] ])(*this); Chris@16: for (int i = 1; i < nr_regions::value ; ++i) Chris@16: { Chris@16: res = typename BinaryOp::type() (res,(*flags_entries[ m_states[i] ])(*this)); Chris@16: } Chris@16: return res; Chris@16: } Chris@16: // checks if a flag is active using no binary op if 1 region, or OR if > 1 regions Chris@16: template Chris@16: bool is_flag_active() const Chris@16: { Chris@16: return FlagHelper1)>::helper(*this,get_entries_for_flag()); Chris@16: } Chris@16: // visit the currently active states (if these are defined as visitable Chris@16: // by implementing accept) Chris@16: void visit_current_states() Chris@16: { Chris@16: for (int i=0; i \ Chris@16: void visit_current_states(BOOST_PP_ENUM(n, MSM_VISIT_STATE_SUB, ~ ) ) \ Chris@16: { \ Chris@16: for (int i=0; i Chris@16: void defer_event(Event const& e) Chris@16: { Chris@16: // to call this function, you need either a state with a deferred_events typedef Chris@16: // or that the fsm provides the activate_deferred_events typedef Chris@16: BOOST_MPL_ASSERT(( has_fsm_deferred_events )); Chris@16: execute_return (library_sm::*pf) (Event const& evt)= &library_sm::process_event; Chris@16: Event temp (e); Chris@16: ::boost::function f= ::boost::bind(pf, this,temp); Chris@16: post_deferred_event(f); Chris@16: } Chris@16: Chris@16: protected: // interface for the derived class Chris@16: Chris@16: // helper used to fill the initial states Chris@16: struct init_states Chris@16: { Chris@16: init_states(int* const init):m_initial_states(init),m_index(-1){} Chris@16: Chris@16: // History initializer function object, used with mpl::for_each Chris@16: template Chris@16: void operator()(::boost::msm::wrap const&) Chris@16: { Chris@16: m_initial_states[++m_index]=get_state_id::type::value; Chris@16: } Chris@16: int* const m_initial_states; Chris@16: int m_index; Chris@16: }; Chris@16: public: Chris@16: struct update_state Chris@16: { Chris@16: update_state(substate_list& to_overwrite_):to_overwrite(&to_overwrite_){} Chris@16: template Chris@16: void operator()(StateType const& astate) const Chris@16: { Chris@16: ::boost::fusion::at_key(*to_overwrite)=astate; Chris@16: } Chris@16: substate_list* to_overwrite; Chris@16: }; Chris@16: template Chris@16: void set_states(Expr const& expr) Chris@16: { Chris@16: ::boost::fusion::for_each( Chris@16: ::boost::fusion::as_vector(FoldToList()(expr, boost::fusion::nil())),update_state(this->m_substate_list)); Chris@16: } Chris@16: Chris@16: // Construct with the default initial states Chris@16: state_machine() Chris@16: :Derived() Chris@16: ,m_events_queue() Chris@16: ,m_deferred_events_queue() Chris@16: ,m_history() Chris@16: ,m_event_processing(false) Chris@16: ,m_is_included(false) Chris@16: ,m_visitors() Chris@16: ,m_substate_list() Chris@16: { Chris@16: // initialize our list of states with the ones defined in Derived::initial_state Chris@16: ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap > Chris@16: (init_states(m_states)); Chris@16: m_history.set_initial_states(m_states); Chris@16: // create states Chris@16: fill_states(this); Chris@16: } Chris@16: template Chris@16: state_machine Chris@16: (Expr const& expr,typename ::boost::enable_if::type >::type* =0) Chris@16: :Derived() Chris@16: ,m_events_queue() Chris@16: ,m_deferred_events_queue() Chris@16: ,m_history() Chris@16: ,m_event_processing(false) Chris@16: ,m_is_included(false) Chris@16: ,m_visitors() Chris@16: ,m_substate_list() Chris@16: { Chris@16: BOOST_MPL_ASSERT_MSG( Chris@16: ( ::boost::proto::matches::value), Chris@16: THE_STATES_EXPRESSION_PASSED_DOES_NOT_MATCH_GRAMMAR, Chris@16: (FoldToList)); Chris@16: Chris@16: // initialize our list of states with the ones defined in Derived::initial_state Chris@16: ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap > Chris@16: (init_states(m_states)); Chris@16: m_history.set_initial_states(m_states); Chris@16: // create states Chris@16: set_states(expr); Chris@16: fill_states(this); Chris@16: } Chris@16: // Construct with the default initial states and some default argument(s) Chris@16: #define MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB(z, n, unused) ARG ## n t ## n Chris@16: #define MSM_CONSTRUCTOR_HELPER_EXECUTE(z, n, unused) \ Chris@16: template \ Chris@16: state_machine(BOOST_PP_ENUM(n, MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB, ~ ), \ Chris@16: typename ::boost::disable_if::type >::type* =0 ) \ Chris@16: :Derived(BOOST_PP_ENUM_PARAMS(n,t)) \ Chris@16: ,m_events_queue() \ Chris@16: ,m_deferred_events_queue() \ Chris@16: ,m_history() \ Chris@16: ,m_event_processing(false) \ Chris@16: ,m_is_included(false) \ Chris@16: ,m_visitors() \ Chris@16: ,m_substate_list() \ Chris@16: { \ Chris@16: ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap > \ Chris@16: (init_states(m_states)); \ Chris@16: m_history.set_initial_states(m_states); \ Chris@16: fill_states(this); \ Chris@16: } \ Chris@16: template \ Chris@16: state_machine(Expr const& expr,BOOST_PP_ENUM(n, MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB, ~ ), \ Chris@16: typename ::boost::enable_if::type >::type* =0 ) \ Chris@16: :Derived(BOOST_PP_ENUM_PARAMS(n,t)) \ Chris@16: ,m_events_queue() \ Chris@16: ,m_deferred_events_queue() \ Chris@16: ,m_history() \ Chris@16: ,m_event_processing(false) \ Chris@16: ,m_is_included(false) \ Chris@16: ,m_visitors() \ Chris@16: ,m_substate_list() \ Chris@16: { \ Chris@16: BOOST_MPL_ASSERT_MSG( \ Chris@16: ( ::boost::proto::matches::value), \ Chris@16: THE_STATES_EXPRESSION_PASSED_DOES_NOT_MATCH_GRAMMAR, \ Chris@16: (FoldToList)); \ Chris@16: ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap > \ Chris@16: (init_states(m_states)); \ Chris@16: m_history.set_initial_states(m_states); \ Chris@16: set_states(expr); \ Chris@16: fill_states(this); \ Chris@16: } Chris@16: Chris@16: BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_CONSTRUCTOR_ARG_SIZE,1), MSM_CONSTRUCTOR_HELPER_EXECUTE, ~) Chris@16: #undef MSM_CONSTRUCTOR_HELPER_EXECUTE Chris@16: #undef MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB Chris@16: Chris@16: Chris@16: Chris@16: // assignment operator using the copy policy to decide if non_copyable, shallow or deep copying is necessary Chris@16: library_sm& operator= (library_sm const& rhs) Chris@16: { Chris@16: if (this != &rhs) Chris@16: { Chris@16: Derived::operator=(rhs); Chris@16: do_copy(rhs); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: state_machine Chris@16: (library_sm const& rhs) Chris@16: : Derived(rhs) Chris@16: { Chris@16: if (this != &rhs) Chris@16: { Chris@16: // initialize our list of states with the ones defined in Derived::initial_state Chris@16: fill_states(this); Chris@16: do_copy(rhs); Chris@16: } Chris@16: } Chris@16: Chris@16: // the following 2 functions handle the terminate/interrupt states handling Chris@16: // if one of these states is found, the first one is used Chris@16: template Chris@16: bool is_event_handling_blocked_helper( ::boost::mpl::true_ const &) Chris@16: { Chris@16: // if the state machine is terminated, do not handle any event Chris@16: if (is_flag_active< ::boost::msm::TerminateFlag>()) Chris@16: return true; Chris@16: // if the state machine is interrupted, do not handle any event Chris@16: // unless the event is the end interrupt event Chris@16: if ( is_flag_active< ::boost::msm::InterruptedFlag>() && Chris@16: !is_flag_active< ::boost::msm::EndInterruptFlag >()) Chris@16: return true; Chris@16: return false; Chris@16: } Chris@16: // otherwise simple handling, no flag => continue Chris@16: template Chris@16: bool is_event_handling_blocked_helper( ::boost::mpl::false_ const &) Chris@16: { Chris@16: // no terminate/interrupt states detected Chris@16: return false; Chris@16: } Chris@16: // the following functions handle pre/post-process handling of a message queue Chris@16: template Chris@101: bool do_pre_msg_queue_helper(EventType const&, ::boost::mpl::true_ const &) Chris@16: { Chris@16: // no message queue needed Chris@16: return true; Chris@16: } Chris@16: template Chris@16: bool do_pre_msg_queue_helper(EventType const& evt, ::boost::mpl::false_ const &) Chris@16: { Chris@16: execute_return (library_sm::*pf) (EventType const& evt) = Chris@16: &library_sm::process_event; Chris@16: // if we are already processing an event Chris@16: if (m_event_processing) Chris@16: { Chris@16: // event has to be put into the queue Chris@16: transition_fct f = ::boost::bind(pf,this,evt); Chris@16: m_events_queue.m_events_queue.push_back(f); Chris@16: return false; Chris@16: } Chris@16: // event can be handled, processing Chris@16: m_event_processing = true; Chris@16: return true; Chris@16: } Chris@16: void do_post_msg_queue_helper( ::boost::mpl::true_ const &) Chris@16: { Chris@16: // no message queue needed Chris@16: } Chris@16: void do_post_msg_queue_helper( ::boost::mpl::false_ const &) Chris@16: { Chris@16: m_event_processing = false; Chris@16: process_message_queue(this); Chris@16: } Chris@16: // the following 2 functions handle the processing either with a try/catch protection or without Chris@16: template Chris@16: HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::true_ const &, bool is_direct_call) Chris@16: { Chris@16: return this->do_process_event(evt,is_direct_call); Chris@16: } Chris@16: template Chris@16: HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::false_ const &, bool is_direct_call) Chris@16: { Chris@16: // when compiling without exception support there is no formal parameter "e" in the catch handler. Chris@16: // Declaring a local variable here does not hurt and will be "used" to make the code in the handler Chris@16: // compilable although the code will never be executed. Chris@16: std::exception e; Chris@16: BOOST_TRY Chris@16: { Chris@16: return this->do_process_event(evt,is_direct_call); Chris@16: } Chris@16: BOOST_CATCH (std::exception& e) Chris@16: { Chris@16: // give a chance to the concrete state machine to handle Chris@16: this->exception_caught(evt,*this,e); Chris@16: } Chris@16: BOOST_CATCH_END Chris@101: return HANDLED_TRUE; Chris@16: } Chris@16: // handling of deferred events Chris@16: // if none is found in the SM, take the following empty main version Chris@16: template Chris@16: struct handle_defer_helper Chris@16: { Chris@16: handle_defer_helper(deferred_msg_queue_helper& ){} Chris@16: void do_pre_handle_deferred() Chris@16: { Chris@16: } Chris@16: Chris@16: void do_post_handle_deferred(HandledEnum) Chris@16: { Chris@16: } Chris@16: }; Chris@16: // otherwise the standard version handling the deferred events Chris@16: template Chris@16: struct handle_defer_helper Chris@16: ::type,int >::type> Chris@16: { Chris@16: handle_defer_helper(deferred_msg_queue_helper& a_queue): Chris@16: events_queue(a_queue),next_deferred_event(){} Chris@16: void do_pre_handle_deferred() Chris@16: { Chris@16: } Chris@16: Chris@16: void do_post_handle_deferred(HandledEnum handled) Chris@16: { Chris@16: if (handled == HANDLED_TRUE) Chris@16: { Chris@16: // a transition has been taken, it makes sense again to try processing waiting deferred events Chris@16: // reset all events to not tested Chris@16: for (std::size_t i = 0; i < events_queue.m_deferred_events_queue.size(); ++i) Chris@16: { Chris@16: events_queue.m_deferred_events_queue[i].second=false; Chris@16: } Chris@16: // test first event Chris@16: if (!events_queue.m_deferred_events_queue.empty()) Chris@16: { Chris@16: deferred_fct next = events_queue.m_deferred_events_queue.front().first; Chris@16: events_queue.m_deferred_events_queue.pop_front(); Chris@16: next(); Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: // look for next deferred event, if any Chris@16: typename deferred_events_queue_t::iterator it = Chris@16: std::find_if(events_queue.m_deferred_events_queue.begin(), Chris@16: events_queue.m_deferred_events_queue.end(), Chris@16: boost::bind(&std::pair::second, _1) == false); Chris@16: if (it != events_queue.m_deferred_events_queue.end()) Chris@16: { Chris@16: (*it).second = true; Chris@16: deferred_fct next = (*it).first; Chris@16: events_queue.m_deferred_events_queue.erase(it); Chris@16: next(); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: deferred_msg_queue_helper& events_queue; Chris@16: deferred_fct next_deferred_event; Chris@16: }; Chris@16: Chris@16: // handling of eventless transitions Chris@16: // if none is found in the SM, nothing to do Chris@16: template Chris@16: struct handle_eventless_transitions_helper Chris@16: { Chris@16: handle_eventless_transitions_helper(library_sm* , bool ){} Chris@16: void process_completion_event(){} Chris@16: }; Chris@16: // otherwise Chris@16: template Chris@16: struct handle_eventless_transitions_helper Chris@16: ::type >::type> Chris@16: { Chris@16: handle_eventless_transitions_helper(library_sm* self_, bool handled_):self(self_),handled(handled_){} Chris@16: void process_completion_event() Chris@16: { Chris@16: typedef typename ::boost::mpl::deref< Chris@16: typename ::boost::mpl::begin< Chris@16: typename find_completion_events::type Chris@16: >::type Chris@16: >::type first_completion_event; Chris@16: if (handled) Chris@16: { Chris@16: self->process_event(first_completion_event() ); Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: library_sm* self; Chris@16: bool handled; Chris@16: }; Chris@16: Chris@16: // helper class called in case the event to process has been found in the fsm's internal stt and is therefore processable Chris@16: template Chris@16: struct process_fsm_internal_table Chris@16: { Chris@16: typedef typename ::boost::mpl::has_key::type is_event_processable; Chris@16: Chris@16: // forward to the correct do_process Chris@16: static void process(Event const& evt,library_sm* self_,HandledEnum& result) Chris@16: { Chris@16: do_process(evt,self_,result,is_event_processable()); Chris@16: } Chris@16: private: Chris@16: // the event is processable, let's try! Chris@16: static void do_process(Event const& evt,library_sm* self_,HandledEnum& result, ::boost::mpl::true_) Chris@16: { Chris@16: if (result != HANDLED_TRUE) Chris@16: { Chris@16: typedef dispatch_table table; Chris@16: HandledEnum res_internal = table::instance.entries[0](*self_, 0, self_->m_states[0], evt); Chris@16: result = (HandledEnum)((int)result | (int)res_internal); Chris@16: } Chris@16: } Chris@16: // version doing nothing if the event is not in the internal stt and we can save ourselves the time trying to process Chris@16: static void do_process(Event const& ,library_sm* ,HandledEnum& , ::boost::mpl::false_) Chris@16: { Chris@16: // do nothing Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct region_processing_helper Chris@16: { Chris@16: public: Chris@16: region_processing_helper(library_sm* self_,HandledEnum& result_) Chris@16: :self(self_),result(result_){} Chris@16: template Chris@16: void process(Event const& evt) Chris@16: { Chris@16: // use this table as if it came directly from the user Chris@16: typedef dispatch_table table; Chris@16: // +1 because index 0 is reserved for this fsm Chris@16: HandledEnum res = Chris@16: table::instance.entries[self->m_states[0]+1]( Chris@16: *self, 0, self->m_states[0], evt); Chris@16: result = (HandledEnum)((int)result | (int)res); Chris@16: // process the event in the internal table of this fsm if the event is processable (present in the table) Chris@16: process_fsm_internal_table::process(evt,self,result); Chris@16: } Chris@16: library_sm* self; Chris@16: HandledEnum& result; Chris@16: }; Chris@16: // version with visitors Chris@16: template Chris@16: struct region_processing_helper >::type> Chris@16: { Chris@16: private: Chris@16: // process event in one region Chris@16: template Chris@16: struct In Chris@16: { Chris@16: template Chris@16: static void process(Event const& evt,library_sm* self_,HandledEnum& result_) Chris@16: { Chris@16: // use this table as if it came directly from the user Chris@16: typedef dispatch_table table; Chris@16: // +1 because index 0 is reserved for this fsm Chris@16: HandledEnum res = Chris@16: table::instance.entries[self_->m_states[region_id::value]+1]( Chris@16: *self_, region_id::value , self_->m_states[region_id::value], evt); Chris@16: result_ = (HandledEnum)((int)result_ | (int)res); Chris@16: In< ::boost::mpl::int_ >::process(evt,self_,result_); Chris@16: } Chris@16: }; Chris@16: template Chris@16: struct In< ::boost::mpl::int_,Dummy> Chris@16: { Chris@16: // end of processing Chris@16: template Chris@16: static void process(Event const& evt,library_sm* self_,HandledEnum& result_) Chris@16: { Chris@16: // process the event in the internal table of this fsm if the event is processable (present in the table) Chris@16: process_fsm_internal_table::process(evt,self_,result_); Chris@16: } Chris@16: }; Chris@16: public: Chris@16: region_processing_helper(library_sm* self_,HandledEnum& result_) Chris@16: :self(self_),result(result_){} Chris@16: template Chris@16: void process(Event const& evt) Chris@16: { Chris@16: In< ::boost::mpl::int_<0> >::process(evt,self,result); Chris@16: } Chris@16: Chris@16: library_sm* self; Chris@16: HandledEnum& result; Chris@16: }; Chris@16: Chris@16: // Main function used internally to make transitions Chris@16: // Can only be called for internally (for example in an action method) generated events. Chris@16: template Chris@16: execute_return process_event_internal(Event const& evt, bool is_direct_call) Chris@16: { Chris@16: HandledEnum ret_handled=HANDLED_FALSE; Chris@16: // if the state machine has terminate or interrupt flags, check them, otherwise skip Chris@16: if (is_event_handling_blocked_helper Chris@16: ( ::boost::mpl::bool_::type::value>() ) ) Chris@16: return HANDLED_TRUE; Chris@16: // if a message queue is needed and processing is on the way Chris@16: if (!do_pre_msg_queue_helper Chris@16: (evt,::boost::mpl::bool_::type::value>()) ) Chris@16: { Chris@16: // wait for the end of current processing Chris@16: return HANDLED_TRUE; Chris@16: } Chris@16: else Chris@16: { Chris@16: // prepare the next deferred event for handling Chris@16: // if one defer is found in the SM, otherwise skip Chris@16: handle_defer_helper defer_helper(m_deferred_events_queue); Chris@16: defer_helper.do_pre_handle_deferred(); Chris@16: // process event Chris@16: HandledEnum handled = this->do_process_helper Chris@16: (evt,::boost::mpl::bool_::type::value>(),is_direct_call); Chris@16: if (handled) Chris@16: { Chris@16: ret_handled = handled; Chris@16: } Chris@16: Chris@16: // process completion transitions BEFORE any other event in the pool (UML Standard 2.3 15.3.14) Chris@16: handle_eventless_transitions_helper eventless_helper(this,(handled == HANDLED_TRUE)); Chris@16: eventless_helper.process_completion_event(); Chris@16: Chris@16: // after handling, take care of the deferred events Chris@16: defer_helper.do_post_handle_deferred(handled); Chris@16: Chris@16: // now check if some events were generated in a transition and was not handled Chris@16: // because of another processing, and if yes, start handling them Chris@16: do_post_msg_queue_helper(::boost::mpl::bool_::type::value>()); Chris@16: Chris@16: return ret_handled; Chris@16: } Chris@16: } Chris@16: Chris@16: // minimum event processing without exceptions, queues, etc. Chris@16: template Chris@16: HandledEnum do_process_event(Event const& evt, bool is_direct_call) Chris@16: { Chris@16: HandledEnum handled = HANDLED_FALSE; Chris@16: // dispatch the event to every region Chris@16: region_processing_helper helper(this,handled); Chris@16: helper.process(evt); Chris@16: Chris@16: // if the event has not been handled and we have orthogonal zones, then Chris@16: // generate an error on every active state Chris@16: // for state machine states contained in other state machines, do not handle Chris@16: // but let the containing sm handle the error, unless the event was generated in this fsm Chris@16: // (by calling process_event on this fsm object, is_direct_call == true) Chris@16: // completion events do not produce an error Chris@16: if ( (!is_contained() || is_direct_call) && !handled && !is_completion_event::type::value) Chris@16: { Chris@16: for (int i=0; ino_transition(evt,*this,this->m_states[i]); Chris@16: } Chris@16: } Chris@16: return handled; Chris@16: } Chris@16: Chris@16: // default row arguments for the compilers which accept this Chris@16: template Chris@16: bool no_guard(Event const&){return true;} Chris@16: template Chris@16: void no_action(Event const&){} Chris@16: Chris@16: #ifndef BOOST_NO_RTTI Chris@16: HandledEnum process_any_event( ::boost::any const& evt); Chris@16: #endif Chris@16: Chris@16: private: Chris@16: // composite accept implementation. First calls accept on the composite, then accept on all its active states. Chris@16: void composite_accept() Chris@16: { Chris@16: this->accept(); Chris@16: this->visit_current_states(); Chris@16: } Chris@16: Chris@16: #define MSM_COMPOSITE_ACCEPT_SUB(z, n, unused) ARG ## n vis ## n Chris@16: #define MSM_COMPOSITE_ACCEPT_SUB2(z, n, unused) boost::ref( vis ## n ) Chris@16: #define MSM_COMPOSITE_ACCEPT_EXECUTE(z, n, unused) \ Chris@16: template \ Chris@16: void composite_accept(BOOST_PP_ENUM(n, MSM_COMPOSITE_ACCEPT_SUB, ~ ) ) \ Chris@16: { \ Chris@16: this->accept(BOOST_PP_ENUM_PARAMS(n,vis)); \ Chris@16: this->visit_current_states(BOOST_PP_ENUM(n,MSM_COMPOSITE_ACCEPT_SUB2, ~)); \ Chris@16: } Chris@16: BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_COMPOSITE_ACCEPT_EXECUTE, ~) Chris@16: #undef MSM_COMPOSITE_ACCEPT_EXECUTE Chris@16: #undef MSM_COMPOSITE_ACCEPT_SUB Chris@16: #undef MSM_COMPOSITE_ACCEPT_SUB2 Chris@16: Chris@16: // helper used to call the init states at the start of the state machine Chris@16: template Chris@16: struct call_init Chris@16: { Chris@16: call_init(Event const& an_event,library_sm* self_): Chris@16: evt(an_event),self(self_){} Chris@16: template Chris@16: void operator()(boost::msm::wrap const&) Chris@16: { Chris@16: execute_entry(::boost::fusion::at_key(self->m_substate_list),evt,*self); Chris@16: } Chris@16: private: Chris@16: Event const& evt; Chris@16: library_sm* self; Chris@16: }; Chris@16: // helper for flag handling. Uses OR by default on orthogonal zones. Chris@16: template Chris@16: struct FlagHelper Chris@16: { Chris@16: static bool helper(library_sm const& sm,flag_handler* ) Chris@16: { Chris@16: // by default we use OR to accumulate the flags Chris@16: return sm.is_flag_active(); Chris@16: } Chris@16: }; Chris@16: template Chris@16: struct FlagHelper Chris@16: { Chris@16: static bool helper(library_sm const& sm,flag_handler* flags_entries) Chris@16: { Chris@16: // just one active state, so we can call operator[] with 0 Chris@16: return flags_entries[sm.current_state()[0]](sm); Chris@16: } Chris@16: }; Chris@16: // handling of flag Chris@16: // defines a true and false functions plus a forwarding one for composite states Chris@16: template Chris@16: struct FlagHandler Chris@16: { Chris@16: static bool flag_true(library_sm const& ) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: static bool flag_false(library_sm const& ) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: static bool forward(library_sm const& fsm) Chris@16: { Chris@16: return ::boost::fusion::at_key(fsm.m_substate_list).template is_flag_active(); Chris@16: } Chris@16: }; Chris@16: template Chris@16: struct init_flags Chris@16: { Chris@16: private: Chris@16: // helper function, helps hiding the forward function for non-state machines states. Chris@16: template Chris@16: void helper (flag_handler* an_entry,int offset, ::boost::mpl::true_ const & ) Chris@16: { Chris@16: // composite => forward Chris@16: an_entry[offset] = &FlagHandler::forward; Chris@16: } Chris@16: template Chris@16: void helper (flag_handler* an_entry,int offset, ::boost::mpl::false_ const & ) Chris@16: { Chris@16: // default no flag Chris@16: an_entry[offset] = &FlagHandler::flag_false; Chris@16: } Chris@16: // attributes Chris@16: flag_handler* entries; Chris@16: Chris@16: public: Chris@16: init_flags(flag_handler* entries_) Chris@16: : entries(entries_) Chris@16: {} Chris@16: Chris@16: // Flags initializer function object, used with mpl::for_each Chris@16: template Chris@16: void operator()( ::boost::msm::wrap const& ) Chris@16: { Chris@16: typedef typename get_flag_list::type flags; Chris@16: typedef typename ::boost::mpl::contains::type found; Chris@16: typedef typename is_composite_state::type composite; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(int, state_id = (get_state_id::type::value)); Chris@16: if (found::type::value) Chris@16: { Chris@16: // the type defined the flag => true Chris@16: entries[state_id] = &FlagHandler::flag_true; Chris@16: } Chris@16: else Chris@16: { Chris@16: // false or forward Chris@16: typedef typename ::boost::mpl::and_< Chris@16: typename is_composite_state::type, Chris@16: typename ::boost::mpl::not_< Chris@16: typename has_non_forwarding_flag::type>::type >::type composite_no_forward; Chris@16: Chris@16: helper(entries,state_id,::boost::mpl::bool_()); Chris@16: } Chris@16: } Chris@16: }; Chris@16: // maintains for every flag a static array containing the flag value for every state Chris@16: template Chris@16: flag_handler* get_entries_for_flag() const Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, max_state = (mpl::size::value)); Chris@16: Chris@16: static flag_handler flags_entries[max_state]; Chris@16: // build a state list Chris@16: ::boost::mpl::for_each > Chris@16: (init_flags(flags_entries)); Chris@16: return flags_entries; Chris@16: } Chris@16: Chris@16: // helper used to create a state using the correct constructor Chris@16: template Chris@16: struct create_state_helper Chris@16: { Chris@16: static void set_sm(library_sm* ) Chris@16: { Chris@16: // state doesn't need its sm Chris@16: } Chris@16: }; Chris@16: // create a state requiring a pointer to the state machine Chris@16: template Chris@16: struct create_state_helper::type> Chris@16: { Chris@16: static void set_sm(library_sm* sm) Chris@16: { Chris@16: // create and set the fsm Chris@16: ::boost::fusion::at_key(sm->m_substate_list).set_sm_ptr(sm); Chris@16: } Chris@16: }; Chris@16: // main unspecialized helper class Chris@16: template Chris@16: struct visitor_args; Chris@16: Chris@16: #define MSM_VISITOR_ARGS_SUB(z, n, unused) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1)) Chris@16: #define MSM_VISITOR_ARGS_TYPEDEF_SUB(z, n, unused) typename StateType::accept_sig::argument ## n Chris@16: Chris@16: #define MSM_VISITOR_ARGS_EXECUTE(z, n, unused) \ Chris@16: template \ Chris@16: struct visitor_args \ Chris@16: { \ Chris@16: template \ Chris@16: static typename enable_if_c::value,void >::type \ Chris@16: helper (library_sm* sm, \ Chris@16: int id,StateType& astate) \ Chris@16: { \ Chris@16: sm->m_visitors.insert(id, boost::bind(&StateType::accept, \ Chris@16: ::boost::ref(astate) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_SUB, ~) )); \ Chris@16: } \ Chris@16: template \ Chris@16: static typename enable_if_c::value,void >::type \ Chris@16: helper (library_sm* sm, \ Chris@16: int id,StateType& astate) \ Chris@16: { \ Chris@16: void (StateType::*caccept)(BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_TYPEDEF_SUB, ~ ) ) \ Chris@16: = &StateType::composite_accept; \ Chris@16: sm->m_visitors.insert(id, boost::bind(caccept, \ Chris@16: ::boost::ref(astate) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_SUB, ~) )); \ Chris@16: } \ Chris@16: }; Chris@16: BOOST_PP_REPEAT(BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_VISITOR_ARGS_EXECUTE, ~) Chris@16: #undef MSM_VISITOR_ARGS_EXECUTE Chris@16: #undef MSM_VISITOR_ARGS_SUB Chris@16: Chris@16: // the IBM compiler seems to have problems with nested classes Chris@16: // the same seems to apply to the Apple version of gcc 4.0.1 (just in case we do for < 4.1) Chris@16: // and also to MS VC < 8 Chris@16: #if defined (__IBMCPP__) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (defined(_MSC_VER) && (_MSC_VER < 1400)) Chris@16: public: Chris@16: #endif Chris@16: template Chris@16: void set_containing_sm(ContainingSM* sm) Chris@16: { Chris@16: m_is_included=true; Chris@16: ::boost::fusion::for_each(m_substate_list,add_state(this,sm)); Chris@16: } Chris@16: #if defined (__IBMCPP__) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (defined(_MSC_VER) && (_MSC_VER < 1400)) Chris@16: private: Chris@16: #endif Chris@16: // A function object for use with mpl::for_each that stuffs Chris@16: // states into the state list. Chris@16: template Chris@16: struct add_state Chris@16: { Chris@16: add_state(library_sm* self_,ContainingSM* sm) Chris@16: : self(self_),containing_sm(sm){} Chris@16: Chris@16: // State is a sub fsm with exit pseudo states and gets a pointer to this fsm, so it can build a callback Chris@16: template Chris@16: typename ::boost::enable_if< Chris@16: typename is_composite_state::type,void >::type Chris@16: new_state_helper(boost::msm::back::dummy<0> = 0) const Chris@16: { Chris@16: ::boost::fusion::at_key(self->m_substate_list).set_containing_sm(containing_sm); Chris@16: } Chris@16: // State is a sub fsm without exit pseudo states and does not get a callback to this fsm Chris@16: // or state is a normal state and needs nothing except creation Chris@16: template Chris@16: typename ::boost::enable_if< Chris@16: typename boost::mpl::and_::type>::type, Chris@16: typename boost::mpl::not_ Chris@16: ::type>::type Chris@16: >::type,void>::type Chris@16: new_state_helper( ::boost::msm::back::dummy<1> = 0) const Chris@16: { Chris@16: //nothing to do Chris@16: } Chris@16: // state is exit pseudo state and gets callback to target fsm Chris@16: template Chris@16: typename ::boost::enable_if::type,void >::type Chris@16: new_state_helper( ::boost::msm::back::dummy<2> = 0) const Chris@16: { Chris@16: execute_return (ContainingSM::*pf) (typename StateType::event const& evt)= Chris@16: &ContainingSM::process_event; Chris@16: ::boost::function fct = Chris@16: ::boost::bind(pf,containing_sm,_1); Chris@16: ::boost::fusion::at_key(self->m_substate_list).set_forward_fct(fct); Chris@16: } Chris@16: // for every defined state in the sm Chris@16: template Chris@16: void operator()( State const&) const Chris@16: { Chris@16: //create a new state with the defined id and type Chris@16: BOOST_STATIC_CONSTANT(int, state_id = (get_state_id::value)); Chris@16: Chris@16: this->new_state_helper(), Chris@16: create_state_helper::set_sm(self); Chris@16: // create a visitor callback Chris@16: visitor_helper(state_id,::boost::fusion::at_key(self->m_substate_list), Chris@16: ::boost::mpl::bool_::type::value>()); Chris@16: } Chris@16: private: Chris@16: // support possible use of a visitor if accept_sig is defined Chris@16: template Chris@16: void visitor_helper(int id,StateType& astate, ::boost::mpl::true_ const & ) const Chris@16: { Chris@16: visitor_args:: Chris@16: template helper(self,id,astate); Chris@16: } Chris@16: template Chris@16: void visitor_helper(int ,StateType& , ::boost::mpl::false_ const &) const Chris@16: { Chris@16: // nothing to do Chris@16: } Chris@16: Chris@16: library_sm* self; Chris@16: ContainingSM* containing_sm; Chris@16: }; Chris@16: Chris@16: // helper used to copy every state if needed Chris@16: struct copy_helper Chris@16: { Chris@16: copy_helper(library_sm* sm): Chris@16: m_sm(sm){} Chris@16: template Chris@16: void operator()( ::boost::msm::wrap const& ) Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, state_id = (get_state_id::type::value)); Chris@16: // possibly also set the visitor Chris@16: visitor_helper(state_id); Chris@16: Chris@16: // and for states that keep a pointer to the fsm, reset the pointer Chris@16: create_state_helper::set_sm(m_sm); Chris@16: } Chris@16: template Chris@16: typename ::boost::enable_if::type,void >::type Chris@16: visitor_helper(int id) const Chris@16: { Chris@16: visitor_args::template helper Chris@16: (m_sm,id,::boost::fusion::at_key(m_sm->m_substate_list)); Chris@16: } Chris@16: template Chris@16: typename ::boost::disable_if::type,void >::type Chris@16: visitor_helper(int) const Chris@16: { Chris@16: // nothing to do Chris@16: } Chris@16: Chris@16: library_sm* m_sm; Chris@16: }; Chris@16: // helper to copy the active states attribute Chris@16: template Chris@16: struct region_copy_helper Chris@16: { Chris@16: static void do_copy(library_sm* self_,library_sm const& rhs) Chris@16: { Chris@16: self_->m_states[region_id::value] = rhs.m_states[region_id::value]; Chris@16: region_copy_helper< ::boost::mpl::int_ >::do_copy(self_,rhs); Chris@16: } Chris@16: }; Chris@16: template Chris@16: struct region_copy_helper< ::boost::mpl::int_,Dummy> Chris@16: { Chris@16: // end of processing Chris@16: static void do_copy(library_sm*,library_sm const& ){} Chris@16: }; Chris@16: // copy functions for deep copy (no need of a 2nd version for NoCopy as noncopyable handles it) Chris@16: void do_copy (library_sm const& rhs, Chris@16: ::boost::msm::back::dummy<0> = 0) Chris@16: { Chris@16: // deep copy simply assigns the data Chris@16: region_copy_helper< ::boost::mpl::int_<0> >::do_copy(this,rhs); Chris@16: m_events_queue = rhs.m_events_queue; Chris@16: m_deferred_events_queue = rhs.m_deferred_events_queue; Chris@16: m_history = rhs.m_history; Chris@16: m_event_processing = rhs.m_event_processing; Chris@16: m_is_included = rhs.m_is_included; Chris@16: m_substate_list = rhs.m_substate_list; Chris@16: // except for the states themselves, which get duplicated Chris@16: Chris@16: ::boost::mpl::for_each > Chris@16: (copy_helper(this)); Chris@16: } Chris@16: Chris@16: // helper used to call the correct entry/exit method Chris@16: // unfortunately in O(number of states in the sub-sm) but should be better than a virtual call Chris@16: template Chris@16: struct entry_exit_helper Chris@16: { Chris@16: entry_exit_helper(int id,Event const& e,library_sm* self_): Chris@16: state_id(id),evt(e),self(self_){} Chris@16: // helper for entry actions Chris@16: template Chris@16: typename ::boost::enable_if::type Chris@16: helper( ::boost::msm::back::dummy<0> = 0) Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, id = (get_state_id::value)); Chris@16: if (id == state_id) Chris@16: { Chris@16: execute_entry(::boost::fusion::at_key(self->m_substate_list),evt,*self); Chris@16: } Chris@16: } Chris@16: // helper for exit actions Chris@16: template Chris@16: typename boost::disable_if::type Chris@16: helper( ::boost::msm::back::dummy<1> = 0) Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, id = (get_state_id::value)); Chris@16: if (id == state_id) Chris@16: { Chris@16: execute_exit(::boost::fusion::at_key(self->m_substate_list),evt,*self); Chris@16: } Chris@16: } Chris@16: // iterates through all states to find the one to be activated Chris@16: template Chris@16: void operator()( ::boost::msm::wrap const&) Chris@16: { Chris@16: entry_exit_helper::template helper< ::boost::mpl::bool_,State >(); Chris@16: } Chris@16: private: Chris@16: int state_id; Chris@16: Event const& evt; Chris@16: library_sm* self; Chris@16: }; Chris@16: Chris@16: // helper to start the fsm Chris@16: template Chris@16: struct region_start_helper Chris@16: { Chris@16: template Chris@16: static void do_start(library_sm* self_,Event const& incomingEvent) Chris@16: { Chris@16: //forward the event for handling by sub state machines Chris@16: ::boost::mpl::for_each > Chris@16: (entry_exit_helper(self_->m_states[region_id::value],incomingEvent,self_)); Chris@16: region_start_helper Chris@16: < ::boost::mpl::int_ >::do_start(self_,incomingEvent); Chris@16: } Chris@16: }; Chris@16: template Chris@16: struct region_start_helper< ::boost::mpl::int_,Dummy> Chris@16: { Chris@16: // end of processing Chris@16: template Chris@16: static void do_start(library_sm*,Event const& ){} Chris@16: }; Chris@16: // start for states machines which are themselves embedded in other state machines (composites) Chris@16: template Chris@16: void internal_start(Event const& incomingEvent) Chris@16: { Chris@16: region_start_helper< ::boost::mpl::int_<0> >::do_start(this,incomingEvent); Chris@16: // give a chance to handle an anonymous (eventless) transition Chris@16: handle_eventless_transitions_helper eventless_helper(this,true); Chris@16: eventless_helper.process_completion_event(); Chris@16: } Chris@16: Chris@16: template Chris@16: struct find_region_id Chris@16: { Chris@16: template Chris@16: struct In Chris@16: { Chris@16: enum {region_index=region}; Chris@16: }; Chris@16: // if the user provides no region, find it! Chris@16: template Chris@16: struct In<-1,Dummy> Chris@16: { Chris@16: typedef typename build_orthogonal_regions< Chris@16: library_sm, Chris@16: initial_states Chris@16: >::type all_regions; Chris@16: enum {region_index= find_region_index::value }; Chris@16: }; Chris@16: enum {region_index = In::region_index }; Chris@16: }; Chris@16: // helper used to set the correct state as active state upon entry into a fsm Chris@16: struct direct_event_start_helper Chris@16: { Chris@16: direct_event_start_helper(library_sm* self_):self(self_){} Chris@16: // this variant is for the standard case, entry due to activation of the containing FSM Chris@16: template Chris@16: typename ::boost::disable_if::type,void>::type Chris@16: operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<0> = 0) Chris@16: { Chris@16: (static_cast(self))->on_entry(evt,fsm); Chris@16: self->internal_start(evt); Chris@16: } Chris@16: Chris@16: // this variant is for the direct entry case (just one entry, not a sequence of entries) Chris@16: template Chris@16: typename ::boost::enable_if< Chris@16: typename ::boost::mpl::and_< Chris@16: typename ::boost::mpl::not_< typename is_pseudo_entry< Chris@16: typename EventType::active_state>::type >::type, Chris@16: typename ::boost::mpl::and_::type, Chris@16: typename ::boost::mpl::not_::type >::type Chris@16: >::type>::type,void Chris@16: >::type Chris@16: operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0) Chris@16: { Chris@16: (static_cast(self))->on_entry(evt,fsm); Chris@16: int state_id = get_state_id::value; Chris@16: BOOST_STATIC_ASSERT(find_region_id::region_index >= 0); Chris@16: BOOST_STATIC_ASSERT(find_region_id::region_index < nr_regions::value); Chris@16: // just set the correct zone, the others will be default/history initialized Chris@16: self->m_states[find_region_id::region_index] = state_id; Chris@16: self->internal_start(evt.m_event); Chris@16: } Chris@16: Chris@16: // this variant is for the fork entry case (a sequence on entries) Chris@16: template Chris@16: typename ::boost::enable_if< Chris@16: typename ::boost::mpl::and_< Chris@16: typename ::boost::mpl::not_< Chris@16: typename is_pseudo_entry::type >::type, Chris@16: typename ::boost::mpl::and_::type, Chris@16: typename ::boost::mpl::is_sequence< Chris@16: typename EventType::active_state>::type Chris@16: >::type>::type,void Chris@16: >::type Chris@16: operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0) Chris@16: { Chris@16: (static_cast(self))->on_entry(evt,fsm); Chris@16: ::boost::mpl::for_each > Chris@16: (fork_helper(self,evt)); Chris@16: // set the correct zones, the others (if any) will be default/history initialized Chris@16: self->internal_start(evt.m_event); Chris@16: } Chris@16: Chris@16: // this variant is for the pseudo state entry case Chris@16: template Chris@16: typename ::boost::enable_if< Chris@16: typename is_pseudo_entry::type,void Chris@16: >::type Chris@16: operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<3> = 0) Chris@16: { Chris@16: // entry on the FSM Chris@16: (static_cast(self))->on_entry(evt,fsm); Chris@16: int state_id = get_state_id::value; Chris@16: BOOST_STATIC_ASSERT(find_region_id::region_index >= 0); Chris@16: BOOST_STATIC_ASSERT(find_region_id::region_index < nr_regions::value); Chris@16: // given region starts with the entry pseudo state as active state Chris@16: self->m_states[find_region_id::region_index] = state_id; Chris@16: self->internal_start(evt.m_event); Chris@16: // and we process the transition in the zone of the newly active state Chris@16: // (entry pseudo states are, according to UML, a state connecting 1 transition outside to 1 inside Chris@16: self->process_event(evt.m_event); Chris@16: } Chris@16: private: Chris@16: // helper for the fork case, does almost like the direct entry Chris@16: library_sm* self; Chris@16: template Chris@16: struct fork_helper Chris@16: { Chris@16: fork_helper(library_sm* self_,EventType const& evt_): Chris@16: helper_self(self_),helper_evt(evt_){} Chris@16: template Chris@16: void operator()( ::boost::msm::wrap const& ) Chris@16: { Chris@16: int state_id = get_state_id::value; Chris@16: BOOST_STATIC_ASSERT(find_region_id::region_index >= 0); Chris@16: BOOST_STATIC_ASSERT(find_region_id::region_index < nr_regions::value); Chris@16: helper_self->m_states[find_region_id::region_index] = state_id; Chris@16: } Chris@16: private: Chris@16: library_sm* helper_self; Chris@16: EventType const& helper_evt; Chris@16: }; Chris@16: }; Chris@16: Chris@16: // helper for entry Chris@16: template Chris@16: struct region_entry_exit_helper Chris@16: { Chris@16: template Chris@16: static void do_entry(library_sm* self_,Event const& incomingEvent) Chris@16: { Chris@16: self_->m_states[region_id::value] = Chris@16: self_->m_history.history_entry(incomingEvent)[region_id::value]; Chris@16: region_entry_exit_helper Chris@16: < ::boost::mpl::int_ >::do_entry(self_,incomingEvent); Chris@16: } Chris@16: template Chris@16: static void do_exit(library_sm* self_,Event const& incomingEvent) Chris@16: { Chris@16: ::boost::mpl::for_each > Chris@16: (entry_exit_helper(self_->m_states[region_id::value],incomingEvent,self_)); Chris@16: region_entry_exit_helper Chris@16: < ::boost::mpl::int_ >::do_exit(self_,incomingEvent); Chris@16: } Chris@16: }; Chris@16: template Chris@16: struct region_entry_exit_helper< ::boost::mpl::int_,Dummy> Chris@16: { Chris@16: // end of processing Chris@16: template Chris@16: static void do_entry(library_sm*,Event const& ){} Chris@16: template Chris@16: static void do_exit(library_sm*,Event const& ){} Chris@16: }; Chris@16: // entry/exit for states machines which are themselves embedded in other state machines (composites) Chris@16: template Chris@16: void do_entry(Event const& incomingEvent,FsmType& fsm) Chris@16: { Chris@16: // by default we activate the history/init states, can be overwritten by direct_event_start_helper Chris@16: region_entry_exit_helper< ::boost::mpl::int_<0> >::do_entry(this,incomingEvent); Chris@16: // block immediate handling of events Chris@16: m_event_processing = true; Chris@16: // if the event is generating a direct entry/fork, set the current state(s) to the direct state(s) Chris@16: direct_event_start_helper(this)(incomingEvent,fsm); Chris@16: // handle messages which were generated and blocked in the init calls Chris@16: m_event_processing = false; Chris@101: // look for deferred events waiting Chris@101: handle_defer_helper defer_helper(m_deferred_events_queue); Chris@101: defer_helper.do_post_handle_deferred(HANDLED_TRUE); Chris@16: process_message_queue(this); Chris@16: } Chris@16: template Chris@16: void do_exit(Event const& incomingEvent,FsmType& fsm) Chris@16: { Chris@16: // first recursively exit the sub machines Chris@16: // forward the event for handling by sub state machines Chris@16: region_entry_exit_helper< ::boost::mpl::int_<0> >::do_exit(this,incomingEvent); Chris@16: // then call our own exit Chris@16: (static_cast(this))->on_exit(incomingEvent,fsm); Chris@16: // give the history a chance to handle this (or not). Chris@16: m_history.history_exit(this->m_states); Chris@101: // history decides what happens with deferred events Chris@101: if (!m_history.process_deferred_events(incomingEvent)) Chris@101: { Chris@101: clear_deferred_queue(); Chris@101: } Chris@16: } Chris@16: Chris@16: // the IBM and VC<8 compilers seem to have problems with the friend declaration of dispatch_table Chris@16: #if defined (__IBMCPP__) || (defined(_MSC_VER) && (_MSC_VER < 1400)) Chris@16: public: Chris@16: #endif Chris@16: // no transition for event. Chris@16: template Chris@16: static HandledEnum call_no_transition(library_sm& , int , int , Event const& ) Chris@16: { Chris@16: return HANDLED_FALSE; Chris@16: } Chris@16: // no transition for event for internal transitions (not an error). Chris@16: template Chris@16: static HandledEnum call_no_transition_internal(library_sm& , int , int , Event const& ) Chris@16: { Chris@16: //// reject to give others a chance to handle Chris@16: //return HANDLED_GUARD_REJECT; Chris@16: return HANDLED_FALSE; Chris@16: } Chris@16: // called for deferred events. Address set in the dispatch_table at init Chris@16: template Chris@16: static HandledEnum defer_transition(library_sm& fsm, int , int , Event const& e) Chris@16: { Chris@16: fsm.defer_event(e); Chris@16: return HANDLED_DEFERRED; Chris@16: } Chris@16: // called for completion events. Default address set in the dispatch_table at init Chris@16: // prevents no-transition detection for completion events Chris@16: template Chris@16: static HandledEnum default_eventless_transition(library_sm&, int, int , Event const&) Chris@16: { Chris@16: return HANDLED_FALSE; Chris@16: } Chris@16: #if defined (__IBMCPP__) || (defined(_MSC_VER) && (_MSC_VER < 1400)) Chris@16: private: Chris@16: #endif Chris@16: // puts a deferred event in the queue Chris@16: void post_deferred_event(deferred_fct& deferred) Chris@16: { Chris@16: m_deferred_events_queue.m_deferred_events_queue.push_back(std::make_pair(deferred,true)); Chris@16: } Chris@16: // removes one event from the message queue and processes it Chris@16: template Chris@16: void process_message_queue(StateType*, Chris@16: typename ::boost::disable_if::type,void >::type* = 0) Chris@16: { Chris@16: if (!m_events_queue.m_events_queue.empty()) Chris@16: { Chris@16: transition_fct to_call = m_events_queue.m_events_queue.front(); Chris@16: m_events_queue.m_events_queue.pop_front(); Chris@16: to_call(); Chris@16: } Chris@16: } Chris@16: template Chris@16: void process_message_queue(StateType*, Chris@16: typename ::boost::enable_if::type,void >::type* = 0) Chris@16: { Chris@16: // nothing to process Chris@16: } Chris@16: // helper function. In cases where the event is wrapped (target is a direct entry states) Chris@16: // we want to send only the real event to on_entry, not the wrapper. Chris@16: template Chris@16: static Chris@16: typename boost::enable_if::type,typename EventType::contained_event const& >::type Chris@16: remove_direct_entry_event_wrapper(EventType const& evt,boost::msm::back::dummy<0> = 0) Chris@16: { Chris@16: return evt.m_event; Chris@16: } Chris@16: template Chris@16: static typename boost::disable_if::type,EventType const& >::type Chris@16: remove_direct_entry_event_wrapper(EventType const& evt,boost::msm::back::dummy<1> = 0) Chris@16: { Chris@16: // identity. No wrapper Chris@16: return evt; Chris@16: } Chris@16: // calls the entry/exit or on_entry/on_exit depending on the state type Chris@16: // (avoids calling virtually) Chris@16: // variant for FSMs Chris@16: template Chris@16: static Chris@16: typename boost::enable_if::type,void >::type Chris@16: execute_entry(StateType& astate,EventType const& evt,FsmType& fsm,boost::msm::back::dummy<0> = 0) Chris@16: { Chris@16: // calls on_entry on the fsm then handles direct entries, fork, entry pseudo state Chris@16: astate.do_entry(evt,fsm); Chris@16: } Chris@16: // variant for states Chris@16: template Chris@16: static Chris@16: typename ::boost::disable_if< Chris@16: typename ::boost::mpl::or_::type, Chris@16: typename is_pseudo_exit::type >::type,void >::type Chris@16: execute_entry(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0) Chris@16: { Chris@16: // simple call to on_entry Chris@16: astate.on_entry(remove_direct_entry_event_wrapper(evt),fsm); Chris@16: } Chris@16: // variant for exit pseudo states Chris@16: template Chris@16: static Chris@16: typename ::boost::enable_if::type,void >::type Chris@16: execute_entry(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0) Chris@16: { Chris@16: // calls on_entry on the state then forward the event to the transition which should be defined inside the Chris@16: // contained fsm Chris@16: astate.on_entry(evt,fsm); Chris@16: astate.forward_event(evt); Chris@16: } Chris@16: template Chris@16: static Chris@16: typename ::boost::enable_if::type,void >::type Chris@16: execute_exit(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<0> = 0) Chris@16: { Chris@16: astate.do_exit(evt,fsm); Chris@16: } Chris@16: template Chris@16: static Chris@16: typename ::boost::disable_if::type,void >::type Chris@16: execute_exit(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0) Chris@16: { Chris@16: // simple call to on_exit Chris@16: astate.on_exit(evt,fsm); Chris@16: } Chris@16: Chris@16: // helper allowing special handling of direct entries / fork Chris@16: template Chris@16: static Chris@16: typename ::boost::disable_if< Chris@16: typename ::boost::mpl::or_::type, Chris@16: ::boost::mpl::is_sequence >::type,void>::type Chris@16: convert_event_and_execute_entry(StateType& astate,EventType const& evt, FsmType& fsm, ::boost::msm::back::dummy<1> = 0) Chris@16: { Chris@16: // if the target is a normal state, do the standard entry handling Chris@16: execute_entry(astate,evt,fsm); Chris@16: } Chris@16: template Chris@16: static Chris@16: typename ::boost::enable_if< Chris@16: typename ::boost::mpl::or_::type, Chris@16: ::boost::mpl::is_sequence >::type,void >::type Chris@16: convert_event_and_execute_entry(StateType& astate,EventType const& evt, FsmType& fsm, ::boost::msm::back::dummy<0> = 0) Chris@16: { Chris@16: // for the direct entry, pack the event in a wrapper so that we handle it differently during fsm entry Chris@16: execute_entry(astate,msm::back::direct_entry_event(evt),fsm); Chris@16: } Chris@16: Chris@16: // creates all the states Chris@16: template Chris@16: void fill_states(ContainingSM* containing_sm=0) Chris@16: { Chris@16: // checks that regions are truly orthogonal Chris@16: FsmCheckPolicy::template check_orthogonality(); Chris@16: // checks that all states are reachable Chris@16: FsmCheckPolicy::template check_unreachable_states(); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(int, max_state = (mpl::size::value)); Chris@16: // allocate the place without reallocation Chris@16: m_visitors.fill_visitors(max_state); Chris@16: ::boost::fusion::for_each(m_substate_list,add_state(this,containing_sm)); Chris@16: Chris@16: } Chris@16: Chris@16: private: Chris@16: template Chris@16: struct msg_queue_helper Chris@16: { Chris@16: public: Chris@16: msg_queue_helper():m_events_queue(){} Chris@16: events_queue_t m_events_queue; Chris@16: }; Chris@16: template Chris@16: struct msg_queue_helper::type >::type> Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: friend struct dispatch_table; Chris@16: Chris@16: // data members Chris@16: int m_states[nr_regions::value]; Chris@16: msg_queue_helper m_events_queue; Chris@16: deferred_msg_queue_helper Chris@16: m_deferred_events_queue; Chris@16: concrete_history m_history; Chris@16: bool m_event_processing; Chris@16: bool m_is_included; Chris@16: visitor_fct_helper m_visitors; Chris@16: substate_list m_substate_list; Chris@16: Chris@16: Chris@16: }; Chris@16: Chris@16: } } }// boost::msm::back Chris@16: #endif //BOOST_MSM_BACK_STATEMACHINE_H Chris@16: