1 // Copyright 2008 Christophe Henry
2 // henry UNDERSCORE christophe AT hotmail DOT com
3 // This is an extended version of the state machine available in the boost::mpl library
4 // Distributed under the same license as the original.
5 // Copyright for the original version:
6 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
7 // under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef BOOST_MSM_BACK_STATEMACHINE_H
12 #define BOOST_MSM_BACK_STATEMACHINE_H
20 #include <boost/detail/no_exceptions_support.hpp>
22 #include <boost/mpl/contains.hpp>
23 #include <boost/mpl/deref.hpp>
24 #include <boost/mpl/assert.hpp>
26 #include <boost/fusion/container/vector/convert.hpp>
27 #include <boost/fusion/include/as_vector.hpp>
28 #include <boost/fusion/include/as_set.hpp>
29 #include <boost/fusion/container/set.hpp>
30 #include <boost/fusion/include/set.hpp>
31 #include <boost/fusion/include/set_fwd.hpp>
32 #include <boost/fusion/include/mpl.hpp>
33 #include <boost/fusion/sequence/intrinsic/at_key.hpp>
34 #include <boost/fusion/include/at_key.hpp>
35 #include <boost/fusion/algorithm/iteration/for_each.hpp>
36 #include <boost/fusion/include/for_each.hpp>
38 #include <boost/assert.hpp>
39 #include <boost/ref.hpp>
40 #include <boost/type_traits.hpp>
41 #include <boost/utility/enable_if.hpp>
42 #include <boost/type_traits/is_convertible.hpp>
44 #include <boost/bind.hpp>
45 #include <boost/function.hpp>
47 #include <boost/any.hpp>
50 #include <boost/serialization/base_object.hpp>
52 #include <boost/parameter.hpp>
54 #include <boost/msm/active_state_switching_policies.hpp>
55 #include <boost/msm/row_tags.hpp>
56 #include <boost/msm/msm_grammar.hpp>
57 #include <boost/msm/back/fold_to_list.hpp>
58 #include <boost/msm/back/metafunctions.hpp>
59 #include <boost/msm/back/history_policies.hpp>
60 #include <boost/msm/back/common_types.hpp>
61 #include <boost/msm/back/args.hpp>
62 #include <boost/msm/back/default_compile_policy.hpp>
63 #include <boost/msm/back/dispatch_table.hpp>
64 #include <boost/msm/back/no_fsm_check.hpp>
65 #include <boost/msm/back/queue_container_deque.hpp>
67 BOOST_MPL_HAS_XXX_TRAIT_DEF(accept_sig)
68 BOOST_MPL_HAS_XXX_TRAIT_DEF(no_automatic_create)
69 BOOST_MPL_HAS_XXX_TRAIT_DEF(non_forwarding_flag)
70 BOOST_MPL_HAS_XXX_TRAIT_DEF(direct_entry)
71 BOOST_MPL_HAS_XXX_TRAIT_DEF(initial_event)
72 BOOST_MPL_HAS_XXX_TRAIT_DEF(final_event)
73 BOOST_MPL_HAS_XXX_TRAIT_DEF(do_serialize)
74 BOOST_MPL_HAS_XXX_TRAIT_DEF(history_policy)
75 BOOST_MPL_HAS_XXX_TRAIT_DEF(fsm_check)
76 BOOST_MPL_HAS_XXX_TRAIT_DEF(compile_policy)
77 BOOST_MPL_HAS_XXX_TRAIT_DEF(queue_container_policy)
78 BOOST_MPL_HAS_XXX_TRAIT_DEF(using_declared_table)
79 BOOST_MPL_HAS_XXX_TRAIT_DEF(event_queue_before_deferred_queue)
81 #ifndef BOOST_MSM_CONSTRUCTOR_ARG_SIZE
82 #define BOOST_MSM_CONSTRUCTOR_ARG_SIZE 5 // default max number of arguments for constructors
85 namespace boost { namespace msm { namespace back
87 // event used internally for wrapping a direct entry
88 template <class StateType,class Event>
89 struct direct_entry_event
91 typedef int direct_entry;
92 typedef StateType active_state;
93 typedef Event contained_event;
95 direct_entry_event(Event const& evt):m_event(evt){}
99 // This declares the statically-initialized dispatch_table instance.
100 template <class Fsm,class Stt, class Event,class CompilePolicy>
101 const boost::msm::back::dispatch_table<Fsm,Stt, Event,CompilePolicy>
102 dispatch_table<Fsm,Stt, Event,CompilePolicy>::instance;
104 BOOST_PARAMETER_TEMPLATE_KEYWORD(front_end)
105 BOOST_PARAMETER_TEMPLATE_KEYWORD(history_policy)
106 BOOST_PARAMETER_TEMPLATE_KEYWORD(compile_policy)
107 BOOST_PARAMETER_TEMPLATE_KEYWORD(fsm_check_policy)
108 BOOST_PARAMETER_TEMPLATE_KEYWORD(queue_container_policy)
110 typedef ::boost::parameter::parameters<
111 ::boost::parameter::required< ::boost::msm::back::tag::front_end >
112 , ::boost::parameter::optional<
113 ::boost::parameter::deduced< ::boost::msm::back::tag::history_policy>, has_history_policy< ::boost::mpl::_ >
115 , ::boost::parameter::optional<
116 ::boost::parameter::deduced< ::boost::msm::back::tag::compile_policy>, has_compile_policy< ::boost::mpl::_ >
118 , ::boost::parameter::optional<
119 ::boost::parameter::deduced< ::boost::msm::back::tag::fsm_check_policy>, has_fsm_check< ::boost::mpl::_ >
121 , ::boost::parameter::optional<
122 ::boost::parameter::deduced< ::boost::msm::back::tag::queue_container_policy>,
123 has_queue_container_policy< ::boost::mpl::_ >
125 > state_machine_signature;
127 // just here to disable use of proto when not needed
128 template <class T, class F,class Enable=void>
129 struct make_euml_terminal;
130 template <class T,class F>
131 struct make_euml_terminal<T,F,typename ::boost::disable_if<has_using_declared_table<F> >::type>
133 template <class T,class F>
134 struct make_euml_terminal<T,F,typename ::boost::enable_if<has_using_declared_table<F> >::type>
135 : public proto::extends<typename proto::terminal< boost::msm::state_tag>::type, T, boost::msm::state_domain>
138 // library-containing class for state machines. Pass the actual FSM class as
139 // the Concrete parameter.
140 // A0=Derived,A1=NoHistory,A2=CompilePolicy,A3=FsmCheckPolicy >
143 , class A1 = parameter::void_
144 , class A2 = parameter::void_
145 , class A3 = parameter::void_
146 , class A4 = parameter::void_
148 class state_machine : //public Derived
149 public ::boost::parameter::binding<
150 typename state_machine_signature::bind<A0,A1,A2,A3,A4>::type, ::boost::msm::back::tag::front_end
152 , public make_euml_terminal<state_machine<A0,A1,A2,A3,A4>,
153 typename ::boost::parameter::binding<
154 typename state_machine_signature::bind<A0,A1,A2,A3,A4>::type, ::boost::msm::back::tag::front_end
159 // Create ArgumentPack
161 state_machine_signature::bind<A0,A1,A2,A3,A4>::type
164 // Extract first logical parameter.
165 typedef typename ::boost::parameter::binding<
166 state_machine_args, ::boost::msm::back::tag::front_end>::type Derived;
168 typedef typename ::boost::parameter::binding<
169 state_machine_args, ::boost::msm::back::tag::history_policy, NoHistory >::type HistoryPolicy;
171 typedef typename ::boost::parameter::binding<
172 state_machine_args, ::boost::msm::back::tag::compile_policy, favor_runtime_speed >::type CompilePolicy;
174 typedef typename ::boost::parameter::binding<
175 state_machine_args, ::boost::msm::back::tag::fsm_check_policy, no_fsm_check >::type FsmCheckPolicy;
177 typedef typename ::boost::parameter::binding<
178 state_machine_args, ::boost::msm::back::tag::queue_container_policy,
179 queue_container_deque >::type QueueContainerPolicy;
183 typedef boost::msm::back::state_machine<
184 A0,A1,A2,A3,A4> library_sm;
186 typedef ::boost::function<
187 execute_return ()> transition_fct;
188 typedef ::boost::function<
189 execute_return () > deferred_fct;
190 typedef typename QueueContainerPolicy::
192 std::pair<deferred_fct,char> >::type deferred_events_queue_t;
193 typedef typename QueueContainerPolicy::
194 template In<transition_fct>::type events_queue_t;
196 typedef typename boost::mpl::eval_if<
197 typename is_active_state_switch_policy<Derived>::type,
198 get_active_state_switch_policy<Derived>,
200 ::boost::mpl::identity<active_state_switch_after_entry>
201 >::type active_state_switching;
203 typedef bool (*flag_handler)(library_sm const&);
205 // all state machines are friend with each other to allow embedding any of them in another fsm
206 template <class ,class , class, class, class
207 > friend class boost::msm::back::state_machine;
209 // helper to add, if needed, visitors to all states
210 // version without visitors
211 template <class StateType,class Enable=void>
212 struct visitor_fct_helper
215 visitor_fct_helper(){}
216 void fill_visitors(int)
223 template <class VISITOR>
224 void execute(int,VISITOR)
228 // version with visitors
229 template <class StateType>
230 struct visitor_fct_helper<StateType,typename ::boost::enable_if<has_accept_sig<StateType> >::type>
233 visitor_fct_helper():m_state_visitors(){}
234 void fill_visitors(int number_of_states)
236 m_state_visitors.resize(number_of_states);
239 void insert(int index,FCT fct)
241 m_state_visitors[index]=fct;
243 void execute(int index)
245 m_state_visitors[index]();
248 #define MSM_VISITOR_HELPER_EXECUTE_SUB(z, n, unused) ARG ## n vis ## n
249 #define MSM_VISITOR_HELPER_EXECUTE(z, n, unused) \
250 template <BOOST_PP_ENUM_PARAMS(n, class ARG)> \
251 void execute(int index BOOST_PP_COMMA_IF(n) \
252 BOOST_PP_ENUM(n, MSM_VISITOR_HELPER_EXECUTE_SUB, ~ ) ) \
254 m_state_visitors[index](BOOST_PP_ENUM_PARAMS(n,vis)); \
256 BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_VISITOR_HELPER_EXECUTE, ~)
257 #undef MSM_VISITOR_HELPER_EXECUTE
258 #undef MSM_VISITOR_HELPER_EXECUTE_SUB
260 typedef typename StateType::accept_sig::type visitor_fct;
261 typedef std::vector<visitor_fct> visitors;
263 visitors m_state_visitors;
266 template <class StateType,class Enable=int>
267 struct deferred_msg_queue_helper
271 template <class StateType>
272 struct deferred_msg_queue_helper<StateType,
273 typename ::boost::enable_if<
274 typename ::boost::msm::back::has_fsm_deferred_events<StateType>::type,int >::type>
277 deferred_msg_queue_helper():m_deferred_events_queue(),m_cur_seq(0){}
280 m_deferred_events_queue.clear();
282 deferred_events_queue_t m_deferred_events_queue;
288 typedef int composite_tag;
290 // in case someone needs to know
291 typedef HistoryPolicy history_policy;
293 struct InitEvent { };
294 struct ExitEvent { };
298 typedef std::logical_and<bool> type;
302 typedef std::logical_or<bool> type;
304 typedef typename Derived::BaseAllStates BaseState;
305 typedef Derived ConcreteSM;
307 // if the front-end fsm provides an initial_event typedef, replace InitEvent by this one
308 typedef typename ::boost::mpl::eval_if<
309 typename has_initial_event<Derived>::type,
310 get_initial_event<Derived>,
311 ::boost::mpl::identity<InitEvent>
312 >::type fsm_initial_event;
314 // if the front-end fsm provides an exit_event typedef, replace ExitEvent by this one
315 typedef typename ::boost::mpl::eval_if<
316 typename has_final_event<Derived>::type,
317 get_final_event<Derived>,
318 ::boost::mpl::identity<ExitEvent>
319 >::type fsm_final_event;
321 template <class ExitPoint>
322 struct exit_pt : public ExitPoint
325 typedef ExitPoint wrapped_exit;
326 typedef int pseudo_exit;
327 typedef library_sm owner;
328 typedef int no_automatic_create;
330 ExitPoint::event Event;
331 typedef ::boost::function<execute_return (Event const&)>
334 // forward event to the higher-level FSM
335 template <class ForwardEvent>
336 void forward_event(ForwardEvent const& incomingEvent)
338 // use helper to forward or not
339 ForwardHelper< ::boost::is_convertible<ForwardEvent,Event>::value>::helper(incomingEvent,m_forward);
341 void set_forward_fct(::boost::function<execute_return (Event const&)> fct)
345 exit_pt():m_forward(){}
346 // by assignments, we keep our forwarding functor unchanged as our containing SM did not change
348 exit_pt(RHS&):m_forward(){}
349 exit_pt<ExitPoint>& operator= (const exit_pt<ExitPoint>& )
354 forwarding_function m_forward;
356 // using partial specialization instead of enable_if because of VC8 bug
357 template <bool OwnEvent, int Dummy=0>
360 template <class ForwardEvent>
361 static void helper(ForwardEvent const& ,forwarding_function& )
363 // Not our event, assert
368 struct ForwardHelper<true,Dummy>
370 template <class ForwardEvent>
371 static void helper(ForwardEvent const& incomingEvent,forwarding_function& forward_fct)
373 // call if handler set, if not, this state is simply a terminate state
375 forward_fct(incomingEvent);
380 template <class EntryPoint>
381 struct entry_pt : public EntryPoint
384 typedef EntryPoint wrapped_entry;
385 typedef int pseudo_entry;
386 typedef library_sm owner;
387 typedef int no_automatic_create;
389 template <class EntryPoint>
390 struct direct : public EntryPoint
393 typedef EntryPoint wrapped_entry;
394 typedef int explicit_entry_state;
395 typedef library_sm owner;
396 typedef int no_automatic_create;
398 typedef typename get_number_of_regions<typename Derived::initial_state>::type nr_regions;
399 // Template used to form rows in the transition table
405 //typedef typename ROW::Source T1;
406 typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
407 typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
408 typedef typename ROW::Evt transition_event;
409 // if the source is an exit pseudo state, then
410 // current_state_type becomes the result of get_owner
411 // meaning the containing SM from which the exit occurs
412 typedef typename ::boost::mpl::eval_if<
413 typename has_pseudo_exit<T1>::type,
414 get_owner<T1,library_sm>,
415 ::boost::mpl::identity<typename ROW::Source> >::type current_state_type;
417 // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry
418 // else if Target is an explicit_entry, next_state_type becomes the result of get_owner
419 // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself
420 typedef typename ::boost::mpl::eval_if<
421 typename ::boost::mpl::is_sequence<T2>::type,
422 get_fork_owner<T2,library_sm>,
423 ::boost::mpl::eval_if<
424 typename has_no_automatic_create<T2>::type,
425 get_owner<T2,library_sm>,
426 ::boost::mpl::identity<T2> >
427 >::type next_state_type;
429 // if a guard condition is here, call it to check that the event is accepted
430 static bool check_guard(library_sm& fsm,transition_event const& evt)
432 if ( ROW::guard_call(fsm,evt,
433 ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
434 ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
435 fsm.m_substate_list ) )
439 // Take the transition action and return the next state.
440 static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt)
443 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
444 BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
445 BOOST_ASSERT(state == (current_state));
446 // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
447 if (has_pseudo_exit<T1>::type::value &&
448 !is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
450 return HANDLED_FALSE;
452 if (!check_guard(fsm,evt))
454 // guard rejected the event, we stay in the current one
455 return HANDLED_GUARD_REJECT;
457 fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state);
459 // the guard condition has already been checked
460 execute_exit<current_state_type>
461 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),evt,fsm);
462 fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state);
464 // then call the action method
465 HandledEnum res = ROW::action_call(fsm,evt,
466 ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
467 ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
468 fsm.m_substate_list);
469 fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state);
471 // and finally the entry method of the new current state
472 convert_event_and_execute_entry<next_state_type,T2>
473 (::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),evt,fsm);
474 fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state);
479 // row having only a guard condition
485 //typedef typename ROW::Source T1;
486 typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
487 typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
488 typedef typename ROW::Evt transition_event;
489 // if the source is an exit pseudo state, then
490 // current_state_type becomes the result of get_owner
491 // meaning the containing SM from which the exit occurs
492 typedef typename ::boost::mpl::eval_if<
493 typename has_pseudo_exit<T1>::type,
494 get_owner<T1,library_sm>,
495 ::boost::mpl::identity<typename ROW::Source> >::type current_state_type;
497 // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry
498 // else if Target is an explicit_entry, next_state_type becomes the result of get_owner
499 // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself
500 typedef typename ::boost::mpl::eval_if<
501 typename ::boost::mpl::is_sequence<T2>::type,
502 get_fork_owner<T2,library_sm>,
503 ::boost::mpl::eval_if<
504 typename has_no_automatic_create<T2>::type,
505 get_owner<T2,library_sm>,
506 ::boost::mpl::identity<T2> >
507 >::type next_state_type;
509 // if a guard condition is defined, call it to check that the event is accepted
510 static bool check_guard(library_sm& fsm,transition_event const& evt)
512 if ( ROW::guard_call(fsm,evt,
513 ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
514 ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
515 fsm.m_substate_list ))
519 // Take the transition action and return the next state.
520 static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt)
522 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
523 BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
524 BOOST_ASSERT(state == (current_state));
525 // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
526 if (has_pseudo_exit<T1>::type::value &&
527 !is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
529 return HANDLED_FALSE;
531 if (!check_guard(fsm,evt))
533 // guard rejected the event, we stay in the current one
534 return HANDLED_GUARD_REJECT;
536 fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state);
538 // the guard condition has already been checked
539 execute_exit<current_state_type>
540 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),evt,fsm);
541 fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state);
542 fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state);
544 // and finally the entry method of the new current state
545 convert_event_and_execute_entry<next_state_type,T2>
546 (::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),evt,fsm);
547 fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state);
552 // row having only an action method
558 //typedef typename ROW::Source T1;
559 typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
560 typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
561 typedef typename ROW::Evt transition_event;
562 // if the source is an exit pseudo state, then
563 // current_state_type becomes the result of get_owner
564 // meaning the containing SM from which the exit occurs
565 typedef typename ::boost::mpl::eval_if<
566 typename has_pseudo_exit<T1>::type,
567 get_owner<T1,library_sm>,
568 ::boost::mpl::identity<typename ROW::Source> >::type current_state_type;
570 // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry
571 // else if Target is an explicit_entry, next_state_type becomes the result of get_owner
572 // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself
573 typedef typename ::boost::mpl::eval_if<
574 typename ::boost::mpl::is_sequence<T2>::type,
575 get_fork_owner<T2,library_sm>,
576 ::boost::mpl::eval_if<
577 typename has_no_automatic_create<T2>::type,
578 get_owner<T2,library_sm>,
579 ::boost::mpl::identity<T2> >
580 >::type next_state_type;
582 // Take the transition action and return the next state.
583 static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt)
585 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
586 BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
587 BOOST_ASSERT(state == (current_state));
589 // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
590 if (has_pseudo_exit<T1>::type::value &&
591 !is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
593 return HANDLED_FALSE;
595 fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state);
597 // no need to check the guard condition
598 // first call the exit method of the current state
599 execute_exit<current_state_type>
600 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),evt,fsm);
601 fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state);
603 // then call the action method
604 HandledEnum res = ROW::action_call(fsm,evt,
605 ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
606 ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
607 fsm.m_substate_list);
608 fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state);
610 // and finally the entry method of the new current state
611 convert_event_and_execute_entry<next_state_type,T2>
612 (::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),evt,fsm);
613 fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state);
618 // row having no guard condition or action, simply transitions
624 //typedef typename ROW::Source T1;
625 typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
626 typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
627 typedef typename ROW::Evt transition_event;
628 // if the source is an exit pseudo state, then
629 // current_state_type becomes the result of get_owner
630 // meaning the containing SM from which the exit occurs
631 typedef typename ::boost::mpl::eval_if<
632 typename has_pseudo_exit<T1>::type,
633 get_owner<T1,library_sm>,
634 ::boost::mpl::identity<typename ROW::Source> >::type current_state_type;
636 // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry
637 // else if Target is an explicit_entry, next_state_type becomes the result of get_owner
638 // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself
639 typedef typename ::boost::mpl::eval_if<
640 typename ::boost::mpl::is_sequence<T2>::type,
641 get_fork_owner<T2,library_sm>,
642 ::boost::mpl::eval_if<
643 typename has_no_automatic_create<T2>::type,
644 get_owner<T2,library_sm>,
645 ::boost::mpl::identity<T2> >
646 >::type next_state_type;
648 // Take the transition action and return the next state.
649 static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt)
651 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
652 BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
653 BOOST_ASSERT(state == (current_state));
655 // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
656 if (has_pseudo_exit<T1>::type::value &&
657 !is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
659 return HANDLED_FALSE;
661 fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state);
663 // first call the exit method of the current state
664 execute_exit<current_state_type>
665 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),evt,fsm);
666 fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state);
667 fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state);
670 // and finally the entry method of the new current state
671 convert_event_and_execute_entry<next_state_type,T2>
672 (::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),evt,fsm);
673 fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state);
677 // "i" rows are rows for internal transitions
683 typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
684 typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
685 typedef typename ROW::Evt transition_event;
686 typedef typename ROW::Source current_state_type;
687 typedef T2 next_state_type;
689 // if a guard condition is here, call it to check that the event is accepted
690 static bool check_guard(library_sm& fsm,transition_event const& evt)
692 if ( ROW::guard_call(fsm,evt,
693 ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
694 ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
695 fsm.m_substate_list))
699 // Take the transition action and return the next state.
700 static HandledEnum execute(library_sm& fsm, int , int state, transition_event const& evt)
703 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
704 BOOST_ASSERT(state == (current_state));
705 if (!check_guard(fsm,evt))
707 // guard rejected the event, we stay in the current one
708 return HANDLED_GUARD_REJECT;
711 // call the action method
712 HandledEnum res = ROW::action_call(fsm,evt,
713 ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
714 ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
715 fsm.m_substate_list);
720 // row having only a guard condition
726 typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
727 typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
728 typedef typename ROW::Evt transition_event;
729 typedef typename ROW::Source current_state_type;
730 typedef T2 next_state_type;
732 // if a guard condition is defined, call it to check that the event is accepted
733 static bool check_guard(library_sm& fsm,transition_event const& evt)
735 if ( ROW::guard_call(fsm,evt,
736 ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
737 ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
738 fsm.m_substate_list) )
742 // Take the transition action and return the next state.
743 static HandledEnum execute(library_sm& fsm, int , int state, transition_event const& evt)
745 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
746 BOOST_ASSERT(state == (current_state));
747 if (!check_guard(fsm,evt))
749 // guard rejected the event, we stay in the current one
750 return HANDLED_GUARD_REJECT;
756 // row having only an action method
762 typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
763 typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
765 typedef typename ROW::Evt transition_event;
766 typedef typename ROW::Source current_state_type;
767 typedef T2 next_state_type;
769 // Take the transition action and return the next state.
770 static HandledEnum execute(library_sm& fsm, int , int state, transition_event const& evt)
772 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
773 BOOST_ASSERT(state == (current_state));
775 // call the action method
776 HandledEnum res = ROW::action_call(fsm,evt,
777 ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
778 ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
779 fsm.m_substate_list);
784 // row simply ignoring the event
790 typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
791 typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
792 typedef typename ROW::Evt transition_event;
793 typedef typename ROW::Source current_state_type;
794 typedef T2 next_state_type;
796 // Take the transition action and return the next state.
797 static HandledEnum execute(library_sm& , int , int state, transition_event const& )
799 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
800 BOOST_ASSERT(state == (current_state));
804 // transitions internal to this state machine (no substate involved)
811 typedef StateType current_state_type;
812 typedef StateType next_state_type;
813 typedef typename ROW::Evt transition_event;
815 // if a guard condition is here, call it to check that the event is accepted
816 static bool check_guard(library_sm& fsm,transition_event const& evt)
818 if ( ROW::guard_call(fsm,evt,
819 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
820 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
821 fsm.m_substate_list) )
825 // Take the transition action and return the next state.
826 static HandledEnum execute(library_sm& fsm, int , int , transition_event const& evt)
828 if (!check_guard(fsm,evt))
830 // guard rejected the event, we stay in the current one
831 return HANDLED_GUARD_REJECT;
834 // then call the action method
835 HandledEnum res = ROW::action_call(fsm,evt,
836 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
837 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
838 fsm.m_substate_list);
845 struct internal_ <ROW,library_sm>
847 typedef library_sm current_state_type;
848 typedef library_sm next_state_type;
849 typedef typename ROW::Evt transition_event;
851 // if a guard condition is here, call it to check that the event is accepted
852 static bool check_guard(library_sm& fsm,transition_event const& evt)
854 if ( ROW::guard_call(fsm,evt,
857 fsm.m_substate_list) )
861 // Take the transition action and return the next state.
862 static HandledEnum execute(library_sm& fsm, int , int , transition_event const& evt)
864 if (!check_guard(fsm,evt))
866 // guard rejected the event, we stay in the current one
867 return HANDLED_GUARD_REJECT;
870 // then call the action method
871 HandledEnum res = ROW::action_call(fsm,evt,
874 fsm.m_substate_list);
885 typedef StateType current_state_type;
886 typedef StateType next_state_type;
887 typedef typename ROW::Evt transition_event;
889 // Take the transition action and return the next state.
890 static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt)
892 // then call the action method
893 HandledEnum res = ROW::action_call(fsm,evt,
894 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
895 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
896 fsm.m_substate_list);
903 struct a_internal_ <ROW,library_sm>
905 typedef library_sm current_state_type;
906 typedef library_sm next_state_type;
907 typedef typename ROW::Evt transition_event;
909 // Take the transition action and return the next state.
910 static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt)
912 // then call the action method
913 HandledEnum res = ROW::action_call(fsm,evt,
916 fsm.m_substate_list);
926 typedef StateType current_state_type;
927 typedef StateType next_state_type;
928 typedef typename ROW::Evt transition_event;
930 // if a guard condition is here, call it to check that the event is accepted
931 static bool check_guard(library_sm& fsm,transition_event const& evt)
933 if ( ROW::guard_call(fsm,evt,
934 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
935 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
936 fsm.m_substate_list) )
940 // Take the transition action and return the next state.
941 static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt)
943 if (!check_guard(fsm,evt))
945 // guard rejected the event, we stay in the current one
946 return HANDLED_GUARD_REJECT;
954 struct g_internal_ <ROW,library_sm>
956 typedef library_sm current_state_type;
957 typedef library_sm next_state_type;
958 typedef typename ROW::Evt transition_event;
960 // if a guard condition is here, call it to check that the event is accepted
961 static bool check_guard(library_sm& fsm,transition_event const& evt)
963 if ( ROW::guard_call(fsm,evt,
966 fsm.m_substate_list) )
970 // Take the transition action and return the next state.
971 static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt)
973 if (!check_guard(fsm,evt))
975 // guard rejected the event, we stay in the current one
976 return HANDLED_GUARD_REJECT;
987 typedef StateType current_state_type;
988 typedef StateType next_state_type;
989 typedef typename ROW::Evt transition_event;
990 static HandledEnum execute(library_sm& , int , int , transition_event const& )
998 struct _internal_ <ROW,library_sm>
1000 typedef library_sm current_state_type;
1001 typedef library_sm next_state_type;
1002 typedef typename ROW::Evt transition_event;
1003 static HandledEnum execute(library_sm& , int , int , transition_event const& )
1005 return HANDLED_TRUE;
1008 // Template used to form forwarding rows in the transition table for every row of a composite SM
1015 typedef T1 current_state_type;
1016 typedef T1 next_state_type;
1017 typedef Evt transition_event;
1018 // tag to find out if a row is a forwarding row
1019 typedef int is_frow;
1021 // Take the transition action and return the next state.
1022 static HandledEnum execute(library_sm& fsm, int region_index, int , transition_event const& evt)
1024 // false as second parameter because this event is forwarded from outer fsm
1025 execute_return res =
1026 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list)).process_event_internal(evt);
1027 fsm.m_states[region_index]=get_state_id<stt,T1>::type::value;
1030 // helper metafunctions used by dispatch table and give the frow a new event
1031 // (used to avoid double entries in a table because of base events)
1032 template <class NewEvent>
1033 struct replace_event
1035 typedef frow<T1,NewEvent> type;
1039 template <class Tag, class Transition,class StateType>
1040 struct create_backend_stt
1043 template <class Transition,class StateType>
1044 struct create_backend_stt<g_row_tag,Transition,StateType>
1046 typedef g_row_<Transition> type;
1048 template <class Transition,class StateType>
1049 struct create_backend_stt<a_row_tag,Transition,StateType>
1051 typedef a_row_<Transition> type;
1053 template <class Transition,class StateType>
1054 struct create_backend_stt<_row_tag,Transition,StateType>
1056 typedef _row_<Transition> type;
1058 template <class Transition,class StateType>
1059 struct create_backend_stt<row_tag,Transition,StateType>
1061 typedef row_<Transition> type;
1063 // internal transitions
1064 template <class Transition,class StateType>
1065 struct create_backend_stt<g_irow_tag,Transition,StateType>
1067 typedef g_irow_<Transition> type;
1069 template <class Transition,class StateType>
1070 struct create_backend_stt<a_irow_tag,Transition,StateType>
1072 typedef a_irow_<Transition> type;
1074 template <class Transition,class StateType>
1075 struct create_backend_stt<irow_tag,Transition,StateType>
1077 typedef irow_<Transition> type;
1079 template <class Transition,class StateType>
1080 struct create_backend_stt<_irow_tag,Transition,StateType>
1082 typedef _irow_<Transition> type;
1084 template <class Transition,class StateType>
1085 struct create_backend_stt<sm_a_i_row_tag,Transition,StateType>
1087 typedef a_internal_<Transition,StateType> type;
1089 template <class Transition,class StateType>
1090 struct create_backend_stt<sm_g_i_row_tag,Transition,StateType>
1092 typedef g_internal_<Transition,StateType> type;
1094 template <class Transition,class StateType>
1095 struct create_backend_stt<sm_i_row_tag,Transition,StateType>
1097 typedef internal_<Transition,StateType> type;
1099 template <class Transition,class StateType>
1100 struct create_backend_stt<sm__i_row_tag,Transition,StateType>
1102 typedef _internal_<Transition,StateType> type;
1104 template <class Transition,class StateType=void>
1107 typedef typename create_backend_stt<typename Transition::row_type_tag,Transition,StateType>::type type;
1110 // add to the stt the initial states which could be missing (if not being involved in a transition)
1111 template <class BaseType, class stt_simulated = typename BaseType::transition_table>
1112 struct create_real_stt
1114 //typedef typename BaseType::transition_table stt_simulated;
1115 typedef typename ::boost::mpl::fold<
1116 stt_simulated,mpl::vector0<>,
1117 ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
1118 make_row_tag< ::boost::mpl::placeholders::_2 , BaseType > >
1122 template <class Table,class Intermediate,class StateType>
1123 struct add_forwarding_row_helper
1125 typedef typename generate_event_set<Table>::type all_events;
1126 typedef typename ::boost::mpl::fold<
1127 all_events, Intermediate,
1128 ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
1129 frow<StateType, ::boost::mpl::placeholders::_2> > >::type type;
1131 // gets the transition table from a composite and make from it a forwarding row
1132 template <class StateType,class IsComposite>
1133 struct get_internal_transition_table
1135 // first get the table of a composite
1136 typedef typename recursive_get_transition_table<StateType>::type original_table;
1138 // we now look for the events the composite has in its internal transitions
1139 // the internal ones are searched recursively in sub-sub... states
1140 // we go recursively because our states can also have internal tables or substates etc.
1141 typedef typename recursive_get_internal_transition_table<StateType, ::boost::mpl::true_>::type recursive_istt;
1142 typedef typename ::boost::mpl::fold<
1143 recursive_istt,::boost::mpl::vector0<>,
1144 ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
1145 make_row_tag< ::boost::mpl::placeholders::_2 , StateType> >
1146 >::type recursive_istt_with_tag;
1148 typedef typename ::boost::mpl::insert_range< original_table, typename ::boost::mpl::end<original_table>::type,
1149 recursive_istt_with_tag>::type table_with_all_events;
1151 // and add for every event a forwarding row
1152 typedef typename ::boost::mpl::eval_if<
1153 typename CompilePolicy::add_forwarding_rows,
1154 add_forwarding_row_helper<table_with_all_events,::boost::mpl::vector0<>,StateType>,
1155 ::boost::mpl::identity< ::boost::mpl::vector0<> >
1158 template <class StateType>
1159 struct get_internal_transition_table<StateType, ::boost::mpl::false_ >
1161 typedef typename create_real_stt<StateType, typename StateType::internal_transition_table >::type type;
1163 // typedefs used internally
1164 typedef typename create_real_stt<Derived>::type real_transition_table;
1165 typedef typename create_stt<library_sm>::type stt;
1166 typedef typename get_initial_states<typename Derived::initial_state>::type initial_states;
1167 typedef typename generate_state_set<stt>::type state_list;
1168 typedef typename HistoryPolicy::template apply<nr_regions::value>::type concrete_history;
1170 typedef typename ::boost::fusion::result_of::as_set<state_list>::type substate_list;
1171 typedef typename ::boost::msm::back::generate_event_set<
1172 typename create_real_stt<library_sm, typename library_sm::internal_transition_table >::type
1173 >::type processable_events_internal_table;
1175 // extends the transition table with rows from composite states
1176 template <class Composite>
1179 // add the init states
1180 //typedef typename create_stt<Composite>::type stt;
1181 typedef typename Composite::stt Stt;
1183 // add the internal events defined in the internal_transition_table
1184 // Note: these are added first because they must have a lesser prio
1185 // than the deeper transitions in the sub regions
1186 // table made of a stt + internal transitions of composite
1187 typedef typename ::boost::mpl::fold<
1188 typename Composite::internal_transition_table,::boost::mpl::vector0<>,
1189 ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
1190 make_row_tag< ::boost::mpl::placeholders::_2 , Composite> >
1191 >::type internal_stt;
1193 typedef typename ::boost::mpl::insert_range<
1195 typename ::boost::mpl::end<Stt>::type,
1197 //typename get_internal_transition_table<Composite, ::boost::mpl::true_ >::type
1198 >::type stt_plus_internal;
1200 // for every state, add its transition table (if any)
1201 // transformed as frow
1202 typedef typename ::boost::mpl::fold<state_list,stt_plus_internal,
1203 ::boost::mpl::insert_range<
1204 ::boost::mpl::placeholders::_1,
1205 ::boost::mpl::end< ::boost::mpl::placeholders::_1>,
1206 get_internal_transition_table<
1207 ::boost::mpl::placeholders::_2,
1208 is_composite_state< ::boost::mpl::placeholders::_2> > >
1211 // extend the table with tables from composite states
1212 typedef typename extend_table<library_sm>::type complete_table;
1213 // build a sequence of regions
1214 typedef typename get_regions_as_sequence<typename Derived::initial_state>::type seq_initial_states;
1217 // start the state machine (calls entry of the initial state)
1220 // reinitialize our list of currently active states with the ones defined in Derived::initial_state
1221 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1222 (init_states(m_states));
1223 // call on_entry on this SM
1224 (static_cast<Derived*>(this))->on_entry(fsm_initial_event(),*this);
1225 ::boost::mpl::for_each<initial_states, boost::msm::wrap<mpl::placeholders::_1> >
1226 (call_init<fsm_initial_event>(fsm_initial_event(),this));
1227 // give a chance to handle an anonymous (eventless) transition
1228 handle_eventless_transitions_helper<library_sm> eventless_helper(this,true);
1229 eventless_helper.process_completion_event();
1232 // start the state machine (calls entry of the initial state passing incomingEvent to on_entry's)
1233 template <class Event>
1234 void start(Event const& incomingEvent)
1236 // reinitialize our list of currently active states with the ones defined in Derived::initial_state
1237 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1238 (init_states(m_states));
1239 // call on_entry on this SM
1240 (static_cast<Derived*>(this))->on_entry(incomingEvent,*this);
1241 ::boost::mpl::for_each<initial_states, boost::msm::wrap<mpl::placeholders::_1> >
1242 (call_init<Event>(incomingEvent,this));
1243 // give a chance to handle an anonymous (eventless) transition
1244 handle_eventless_transitions_helper<library_sm> eventless_helper(this,true);
1245 eventless_helper.process_completion_event();
1248 // stop the state machine (calls exit of the current state)
1251 do_exit(fsm_final_event(),*this);
1254 // stop the state machine (calls exit of the current state passing finalEvent to on_exit's)
1255 template <class Event>
1256 void stop(Event const& finalEvent)
1258 do_exit(finalEvent,*this);
1261 // Main function used by clients of the derived FSM to make transitions.
1262 template<class Event>
1263 execute_return process_event(Event const& evt)
1265 return process_event_internal(evt, EVENT_SOURCE_DIRECT);
1268 template <class EventType>
1269 void enqueue_event_helper(EventType const& evt, ::boost::mpl::false_ const &)
1271 execute_return (library_sm::*pf) (EventType const&, EventSource) =
1272 &library_sm::process_event_internal;
1274 m_events_queue.m_events_queue.push_back(
1277 static_cast<EventSource>(EVENT_SOURCE_MSG_QUEUE)));
1279 template <class EventType>
1280 void enqueue_event_helper(EventType const& , ::boost::mpl::true_ const &)
1285 void execute_queued_events_helper(::boost::mpl::false_ const &)
1287 while(!m_events_queue.m_events_queue.empty())
1289 transition_fct to_call = m_events_queue.m_events_queue.front();
1290 m_events_queue.m_events_queue.pop_front();
1294 void execute_queued_events_helper(::boost::mpl::true_ const &)
1296 // no queue required
1298 void execute_single_queued_event_helper(::boost::mpl::false_ const &)
1300 transition_fct to_call = m_events_queue.m_events_queue.front();
1301 m_events_queue.m_events_queue.pop_front();
1304 void execute_single_queued_event_helper(::boost::mpl::true_ const &)
1306 // no queue required
1308 // enqueues an event in the message queue
1309 // call execute_queued_events to process all queued events.
1310 // Be careful if you do this during event processing, the event will be processed immediately
1311 // and not kept in the queue
1312 template <class EventType>
1313 void enqueue_event(EventType const& evt)
1315 enqueue_event_helper<EventType>(evt, typename is_no_message_queue<library_sm>::type());
1318 // empty the queue and process events
1319 void execute_queued_events()
1321 execute_queued_events_helper(typename is_no_message_queue<library_sm>::type());
1323 void execute_single_queued_event()
1325 execute_single_queued_event_helper(typename is_no_message_queue<library_sm>::type());
1327 typename events_queue_t::size_type get_message_queue_size() const
1329 return m_events_queue.m_events_queue.size();
1332 events_queue_t& get_message_queue()
1334 return m_events_queue.m_events_queue;
1337 const events_queue_t& get_message_queue() const
1339 return m_events_queue.m_events_queue;
1342 void clear_deferred_queue()
1344 m_deferred_events_queue.clear();
1347 deferred_events_queue_t& get_deferred_queue()
1349 return m_deferred_events_queue.m_deferred_events_queue;
1352 const deferred_events_queue_t& get_deferred_queue() const
1354 return m_deferred_events_queue.m_deferred_events_queue;
1357 // Getter that returns the current state of the FSM
1358 const int* current_state() const
1360 return this->m_states;
1363 template <class Archive>
1364 struct serialize_state
1366 serialize_state(Archive& ar):ar_(ar){}
1368 template<typename T>
1369 typename ::boost::enable_if<
1370 typename ::boost::mpl::or_<
1371 typename has_do_serialize<T>::type,
1372 typename is_composite_state<T>::type
1376 operator()(T& t) const
1380 template<typename T>
1381 typename ::boost::disable_if<
1382 typename ::boost::mpl::or_<
1383 typename has_do_serialize<T>::type,
1384 typename is_composite_state<T>::type
1388 operator()(T&) const
1390 // no state to serialize
1395 template<class Archive>
1396 void serialize(Archive & ar, const unsigned int)
1398 // invoke serialization of the base class
1399 (serialize_state<Archive>(ar))(boost::serialization::base_object<Derived>(*this));
1400 // now our attributes
1402 // queues cannot be serialized => skip
1404 ar & m_event_processing;
1406 // visitors cannot be serialized => skip
1407 ::boost::fusion::for_each(m_substate_list, serialize_state<Archive>(ar));
1410 // linearly search for the state with the given id
1411 struct get_state_id_helper
1413 get_state_id_helper(int id,const BaseState** res,const library_sm* self_):
1414 result_state(res),searched_id(id),self(self_) {}
1416 template <class StateType>
1417 void operator()(boost::msm::wrap<StateType> const&)
1419 // look for the state id until found
1420 BOOST_STATIC_CONSTANT(int, id = (get_state_id<stt,StateType>::value));
1421 if (!*result_state && (id == searched_id))
1423 *result_state = &::boost::fusion::at_key<StateType>(self->m_substate_list);
1426 const BaseState** result_state;
1428 const library_sm* self;
1430 // return the state whose id is passed or 0 if not found
1431 // caution if you need this, you probably need polymorphic states
1432 // complexity: O(number of states)
1433 BaseState* get_state_by_id(int id)
1435 const BaseState* result_state=0;
1436 ::boost::mpl::for_each<state_list,
1437 ::boost::msm::wrap< ::boost::mpl::placeholders::_1> > (get_state_id_helper(id,&result_state,this));
1438 return const_cast<BaseState*>(result_state);
1440 const BaseState* get_state_by_id(int id) const
1442 const BaseState* result_state=0;
1443 ::boost::mpl::for_each<state_list,
1444 ::boost::msm::wrap< ::boost::mpl::placeholders::_1> > (get_state_id_helper(id,&result_state,this));
1445 return result_state;
1447 // true if the sm is used in another sm
1448 bool is_contained() const
1450 return m_is_included;
1452 // get the history policy class
1453 concrete_history& get_history()
1457 concrete_history const& get_history() const
1461 // get a state (const version)
1463 template <class State>
1464 typename ::boost::enable_if<typename ::boost::is_pointer<State>::type,State >::type
1465 get_state(::boost::msm::back::dummy<0> = 0) const
1467 return const_cast<State >
1469 (::boost::fusion::at_key<
1470 typename ::boost::remove_const<typename ::boost::remove_pointer<State>::type>::type>(m_substate_list)));
1473 template <class State>
1474 typename ::boost::enable_if<typename ::boost::is_reference<State>::type,State >::type
1475 get_state(::boost::msm::back::dummy<1> = 0) const
1477 return const_cast<State >
1478 ( ::boost::fusion::at_key<
1479 typename ::boost::remove_const<typename ::boost::remove_reference<State>::type>::type>(m_substate_list) );
1481 // get a state (non const version)
1483 template <class State>
1484 typename ::boost::enable_if<typename ::boost::is_pointer<State>::type,State >::type
1485 get_state(::boost::msm::back::dummy<0> = 0)
1487 return &(static_cast<typename boost::add_reference<typename ::boost::remove_pointer<State>::type>::type >
1488 (::boost::fusion::at_key<typename ::boost::remove_pointer<State>::type>(m_substate_list)));
1491 template <class State>
1492 typename ::boost::enable_if<typename ::boost::is_reference<State>::type,State >::type
1493 get_state(::boost::msm::back::dummy<1> = 0)
1495 return ::boost::fusion::at_key<typename ::boost::remove_reference<State>::type>(m_substate_list);
1497 // checks if a flag is active using the BinaryOp as folding function
1498 template <class Flag,class BinaryOp>
1499 bool is_flag_active() const
1501 flag_handler* flags_entries = get_entries_for_flag<Flag>();
1502 bool res = (*flags_entries[ m_states[0] ])(*this);
1503 for (int i = 1; i < nr_regions::value ; ++i)
1505 res = typename BinaryOp::type() (res,(*flags_entries[ m_states[i] ])(*this));
1509 // checks if a flag is active using no binary op if 1 region, or OR if > 1 regions
1510 template <class Flag>
1511 bool is_flag_active() const
1513 return FlagHelper<Flag,(nr_regions::value>1)>::helper(*this,get_entries_for_flag<Flag>());
1515 // visit the currently active states (if these are defined as visitable
1516 // by implementing accept)
1517 void visit_current_states()
1519 for (int i=0; i<nr_regions::value;++i)
1521 m_visitors.execute(m_states[i]);
1524 #define MSM_VISIT_STATE_SUB(z, n, unused) ARG ## n vis ## n
1525 #define MSM_VISIT_STATE_EXECUTE(z, n, unused) \
1526 template <BOOST_PP_ENUM_PARAMS(n, class ARG)> \
1527 void visit_current_states(BOOST_PP_ENUM(n, MSM_VISIT_STATE_SUB, ~ ) ) \
1529 for (int i=0; i<nr_regions::value;++i) \
1531 m_visitors.execute(m_states[i],BOOST_PP_ENUM_PARAMS(n,vis)); \
1534 BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_VISIT_STATE_EXECUTE, ~)
1535 #undef MSM_VISIT_STATE_EXECUTE
1536 #undef MSM_VISIT_STATE_SUB
1538 // puts the given event into the deferred queue
1539 template <class Event>
1540 void defer_event(Event const& e)
1542 // to call this function, you need either a state with a deferred_events typedef
1543 // or that the fsm provides the activate_deferred_events typedef
1544 BOOST_MPL_ASSERT(( has_fsm_deferred_events<library_sm> ));
1545 execute_return (library_sm::*pf) (Event const&, EventSource) =
1546 &library_sm::process_event_internal;
1548 // Deferred events are added with a correlation sequence that helps to
1549 // identify when an event was added - This is typically to distinguish
1550 // between events deferred in this processing versus previous.
1551 m_deferred_events_queue.m_deferred_events_queue.push_back(
1554 pf, this, e, static_cast<EventSource>(EVENT_SOURCE_DIRECT|EVENT_SOURCE_DEFERRED)),
1555 static_cast<char>(m_deferred_events_queue.m_cur_seq+1)));
1558 protected: // interface for the derived class
1560 // helper used to fill the initial states
1563 init_states(int* const init):m_initial_states(init),m_index(-1){}
1565 // History initializer function object, used with mpl::for_each
1566 template <class State>
1567 void operator()(::boost::msm::wrap<State> const&)
1569 m_initial_states[++m_index]=get_state_id<stt,State>::type::value;
1571 int* const m_initial_states;
1577 update_state(substate_list& to_overwrite_):to_overwrite(&to_overwrite_){}
1578 template<typename StateType>
1579 void operator()(StateType const& astate) const
1581 ::boost::fusion::at_key<StateType>(*to_overwrite)=astate;
1583 substate_list* to_overwrite;
1585 template <class Expr>
1586 void set_states(Expr const& expr)
1588 ::boost::fusion::for_each(
1589 ::boost::fusion::as_vector(FoldToList()(expr, boost::fusion::nil_())),update_state(this->m_substate_list));
1592 // Construct with the default initial states
1593 state_machine<A0,A1,A2,A3,A4 >()
1596 ,m_deferred_events_queue()
1598 ,m_event_processing(false)
1599 ,m_is_included(false)
1603 // initialize our list of states with the ones defined in Derived::initial_state
1604 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1605 (init_states(m_states));
1606 m_history.set_initial_states(m_states);
1610 template <class Expr>
1611 state_machine<A0,A1,A2,A3,A4 >
1612 (Expr const& expr,typename ::boost::enable_if<typename ::boost::proto::is_expr<Expr>::type >::type* =0)
1615 ,m_deferred_events_queue()
1617 ,m_event_processing(false)
1618 ,m_is_included(false)
1622 BOOST_MPL_ASSERT_MSG(
1623 ( ::boost::proto::matches<Expr, FoldToList>::value),
1624 THE_STATES_EXPRESSION_PASSED_DOES_NOT_MATCH_GRAMMAR,
1627 // initialize our list of states with the ones defined in Derived::initial_state
1628 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1629 (init_states(m_states));
1630 m_history.set_initial_states(m_states);
1635 // Construct with the default initial states and some default argument(s)
1636 #if defined (BOOST_NO_CXX11_RVALUE_REFERENCES) \
1637 || defined (BOOST_NO_CXX11_VARIADIC_TEMPLATES) \
1638 || defined (BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS)
1639 #define MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB(z, n, unused) ARG ## n t ## n
1640 #define MSM_CONSTRUCTOR_HELPER_EXECUTE(z, n, unused) \
1641 template <BOOST_PP_ENUM_PARAMS(n, class ARG)> \
1642 state_machine<A0,A1,A2,A3,A4 \
1643 >(BOOST_PP_ENUM(n, MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB, ~ ), \
1644 typename ::boost::disable_if<typename ::boost::proto::is_expr<ARG0>::type >::type* =0 ) \
1645 :Derived(BOOST_PP_ENUM_PARAMS(n,t)) \
1647 ,m_deferred_events_queue() \
1649 ,m_event_processing(false) \
1650 ,m_is_included(false) \
1652 ,m_substate_list() \
1654 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> > \
1655 (init_states(m_states)); \
1656 m_history.set_initial_states(m_states); \
1657 fill_states(this); \
1659 template <class Expr,BOOST_PP_ENUM_PARAMS(n, class ARG)> \
1660 state_machine<A0,A1,A2,A3,A4 \
1661 >(Expr const& expr,BOOST_PP_ENUM(n, MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB, ~ ), \
1662 typename ::boost::enable_if<typename ::boost::proto::is_expr<Expr>::type >::type* =0 ) \
1663 :Derived(BOOST_PP_ENUM_PARAMS(n,t)) \
1665 ,m_deferred_events_queue() \
1667 ,m_event_processing(false) \
1668 ,m_is_included(false) \
1670 ,m_substate_list() \
1672 BOOST_MPL_ASSERT_MSG( \
1673 ( ::boost::proto::matches<Expr, FoldToList>::value), \
1674 THE_STATES_EXPRESSION_PASSED_DOES_NOT_MATCH_GRAMMAR, \
1676 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> > \
1677 (init_states(m_states)); \
1678 m_history.set_initial_states(m_states); \
1680 fill_states(this); \
1683 BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_CONSTRUCTOR_ARG_SIZE,1), MSM_CONSTRUCTOR_HELPER_EXECUTE, ~)
1684 #undef MSM_CONSTRUCTOR_HELPER_EXECUTE
1685 #undef MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB
1688 template <class ARG0,class... ARG,class=typename ::boost::disable_if<typename ::boost::proto::is_expr<ARG0>::type >::type>
1689 state_machine<A0,A1,A2,A3,A4
1690 >(ARG0&& t0,ARG&&... t)
1691 :Derived(std::forward<ARG0>(t0), std::forward<ARG>(t)...)
1693 ,m_deferred_events_queue()
1695 ,m_event_processing(false)
1696 ,m_is_included(false)
1700 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1701 (init_states(m_states));
1702 m_history.set_initial_states(m_states);
1705 template <class Expr,class... ARG,class=typename ::boost::enable_if<typename ::boost::proto::is_expr<Expr>::type >::type>
1706 state_machine<A0,A1,A2,A3,A4
1707 >(Expr const& expr,ARG&&... t)
1708 :Derived(std::forward<ARG>(t)...)
1710 ,m_deferred_events_queue()
1712 ,m_event_processing(false)
1713 ,m_is_included(false)
1717 BOOST_MPL_ASSERT_MSG(
1718 ( ::boost::proto::matches<Expr, FoldToList>::value),
1719 THE_STATES_EXPRESSION_PASSED_DOES_NOT_MATCH_GRAMMAR,
1721 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1722 (init_states(m_states));
1723 m_history.set_initial_states(m_states);
1730 // assignment operator using the copy policy to decide if non_copyable, shallow or deep copying is necessary
1731 library_sm& operator= (library_sm const& rhs)
1735 Derived::operator=(rhs);
1740 state_machine<A0,A1,A2,A3,A4>
1741 (library_sm const& rhs)
1746 // initialize our list of states with the ones defined in Derived::initial_state
1752 // the following 2 functions handle the terminate/interrupt states handling
1753 // if one of these states is found, the first one is used
1754 template <class Event>
1755 bool is_event_handling_blocked_helper( ::boost::mpl::true_ const &)
1757 // if the state machine is terminated, do not handle any event
1758 if (is_flag_active< ::boost::msm::TerminateFlag>())
1760 // if the state machine is interrupted, do not handle any event
1761 // unless the event is the end interrupt event
1762 if ( is_flag_active< ::boost::msm::InterruptedFlag>() &&
1763 !is_flag_active< ::boost::msm::EndInterruptFlag<Event> >())
1767 // otherwise simple handling, no flag => continue
1768 template <class Event>
1769 bool is_event_handling_blocked_helper( ::boost::mpl::false_ const &)
1771 // no terminate/interrupt states detected
1774 void do_handle_prio_msg_queue_deferred_queue(EventSource source, HandledEnum handled, ::boost::mpl::true_ const &)
1776 // non-default. Handle msg queue with higher prio than deferred queue
1777 if (!(EVENT_SOURCE_MSG_QUEUE & source))
1779 do_post_msg_queue_helper(
1780 ::boost::mpl::bool_<
1781 is_no_message_queue<library_sm>::type::value>());
1782 if (!(EVENT_SOURCE_DEFERRED & source))
1784 handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
1785 defer_helper.do_handle_deferred(HANDLED_TRUE & handled);
1789 void do_handle_prio_msg_queue_deferred_queue(EventSource source, HandledEnum handled, ::boost::mpl::false_ const &)
1791 // default. Handle deferred queue with higher prio than msg queue
1792 if (!(EVENT_SOURCE_DEFERRED & source))
1794 handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
1795 defer_helper.do_handle_deferred(HANDLED_TRUE & handled);
1797 // Handle any new events generated into the queue, but only if
1798 // we're not already processing from the message queue.
1799 if (!(EVENT_SOURCE_MSG_QUEUE & source))
1801 do_post_msg_queue_helper(
1802 ::boost::mpl::bool_<
1803 is_no_message_queue<library_sm>::type::value>());
1807 // the following functions handle pre/post-process handling of a message queue
1808 template <class StateType,class EventType>
1809 bool do_pre_msg_queue_helper(EventType const&, ::boost::mpl::true_ const &)
1811 // no message queue needed
1814 template <class StateType,class EventType>
1815 bool do_pre_msg_queue_helper(EventType const& evt, ::boost::mpl::false_ const &)
1817 execute_return (library_sm::*pf) (EventType const&, EventSource) =
1818 &library_sm::process_event_internal;
1820 // if we are already processing an event
1821 if (m_event_processing)
1823 // event has to be put into the queue
1824 m_events_queue.m_events_queue.push_back(
1827 static_cast<EventSource>(EVENT_SOURCE_DIRECT | EVENT_SOURCE_MSG_QUEUE)));
1832 // event can be handled, processing
1833 m_event_processing = true;
1836 void do_post_msg_queue_helper( ::boost::mpl::true_ const &)
1838 // no message queue needed
1840 void do_post_msg_queue_helper( ::boost::mpl::false_ const &)
1842 process_message_queue(this);
1844 void do_allow_event_processing_after_transition( ::boost::mpl::true_ const &)
1846 // no message queue needed
1848 void do_allow_event_processing_after_transition( ::boost::mpl::false_ const &)
1850 m_event_processing = false;
1852 // the following 2 functions handle the processing either with a try/catch protection or without
1853 template <class StateType,class EventType>
1854 HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::true_ const &, bool is_direct_call)
1856 return this->do_process_event(evt,is_direct_call);
1858 template <class StateType,class EventType>
1859 HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::false_ const &, bool is_direct_call)
1861 // when compiling without exception support there is no formal parameter "e" in the catch handler.
1862 // Declaring a local variable here does not hurt and will be "used" to make the code in the handler
1863 // compilable although the code will never be executed.
1867 return this->do_process_event(evt,is_direct_call);
1869 BOOST_CATCH (std::exception& e)
1871 // give a chance to the concrete state machine to handle
1872 this->exception_caught(evt,*this,e);
1875 return HANDLED_TRUE;
1877 // handling of deferred events
1878 // if none is found in the SM, take the following empty main version
1879 template <class StateType, class Enable = int>
1880 struct handle_defer_helper
1882 handle_defer_helper(deferred_msg_queue_helper<library_sm>& ){}
1883 void do_handle_deferred(bool)
1887 // otherwise the standard version handling the deferred events
1888 template <class StateType>
1889 struct handle_defer_helper
1890 <StateType, typename enable_if< typename ::boost::msm::back::has_fsm_deferred_events<StateType>::type,int >::type>
1892 handle_defer_helper(deferred_msg_queue_helper<library_sm>& a_queue):
1893 m_events_queue(a_queue) {}
1894 void do_handle_deferred(bool new_seq=false)
1896 // A new sequence is typically started upon initial entry to the
1897 // state, or upon a new transition. When this occurs we want to
1898 // process all previously deferred events by incrementing the
1899 // correlation sequence.
1902 ++m_events_queue.m_cur_seq;
1905 char& cur_seq = m_events_queue.m_cur_seq;
1907 // Iteratively process all of the events within the deferred
1908 // queue upto (but not including) newly deferred events.
1909 while (!m_events_queue.m_deferred_events_queue.empty())
1911 typename deferred_events_queue_t::value_type& pair =
1912 m_events_queue.m_deferred_events_queue.front();
1914 if (cur_seq != pair.second)
1919 deferred_fct next = pair.first;
1920 m_events_queue.m_deferred_events_queue.pop_front();
1926 deferred_msg_queue_helper<library_sm>& m_events_queue;
1929 // handling of eventless transitions
1930 // if none is found in the SM, nothing to do
1931 template <class StateType, class Enable = void>
1932 struct handle_eventless_transitions_helper
1934 handle_eventless_transitions_helper(library_sm* , bool ){}
1935 void process_completion_event(EventSource = EVENT_SOURCE_DEFAULT){}
1938 template <class StateType>
1939 struct handle_eventless_transitions_helper
1940 <StateType, typename enable_if< typename ::boost::msm::back::has_fsm_eventless_transition<StateType>::type >::type>
1942 handle_eventless_transitions_helper(library_sm* self_, bool handled_):self(self_),handled(handled_){}
1943 void process_completion_event(EventSource source = EVENT_SOURCE_DEFAULT)
1945 typedef typename ::boost::mpl::deref<
1946 typename ::boost::mpl::begin<
1947 typename find_completion_events<StateType>::type
1949 >::type first_completion_event;
1952 self->process_event_internal(
1953 first_completion_event(),
1954 source | EVENT_SOURCE_DIRECT);
1963 // helper class called in case the event to process has been found in the fsm's internal stt and is therefore processable
1964 template<class Event>
1965 struct process_fsm_internal_table
1967 typedef typename ::boost::mpl::has_key<processable_events_internal_table,Event>::type is_event_processable;
1969 // forward to the correct do_process
1970 static void process(Event const& evt,library_sm* self_,HandledEnum& result)
1972 do_process(evt,self_,result,is_event_processable());
1975 // the event is processable, let's try!
1976 static void do_process(Event const& evt,library_sm* self_,HandledEnum& result, ::boost::mpl::true_)
1978 if (result != HANDLED_TRUE)
1980 typedef dispatch_table<library_sm,complete_table,Event,CompilePolicy> table;
1981 HandledEnum res_internal = table::instance.entries[0](*self_, 0, self_->m_states[0], evt);
1982 result = (HandledEnum)((int)result | (int)res_internal);
1985 // version doing nothing if the event is not in the internal stt and we can save ourselves the time trying to process
1986 static void do_process(Event const& ,library_sm* ,HandledEnum& , ::boost::mpl::false_)
1992 template <class StateType,class Enable=void>
1993 struct region_processing_helper
1996 region_processing_helper(library_sm* self_,HandledEnum& result_)
1997 :self(self_),result(result_){}
1998 template<class Event>
1999 void process(Event const& evt)
2001 // use this table as if it came directly from the user
2002 typedef dispatch_table<library_sm,complete_table,Event,CompilePolicy> table;
2003 // +1 because index 0 is reserved for this fsm
2005 table::instance.entries[self->m_states[0]+1](
2006 *self, 0, self->m_states[0], evt);
2007 result = (HandledEnum)((int)result | (int)res);
2008 // process the event in the internal table of this fsm if the event is processable (present in the table)
2009 process_fsm_internal_table<Event>::process(evt,self,result);
2012 HandledEnum& result;
2014 // version with visitors
2015 template <class StateType>
2016 struct region_processing_helper<StateType,typename ::boost::enable_if<
2017 ::boost::mpl::is_sequence<typename StateType::initial_state> >::type>
2020 // process event in one region
2021 template <class region_id,int Dummy=0>
2024 template<class Event>
2025 static void process(Event const& evt,library_sm* self_,HandledEnum& result_)
2027 // use this table as if it came directly from the user
2028 typedef dispatch_table<library_sm,complete_table,Event,CompilePolicy> table;
2029 // +1 because index 0 is reserved for this fsm
2031 table::instance.entries[self_->m_states[region_id::value]+1](
2032 *self_, region_id::value , self_->m_states[region_id::value], evt);
2033 result_ = (HandledEnum)((int)result_ | (int)res);
2034 In< ::boost::mpl::int_<region_id::value+1> >::process(evt,self_,result_);
2037 template <int Dummy>
2038 struct In< ::boost::mpl::int_<nr_regions::value>,Dummy>
2040 // end of processing
2041 template<class Event>
2042 static void process(Event const& evt,library_sm* self_,HandledEnum& result_)
2044 // process the event in the internal table of this fsm if the event is processable (present in the table)
2045 process_fsm_internal_table<Event>::process(evt,self_,result_);
2049 region_processing_helper(library_sm* self_,HandledEnum& result_)
2050 :self(self_),result(result_){}
2051 template<class Event>
2052 void process(Event const& evt)
2054 In< ::boost::mpl::int_<0> >::process(evt,self,result);
2058 HandledEnum& result;
2061 // Main function used internally to make transitions
2062 // Can only be called for internally (for example in an action method) generated events.
2063 template<class Event>
2064 execute_return process_event_internal(Event const& evt,
2065 EventSource source = EVENT_SOURCE_DEFAULT)
2067 // if the state machine has terminate or interrupt flags, check them, otherwise skip
2068 if (is_event_handling_blocked_helper<Event>
2069 ( ::boost::mpl::bool_<has_fsm_blocking_states<library_sm>::type::value>() ) )
2071 return HANDLED_TRUE;
2074 // if a message queue is needed and processing is on the way
2075 if (!do_pre_msg_queue_helper<Event>
2076 (evt,::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>()))
2078 // wait for the end of current processing
2079 return HANDLED_TRUE;
2084 HandledEnum handled = this->do_process_helper<Event>(
2086 ::boost::mpl::bool_<is_no_exception_thrown<library_sm>::type::value>(),
2087 (EVENT_SOURCE_DIRECT & source));
2089 // at this point we allow the next transition be executed without enqueing
2090 // so that completion events and deferred events execute now (if any)
2091 do_allow_event_processing_after_transition(
2092 ::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>());
2094 // Process completion transitions BEFORE any other event in the
2095 // pool (UML Standard 2.3 15.3.14)
2096 handle_eventless_transitions_helper<library_sm>
2097 eventless_helper(this,(HANDLED_TRUE & handled));
2098 eventless_helper.process_completion_event(source);
2100 // After handling, take care of the deferred events, but only if
2101 // we're not already processing from the deferred queue.
2102 do_handle_prio_msg_queue_deferred_queue(
2104 ::boost::mpl::bool_<has_event_queue_before_deferred_queue<library_sm>::type::value>());
2109 // minimum event processing without exceptions, queues, etc.
2110 template<class Event>
2111 HandledEnum do_process_event(Event const& evt, bool is_direct_call)
2113 HandledEnum handled = HANDLED_FALSE;
2115 // dispatch the event to every region
2116 region_processing_helper<Derived> helper(this,handled);
2117 helper.process(evt);
2119 // if the event has not been handled and we have orthogonal zones, then
2120 // generate an error on every active state
2121 // for state machine states contained in other state machines, do not handle
2122 // but let the containing sm handle the error, unless the event was generated in this fsm
2123 // (by calling process_event on this fsm object, is_direct_call == true)
2124 // completion events do not produce an error
2125 if ( (!is_contained() || is_direct_call) && !handled && !is_completion_event<Event>::type::value)
2127 for (int i=0; i<nr_regions::value;++i)
2129 this->no_transition(evt,*this,this->m_states[i]);
2135 // default row arguments for the compilers which accept this
2136 template <class Event>
2137 bool no_guard(Event const&){return true;}
2138 template <class Event>
2139 void no_action(Event const&){}
2141 #ifndef BOOST_NO_RTTI
2142 HandledEnum process_any_event( ::boost::any const& evt);
2146 // composite accept implementation. First calls accept on the composite, then accept on all its active states.
2147 void composite_accept()
2150 this->visit_current_states();
2153 #define MSM_COMPOSITE_ACCEPT_SUB(z, n, unused) ARG ## n vis ## n
2154 #define MSM_COMPOSITE_ACCEPT_SUB2(z, n, unused) boost::ref( vis ## n )
2155 #define MSM_COMPOSITE_ACCEPT_EXECUTE(z, n, unused) \
2156 template <BOOST_PP_ENUM_PARAMS(n, class ARG)> \
2157 void composite_accept(BOOST_PP_ENUM(n, MSM_COMPOSITE_ACCEPT_SUB, ~ ) ) \
2159 this->accept(BOOST_PP_ENUM_PARAMS(n,vis)); \
2160 this->visit_current_states(BOOST_PP_ENUM(n,MSM_COMPOSITE_ACCEPT_SUB2, ~)); \
2162 BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_COMPOSITE_ACCEPT_EXECUTE, ~)
2163 #undef MSM_COMPOSITE_ACCEPT_EXECUTE
2164 #undef MSM_COMPOSITE_ACCEPT_SUB
2165 #undef MSM_COMPOSITE_ACCEPT_SUB2
2167 // helper used to call the init states at the start of the state machine
2168 template <class Event>
2171 call_init(Event const& an_event,library_sm* self_):
2172 evt(an_event),self(self_){}
2173 template <class State>
2174 void operator()(boost::msm::wrap<State> const&)
2176 execute_entry(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
2182 // helper for flag handling. Uses OR by default on orthogonal zones.
2183 template <class Flag,bool orthogonalStates>
2186 static bool helper(library_sm const& sm,flag_handler* )
2188 // by default we use OR to accumulate the flags
2189 return sm.is_flag_active<Flag,Flag_OR>();
2192 template <class Flag>
2193 struct FlagHelper<Flag,false>
2195 static bool helper(library_sm const& sm,flag_handler* flags_entries)
2197 // just one active state, so we can call operator[] with 0
2198 return flags_entries[sm.current_state()[0]](sm);
2202 // defines a true and false functions plus a forwarding one for composite states
2203 template <class StateType,class Flag>
2206 static bool flag_true(library_sm const& )
2210 static bool flag_false(library_sm const& )
2214 static bool forward(library_sm const& fsm)
2216 return ::boost::fusion::at_key<StateType>(fsm.m_substate_list).template is_flag_active<Flag>();
2219 template <class Flag>
2223 // helper function, helps hiding the forward function for non-state machines states.
2225 void helper (flag_handler* an_entry,int offset, ::boost::mpl::true_ const & )
2227 // composite => forward
2228 an_entry[offset] = &FlagHandler<T,Flag>::forward;
2231 void helper (flag_handler* an_entry,int offset, ::boost::mpl::false_ const & )
2234 an_entry[offset] = &FlagHandler<T,Flag>::flag_false;
2237 flag_handler* entries;
2240 init_flags(flag_handler* entries_)
2244 // Flags initializer function object, used with mpl::for_each
2245 template <class StateType>
2246 void operator()( ::boost::msm::wrap<StateType> const& )
2248 typedef typename get_flag_list<StateType>::type flags;
2249 typedef typename ::boost::mpl::contains<flags,Flag >::type found;
2251 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,StateType>::type::value));
2252 if (found::type::value)
2254 // the type defined the flag => true
2255 entries[state_id] = &FlagHandler<StateType,Flag>::flag_true;
2260 typedef typename ::boost::mpl::and_<
2261 typename is_composite_state<StateType>::type,
2262 typename ::boost::mpl::not_<
2263 typename has_non_forwarding_flag<Flag>::type>::type >::type composite_no_forward;
2265 helper<StateType>(entries,state_id,::boost::mpl::bool_<composite_no_forward::type::value>());
2269 // maintains for every flag a static array containing the flag value for every state
2270 template <class Flag>
2271 flag_handler* get_entries_for_flag() const
2273 BOOST_STATIC_CONSTANT(int, max_state = (mpl::size<state_list>::value));
2275 static flag_handler flags_entries[max_state];
2276 // build a state list
2277 ::boost::mpl::for_each<state_list, boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2278 (init_flags<Flag>(flags_entries));
2279 return flags_entries;
2282 // helper used to create a state using the correct constructor
2283 template <class State, class Enable=void>
2284 struct create_state_helper
2286 static void set_sm(library_sm* )
2288 // state doesn't need its sm
2291 // create a state requiring a pointer to the state machine
2292 template <class State>
2293 struct create_state_helper<State,typename boost::enable_if<typename State::needs_sm >::type>
2295 static void set_sm(library_sm* sm)
2297 // create and set the fsm
2298 ::boost::fusion::at_key<State>(sm->m_substate_list).set_sm_ptr(sm);
2301 // main unspecialized helper class
2302 template <class StateType,int ARGS>
2303 struct visitor_args;
2305 #define MSM_VISITOR_ARGS_SUB(z, n, unused) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1))
2306 #define MSM_VISITOR_ARGS_TYPEDEF_SUB(z, n, unused) typename StateType::accept_sig::argument ## n
2308 #define MSM_VISITOR_ARGS_EXECUTE(z, n, unused) \
2309 template <class StateType> \
2310 struct visitor_args<StateType,n> \
2312 template <class State> \
2313 static typename enable_if_c<!is_composite_state<State>::value,void >::type \
2314 helper (library_sm* sm, \
2315 int id,StateType& astate) \
2317 sm->m_visitors.insert(id, boost::bind(&StateType::accept, \
2318 ::boost::ref(astate) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_SUB, ~) )); \
2320 template <class State> \
2321 static typename enable_if_c<is_composite_state<State>::value,void >::type \
2322 helper (library_sm* sm, \
2323 int id,StateType& astate) \
2325 void (StateType::*caccept)(BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_TYPEDEF_SUB, ~ ) ) \
2326 = &StateType::composite_accept; \
2327 sm->m_visitors.insert(id, boost::bind(caccept, \
2328 ::boost::ref(astate) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_SUB, ~) )); \
2331 BOOST_PP_REPEAT(BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_VISITOR_ARGS_EXECUTE, ~)
2332 #undef MSM_VISITOR_ARGS_EXECUTE
2333 #undef MSM_VISITOR_ARGS_SUB
2335 // the IBM compiler seems to have problems with nested classes
2336 // the same seems to apply to the Apple version of gcc 4.0.1 (just in case we do for < 4.1)
2337 // and also to MS VC < 8
2338 #if defined (__IBMCPP__) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2341 template<class ContainingSM>
2342 void set_containing_sm(ContainingSM* sm)
2345 ::boost::fusion::for_each(m_substate_list,add_state<ContainingSM>(this,sm));
2347 #if defined (__IBMCPP__) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2350 // A function object for use with mpl::for_each that stuffs
2351 // states into the state list.
2352 template<class ContainingSM>
2355 add_state(library_sm* self_,ContainingSM* sm)
2356 : self(self_),containing_sm(sm){}
2358 // State is a sub fsm with exit pseudo states and gets a pointer to this fsm, so it can build a callback
2359 template <class StateType>
2360 typename ::boost::enable_if<
2361 typename is_composite_state<StateType>::type,void >::type
2362 new_state_helper(boost::msm::back::dummy<0> = 0) const
2364 ::boost::fusion::at_key<StateType>(self->m_substate_list).set_containing_sm(containing_sm);
2366 // State is a sub fsm without exit pseudo states and does not get a callback to this fsm
2367 // or state is a normal state and needs nothing except creation
2368 template <class StateType>
2369 typename ::boost::enable_if<
2370 typename boost::mpl::and_<typename boost::mpl::not_
2371 <typename is_composite_state<StateType>::type>::type,
2372 typename boost::mpl::not_
2373 <typename is_pseudo_exit<StateType>::type>::type
2375 new_state_helper( ::boost::msm::back::dummy<1> = 0) const
2379 // state is exit pseudo state and gets callback to target fsm
2380 template <class StateType>
2381 typename ::boost::enable_if<typename is_pseudo_exit<StateType>::type,void >::type
2382 new_state_helper( ::boost::msm::back::dummy<2> = 0) const
2384 execute_return (ContainingSM::*pf) (typename StateType::event const& evt)=
2385 &ContainingSM::process_event;
2386 ::boost::function<execute_return (typename StateType::event const&)> fct =
2387 ::boost::bind(pf,containing_sm,_1);
2388 ::boost::fusion::at_key<StateType>(self->m_substate_list).set_forward_fct(fct);
2390 // for every defined state in the sm
2391 template <class State>
2392 void operator()( State const&) const
2394 //create a new state with the defined id and type
2395 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,State>::value));
2397 this->new_state_helper<State>(),
2398 create_state_helper<State>::set_sm(self);
2399 // create a visitor callback
2400 visitor_helper(state_id,::boost::fusion::at_key<State>(self->m_substate_list),
2401 ::boost::mpl::bool_<has_accept_sig<State>::type::value>());
2404 // support possible use of a visitor if accept_sig is defined
2405 template <class StateType>
2406 void visitor_helper(int id,StateType& astate, ::boost::mpl::true_ const & ) const
2408 visitor_args<StateType,StateType::accept_sig::args_number>::
2409 template helper<StateType>(self,id,astate);
2411 template <class StateType>
2412 void visitor_helper(int ,StateType& , ::boost::mpl::false_ const &) const
2418 ContainingSM* containing_sm;
2421 // helper used to copy every state if needed
2424 copy_helper(library_sm* sm):
2426 template <class StateType>
2427 void operator()( ::boost::msm::wrap<StateType> const& )
2429 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,StateType>::type::value));
2430 // possibly also set the visitor
2431 visitor_helper<StateType>(state_id);
2433 // and for states that keep a pointer to the fsm, reset the pointer
2434 create_state_helper<StateType>::set_sm(m_sm);
2436 template <class StateType>
2437 typename ::boost::enable_if<typename has_accept_sig<StateType>::type,void >::type
2438 visitor_helper(int id) const
2440 visitor_args<StateType,StateType::accept_sig::args_number>::template helper<StateType>
2441 (m_sm,id,::boost::fusion::at_key<StateType>(m_sm->m_substate_list));
2443 template <class StateType>
2444 typename ::boost::disable_if<typename has_accept_sig<StateType>::type,void >::type
2445 visitor_helper(int) const
2452 // helper to copy the active states attribute
2453 template <class region_id,int Dummy=0>
2454 struct region_copy_helper
2456 static void do_copy(library_sm* self_,library_sm const& rhs)
2458 self_->m_states[region_id::value] = rhs.m_states[region_id::value];
2459 region_copy_helper< ::boost::mpl::int_<region_id::value+1> >::do_copy(self_,rhs);
2462 template <int Dummy>
2463 struct region_copy_helper< ::boost::mpl::int_<nr_regions::value>,Dummy>
2465 // end of processing
2466 static void do_copy(library_sm*,library_sm const& ){}
2468 // copy functions for deep copy (no need of a 2nd version for NoCopy as noncopyable handles it)
2469 void do_copy (library_sm const& rhs,
2470 ::boost::msm::back::dummy<0> = 0)
2472 // deep copy simply assigns the data
2473 region_copy_helper< ::boost::mpl::int_<0> >::do_copy(this,rhs);
2474 m_events_queue = rhs.m_events_queue;
2475 m_deferred_events_queue = rhs.m_deferred_events_queue;
2476 m_history = rhs.m_history;
2477 m_event_processing = rhs.m_event_processing;
2478 m_is_included = rhs.m_is_included;
2479 m_substate_list = rhs.m_substate_list;
2480 // except for the states themselves, which get duplicated
2482 ::boost::mpl::for_each<state_list, ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2483 (copy_helper(this));
2486 // helper used to call the correct entry/exit method
2487 // unfortunately in O(number of states in the sub-sm) but should be better than a virtual call
2488 template<class Event,bool is_entry>
2489 struct entry_exit_helper
2491 entry_exit_helper(int id,Event const& e,library_sm* self_):
2492 state_id(id),evt(e),self(self_){}
2493 // helper for entry actions
2494 template <class IsEntry,class State>
2495 typename ::boost::enable_if<typename IsEntry::type,void >::type
2496 helper( ::boost::msm::back::dummy<0> = 0)
2498 BOOST_STATIC_CONSTANT(int, id = (get_state_id<stt,State>::value));
2501 execute_entry<State>(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
2504 // helper for exit actions
2505 template <class IsEntry,class State>
2506 typename boost::disable_if<typename IsEntry::type,void >::type
2507 helper( ::boost::msm::back::dummy<1> = 0)
2509 BOOST_STATIC_CONSTANT(int, id = (get_state_id<stt,State>::value));
2512 execute_exit<State>(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
2515 // iterates through all states to find the one to be activated
2516 template <class State>
2517 void operator()( ::boost::msm::wrap<State> const&)
2519 entry_exit_helper<Event,is_entry>::template helper< ::boost::mpl::bool_<is_entry>,State >();
2527 // helper to start the fsm
2528 template <class region_id,int Dummy=0>
2529 struct region_start_helper
2531 template<class Event>
2532 static void do_start(library_sm* self_,Event const& incomingEvent)
2534 //forward the event for handling by sub state machines
2535 ::boost::mpl::for_each<state_list, ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2536 (entry_exit_helper<Event,true>(self_->m_states[region_id::value],incomingEvent,self_));
2538 < ::boost::mpl::int_<region_id::value+1> >::do_start(self_,incomingEvent);
2541 template <int Dummy>
2542 struct region_start_helper< ::boost::mpl::int_<nr_regions::value>,Dummy>
2544 // end of processing
2545 template<class Event>
2546 static void do_start(library_sm*,Event const& ){}
2548 // start for states machines which are themselves embedded in other state machines (composites)
2549 template <class Event>
2550 void internal_start(Event const& incomingEvent)
2552 region_start_helper< ::boost::mpl::int_<0> >::do_start(this,incomingEvent);
2553 // give a chance to handle an anonymous (eventless) transition
2554 handle_eventless_transitions_helper<library_sm> eventless_helper(this,true);
2555 eventless_helper.process_completion_event();
2558 template <class StateType>
2559 struct find_region_id
2561 template <int region,int Dummy=0>
2564 enum {region_index=region};
2566 // if the user provides no region, find it!
2570 typedef typename build_orthogonal_regions<
2573 >::type all_regions;
2574 enum {region_index= find_region_index<all_regions,StateType>::value };
2576 enum {region_index = In<StateType::zone_index>::region_index };
2578 // helper used to set the correct state as active state upon entry into a fsm
2579 struct direct_event_start_helper
2581 direct_event_start_helper(library_sm* self_):self(self_){}
2582 // this variant is for the standard case, entry due to activation of the containing FSM
2583 template <class EventType,class FsmType>
2584 typename ::boost::disable_if<typename has_direct_entry<EventType>::type,void>::type
2585 operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<0> = 0)
2587 (static_cast<Derived*>(self))->on_entry(evt,fsm);
2588 self->internal_start(evt);
2591 // this variant is for the direct entry case (just one entry, not a sequence of entries)
2592 template <class EventType,class FsmType>
2593 typename ::boost::enable_if<
2594 typename ::boost::mpl::and_<
2595 typename ::boost::mpl::not_< typename is_pseudo_entry<
2596 typename EventType::active_state>::type >::type,
2597 typename ::boost::mpl::and_<typename has_direct_entry<EventType>::type,
2598 typename ::boost::mpl::not_<typename ::boost::mpl::is_sequence
2599 <typename EventType::active_state>::type >::type
2602 operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2604 (static_cast<Derived*>(self))->on_entry(evt,fsm);
2605 int state_id = get_state_id<stt,typename EventType::active_state::wrapped_entry>::value;
2606 BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index >= 0);
2607 BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index < nr_regions::value);
2608 // just set the correct zone, the others will be default/history initialized
2609 self->m_states[find_region_id<typename EventType::active_state::wrapped_entry>::region_index] = state_id;
2610 self->internal_start(evt.m_event);
2613 // this variant is for the fork entry case (a sequence on entries)
2614 template <class EventType,class FsmType>
2615 typename ::boost::enable_if<
2616 typename ::boost::mpl::and_<
2617 typename ::boost::mpl::not_<
2618 typename is_pseudo_entry<typename EventType::active_state>::type >::type,
2619 typename ::boost::mpl::and_<typename has_direct_entry<EventType>::type,
2620 typename ::boost::mpl::is_sequence<
2621 typename EventType::active_state>::type
2624 operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0)
2626 (static_cast<Derived*>(self))->on_entry(evt,fsm);
2627 ::boost::mpl::for_each<typename EventType::active_state,
2628 ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2629 (fork_helper<EventType>(self,evt));
2630 // set the correct zones, the others (if any) will be default/history initialized
2631 self->internal_start(evt.m_event);
2634 // this variant is for the pseudo state entry case
2635 template <class EventType,class FsmType>
2636 typename ::boost::enable_if<
2637 typename is_pseudo_entry<typename EventType::active_state >::type,void
2639 operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<3> = 0)
2642 (static_cast<Derived*>(self))->on_entry(evt,fsm);
2643 int state_id = get_state_id<stt,typename EventType::active_state::wrapped_entry>::value;
2644 BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index >= 0);
2645 BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index < nr_regions::value);
2646 // given region starts with the entry pseudo state as active state
2647 self->m_states[find_region_id<typename EventType::active_state::wrapped_entry>::region_index] = state_id;
2648 self->internal_start(evt.m_event);
2649 // and we process the transition in the zone of the newly active state
2650 // (entry pseudo states are, according to UML, a state connecting 1 transition outside to 1 inside
2651 self->process_event(evt.m_event);
2654 // helper for the fork case, does almost like the direct entry
2656 template <class EventType>
2659 fork_helper(library_sm* self_,EventType const& evt_):
2660 helper_self(self_),helper_evt(evt_){}
2661 template <class StateType>
2662 void operator()( ::boost::msm::wrap<StateType> const& )
2664 int state_id = get_state_id<stt,typename StateType::wrapped_entry>::value;
2665 BOOST_STATIC_ASSERT(find_region_id<typename StateType::wrapped_entry>::region_index >= 0);
2666 BOOST_STATIC_ASSERT(find_region_id<typename StateType::wrapped_entry>::region_index < nr_regions::value);
2667 helper_self->m_states[find_region_id<typename StateType::wrapped_entry>::region_index] = state_id;
2670 library_sm* helper_self;
2671 EventType const& helper_evt;
2676 template <class region_id,int Dummy=0>
2677 struct region_entry_exit_helper
2679 template<class Event>
2680 static void do_entry(library_sm* self_,Event const& incomingEvent)
2682 self_->m_states[region_id::value] =
2683 self_->m_history.history_entry(incomingEvent)[region_id::value];
2684 region_entry_exit_helper
2685 < ::boost::mpl::int_<region_id::value+1> >::do_entry(self_,incomingEvent);
2687 template<class Event>
2688 static void do_exit(library_sm* self_,Event const& incomingEvent)
2690 ::boost::mpl::for_each<state_list, ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2691 (entry_exit_helper<Event,false>(self_->m_states[region_id::value],incomingEvent,self_));
2692 region_entry_exit_helper
2693 < ::boost::mpl::int_<region_id::value+1> >::do_exit(self_,incomingEvent);
2696 template <int Dummy>
2697 struct region_entry_exit_helper< ::boost::mpl::int_<nr_regions::value>,Dummy>
2699 // end of processing
2700 template<class Event>
2701 static void do_entry(library_sm*,Event const& ){}
2702 template<class Event>
2703 static void do_exit(library_sm*,Event const& ){}
2705 // entry/exit for states machines which are themselves embedded in other state machines (composites)
2706 template <class Event,class FsmType>
2707 void do_entry(Event const& incomingEvent,FsmType& fsm)
2709 // by default we activate the history/init states, can be overwritten by direct_event_start_helper
2710 region_entry_exit_helper< ::boost::mpl::int_<0> >::do_entry(this,incomingEvent);
2711 // block immediate handling of events
2712 m_event_processing = true;
2713 // if the event is generating a direct entry/fork, set the current state(s) to the direct state(s)
2714 direct_event_start_helper(this)(incomingEvent,fsm);
2715 // handle messages which were generated and blocked in the init calls
2716 m_event_processing = false;
2717 // look for deferred events waiting
2718 handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
2719 defer_helper.do_handle_deferred(true);
2720 process_message_queue(this);
2722 template <class Event,class FsmType>
2723 void do_exit(Event const& incomingEvent,FsmType& fsm)
2725 // first recursively exit the sub machines
2726 // forward the event for handling by sub state machines
2727 region_entry_exit_helper< ::boost::mpl::int_<0> >::do_exit(this,incomingEvent);
2728 // then call our own exit
2729 (static_cast<Derived*>(this))->on_exit(incomingEvent,fsm);
2730 // give the history a chance to handle this (or not).
2731 m_history.history_exit(this->m_states);
2732 // history decides what happens with deferred events
2733 if (!m_history.process_deferred_events(incomingEvent))
2735 clear_deferred_queue();
2739 // the IBM and VC<8 compilers seem to have problems with the friend declaration of dispatch_table
2740 #if defined (__IBMCPP__) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2743 // no transition for event.
2744 template <class Event>
2745 static HandledEnum call_no_transition(library_sm& , int , int , Event const& )
2747 return HANDLED_FALSE;
2749 // no transition for event for internal transitions (not an error).
2750 template <class Event>
2751 static HandledEnum call_no_transition_internal(library_sm& , int , int , Event const& )
2753 //// reject to give others a chance to handle
2754 //return HANDLED_GUARD_REJECT;
2755 return HANDLED_FALSE;
2757 // called for deferred events. Address set in the dispatch_table at init
2758 template <class Event>
2759 static HandledEnum defer_transition(library_sm& fsm, int , int , Event const& e)
2762 return HANDLED_DEFERRED;
2764 // called for completion events. Default address set in the dispatch_table at init
2765 // prevents no-transition detection for completion events
2766 template <class Event>
2767 static HandledEnum default_eventless_transition(library_sm&, int, int , Event const&)
2769 return HANDLED_FALSE;
2771 #if defined (__IBMCPP__) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2774 // removes one event from the message queue and processes it
2775 template <class StateType>
2776 void process_message_queue(StateType*,
2777 typename ::boost::disable_if<typename is_no_message_queue<StateType>::type,void >::type* = 0)
2779 // Iteratively process all events from the message queue.
2780 while (!m_events_queue.m_events_queue.empty())
2782 transition_fct next = m_events_queue.m_events_queue.front();
2783 m_events_queue.m_events_queue.pop_front();
2787 template <class StateType>
2788 void process_message_queue(StateType*,
2789 typename ::boost::enable_if<typename is_no_message_queue<StateType>::type,void >::type* = 0)
2791 // nothing to process
2793 // helper function. In cases where the event is wrapped (target is a direct entry states)
2794 // we want to send only the real event to on_entry, not the wrapper.
2795 template <class EventType>
2797 typename boost::enable_if<typename has_direct_entry<EventType>::type,typename EventType::contained_event const& >::type
2798 remove_direct_entry_event_wrapper(EventType const& evt,boost::msm::back::dummy<0> = 0)
2802 template <class EventType>
2803 static typename boost::disable_if<typename has_direct_entry<EventType>::type,EventType const& >::type
2804 remove_direct_entry_event_wrapper(EventType const& evt,boost::msm::back::dummy<1> = 0)
2806 // identity. No wrapper
2809 // calls the entry/exit or on_entry/on_exit depending on the state type
2810 // (avoids calling virtually)
2812 template <class StateType,class EventType,class FsmType>
2814 typename boost::enable_if<typename is_composite_state<StateType>::type,void >::type
2815 execute_entry(StateType& astate,EventType const& evt,FsmType& fsm,boost::msm::back::dummy<0> = 0)
2817 // calls on_entry on the fsm then handles direct entries, fork, entry pseudo state
2818 astate.do_entry(evt,fsm);
2820 // variant for states
2821 template <class StateType,class EventType,class FsmType>
2823 typename ::boost::disable_if<
2824 typename ::boost::mpl::or_<typename is_composite_state<StateType>::type,
2825 typename is_pseudo_exit<StateType>::type >::type,void >::type
2826 execute_entry(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2828 // simple call to on_entry
2829 astate.on_entry(remove_direct_entry_event_wrapper(evt),fsm);
2831 // variant for exit pseudo states
2832 template <class StateType,class EventType,class FsmType>
2834 typename ::boost::enable_if<typename is_pseudo_exit<StateType>::type,void >::type
2835 execute_entry(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0)
2837 // calls on_entry on the state then forward the event to the transition which should be defined inside the
2839 astate.on_entry(evt,fsm);
2840 astate.forward_event(evt);
2842 template <class StateType,class EventType,class FsmType>
2844 typename ::boost::enable_if<typename is_composite_state<StateType>::type,void >::type
2845 execute_exit(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<0> = 0)
2847 astate.do_exit(evt,fsm);
2849 template <class StateType,class EventType,class FsmType>
2851 typename ::boost::disable_if<typename is_composite_state<StateType>::type,void >::type
2852 execute_exit(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2854 // simple call to on_exit
2855 astate.on_exit(evt,fsm);
2858 // helper allowing special handling of direct entries / fork
2859 template <class StateType,class TargetType,class EventType,class FsmType>
2861 typename ::boost::disable_if<
2862 typename ::boost::mpl::or_<typename has_explicit_entry_state<TargetType>::type,
2863 ::boost::mpl::is_sequence<TargetType> >::type,void>::type
2864 convert_event_and_execute_entry(StateType& astate,EventType const& evt, FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2866 // if the target is a normal state, do the standard entry handling
2867 execute_entry<StateType>(astate,evt,fsm);
2869 template <class StateType,class TargetType,class EventType,class FsmType>
2871 typename ::boost::enable_if<
2872 typename ::boost::mpl::or_<typename has_explicit_entry_state<TargetType>::type,
2873 ::boost::mpl::is_sequence<TargetType> >::type,void >::type
2874 convert_event_and_execute_entry(StateType& astate,EventType const& evt, FsmType& fsm, ::boost::msm::back::dummy<0> = 0)
2876 // for the direct entry, pack the event in a wrapper so that we handle it differently during fsm entry
2877 execute_entry(astate,msm::back::direct_entry_event<TargetType,EventType>(evt),fsm);
2880 // creates all the states
2881 template <class ContainingSM>
2882 void fill_states(ContainingSM* containing_sm=0)
2884 // checks that regions are truly orthogonal
2885 FsmCheckPolicy::template check_orthogonality<library_sm>();
2886 // checks that all states are reachable
2887 FsmCheckPolicy::template check_unreachable_states<library_sm>();
2889 BOOST_STATIC_CONSTANT(int, max_state = (mpl::size<state_list>::value));
2890 // allocate the place without reallocation
2891 m_visitors.fill_visitors(max_state);
2892 ::boost::fusion::for_each(m_substate_list,add_state<ContainingSM>(this,containing_sm));
2897 template <class StateType,class Enable=void>
2898 struct msg_queue_helper
2901 msg_queue_helper():m_events_queue(){}
2902 events_queue_t m_events_queue;
2904 template <class StateType>
2905 struct msg_queue_helper<StateType,
2906 typename ::boost::enable_if<typename is_no_message_queue<StateType>::type >::type>
2910 template <class Fsm,class Stt, class Event, class Compile>
2911 friend struct dispatch_table;
2914 int m_states[nr_regions::value];
2915 msg_queue_helper<library_sm> m_events_queue;
2916 deferred_msg_queue_helper
2917 <library_sm> m_deferred_events_queue;
2918 concrete_history m_history;
2919 bool m_event_processing;
2921 visitor_fct_helper<BaseState> m_visitors;
2922 substate_list m_substate_list;
2927 } } }// boost::msm::back
2928 #endif //BOOST_MSM_BACK_STATEMACHINE_H