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/core/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/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
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>
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(ARG0&& t0,ARG&&... t)
1690 :Derived(std::forward<ARG0>(t0), std::forward<ARG>(t)...)
1692 ,m_deferred_events_queue()
1694 ,m_event_processing(false)
1695 ,m_is_included(false)
1699 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1700 (init_states(m_states));
1701 m_history.set_initial_states(m_states);
1704 template <class Expr,class... ARG,class=typename ::boost::enable_if<typename ::boost::proto::is_expr<Expr>::type >::type>
1705 state_machine(Expr const& expr,ARG&&... t)
1706 :Derived(std::forward<ARG>(t)...)
1708 ,m_deferred_events_queue()
1710 ,m_event_processing(false)
1711 ,m_is_included(false)
1715 BOOST_MPL_ASSERT_MSG(
1716 ( ::boost::proto::matches<Expr, FoldToList>::value),
1717 THE_STATES_EXPRESSION_PASSED_DOES_NOT_MATCH_GRAMMAR,
1719 ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1720 (init_states(m_states));
1721 m_history.set_initial_states(m_states);
1728 // assignment operator using the copy policy to decide if non_copyable, shallow or deep copying is necessary
1729 library_sm& operator= (library_sm const& rhs)
1733 Derived::operator=(rhs);
1738 state_machine(library_sm const& rhs)
1743 // initialize our list of states with the ones defined in Derived::initial_state
1749 // the following 2 functions handle the terminate/interrupt states handling
1750 // if one of these states is found, the first one is used
1751 template <class Event>
1752 bool is_event_handling_blocked_helper( ::boost::mpl::true_ const &)
1754 // if the state machine is terminated, do not handle any event
1755 if (is_flag_active< ::boost::msm::TerminateFlag>())
1757 // if the state machine is interrupted, do not handle any event
1758 // unless the event is the end interrupt event
1759 if ( is_flag_active< ::boost::msm::InterruptedFlag>() &&
1760 !is_flag_active< ::boost::msm::EndInterruptFlag<Event> >())
1764 // otherwise simple handling, no flag => continue
1765 template <class Event>
1766 bool is_event_handling_blocked_helper( ::boost::mpl::false_ const &)
1768 // no terminate/interrupt states detected
1771 void do_handle_prio_msg_queue_deferred_queue(EventSource source, HandledEnum handled, ::boost::mpl::true_ const &)
1773 // non-default. Handle msg queue with higher prio than deferred queue
1774 if (!(EVENT_SOURCE_MSG_QUEUE & source))
1776 do_post_msg_queue_helper(
1777 ::boost::mpl::bool_<
1778 is_no_message_queue<library_sm>::type::value>());
1779 if (!(EVENT_SOURCE_DEFERRED & source))
1781 handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
1782 defer_helper.do_handle_deferred(HANDLED_TRUE & handled);
1786 void do_handle_prio_msg_queue_deferred_queue(EventSource source, HandledEnum handled, ::boost::mpl::false_ const &)
1788 // default. Handle deferred queue with higher prio than msg queue
1789 if (!(EVENT_SOURCE_DEFERRED & source))
1791 handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
1792 defer_helper.do_handle_deferred(HANDLED_TRUE & handled);
1794 // Handle any new events generated into the queue, but only if
1795 // we're not already processing from the message queue.
1796 if (!(EVENT_SOURCE_MSG_QUEUE & source))
1798 do_post_msg_queue_helper(
1799 ::boost::mpl::bool_<
1800 is_no_message_queue<library_sm>::type::value>());
1804 // the following functions handle pre/post-process handling of a message queue
1805 template <class StateType,class EventType>
1806 bool do_pre_msg_queue_helper(EventType const&, ::boost::mpl::true_ const &)
1808 // no message queue needed
1811 template <class StateType,class EventType>
1812 bool do_pre_msg_queue_helper(EventType const& evt, ::boost::mpl::false_ const &)
1814 execute_return (library_sm::*pf) (EventType const&, EventSource) =
1815 &library_sm::process_event_internal;
1817 // if we are already processing an event
1818 if (m_event_processing)
1820 // event has to be put into the queue
1821 m_events_queue.m_events_queue.push_back(
1824 static_cast<EventSource>(EVENT_SOURCE_DIRECT | EVENT_SOURCE_MSG_QUEUE)));
1829 // event can be handled, processing
1830 m_event_processing = true;
1833 void do_post_msg_queue_helper( ::boost::mpl::true_ const &)
1835 // no message queue needed
1837 void do_post_msg_queue_helper( ::boost::mpl::false_ const &)
1839 process_message_queue(this);
1841 void do_allow_event_processing_after_transition( ::boost::mpl::true_ const &)
1843 // no message queue needed
1845 void do_allow_event_processing_after_transition( ::boost::mpl::false_ const &)
1847 m_event_processing = false;
1849 // the following 2 functions handle the processing either with a try/catch protection or without
1850 template <class StateType,class EventType>
1851 HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::true_ const &, bool is_direct_call)
1853 return this->do_process_event(evt,is_direct_call);
1855 template <class StateType,class EventType>
1856 HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::false_ const &, bool is_direct_call)
1858 // when compiling without exception support there is no formal parameter "e" in the catch handler.
1859 // Declaring a local variable here does not hurt and will be "used" to make the code in the handler
1860 // compilable although the code will never be executed.
1864 return this->do_process_event(evt,is_direct_call);
1866 BOOST_CATCH (std::exception& e)
1868 // give a chance to the concrete state machine to handle
1869 this->exception_caught(evt,*this,e);
1872 return HANDLED_TRUE;
1874 // handling of deferred events
1875 // if none is found in the SM, take the following empty main version
1876 template <class StateType, class Enable = int>
1877 struct handle_defer_helper
1879 handle_defer_helper(deferred_msg_queue_helper<library_sm>& ){}
1880 void do_handle_deferred(bool)
1884 // otherwise the standard version handling the deferred events
1885 template <class StateType>
1886 struct handle_defer_helper
1887 <StateType, typename enable_if< typename ::boost::msm::back::has_fsm_deferred_events<StateType>::type,int >::type>
1889 handle_defer_helper(deferred_msg_queue_helper<library_sm>& a_queue):
1890 m_events_queue(a_queue) {}
1891 void do_handle_deferred(bool new_seq=false)
1893 // A new sequence is typically started upon initial entry to the
1894 // state, or upon a new transition. When this occurs we want to
1895 // process all previously deferred events by incrementing the
1896 // correlation sequence.
1899 ++m_events_queue.m_cur_seq;
1902 char& cur_seq = m_events_queue.m_cur_seq;
1904 // Iteratively process all of the events within the deferred
1905 // queue upto (but not including) newly deferred events.
1906 while (!m_events_queue.m_deferred_events_queue.empty())
1908 typename deferred_events_queue_t::value_type& pair =
1909 m_events_queue.m_deferred_events_queue.front();
1911 if (cur_seq != pair.second)
1916 deferred_fct next = pair.first;
1917 m_events_queue.m_deferred_events_queue.pop_front();
1923 deferred_msg_queue_helper<library_sm>& m_events_queue;
1926 // handling of eventless transitions
1927 // if none is found in the SM, nothing to do
1928 template <class StateType, class Enable = void>
1929 struct handle_eventless_transitions_helper
1931 handle_eventless_transitions_helper(library_sm* , bool ){}
1932 void process_completion_event(EventSource = EVENT_SOURCE_DEFAULT){}
1935 template <class StateType>
1936 struct handle_eventless_transitions_helper
1937 <StateType, typename enable_if< typename ::boost::msm::back::has_fsm_eventless_transition<StateType>::type >::type>
1939 handle_eventless_transitions_helper(library_sm* self_, bool handled_):self(self_),handled(handled_){}
1940 void process_completion_event(EventSource source = EVENT_SOURCE_DEFAULT)
1942 typedef typename ::boost::mpl::deref<
1943 typename ::boost::mpl::begin<
1944 typename find_completion_events<StateType>::type
1946 >::type first_completion_event;
1949 self->process_event_internal(
1950 first_completion_event(),
1951 source | EVENT_SOURCE_DIRECT);
1960 // helper class called in case the event to process has been found in the fsm's internal stt and is therefore processable
1961 template<class Event>
1962 struct process_fsm_internal_table
1964 typedef typename ::boost::mpl::has_key<processable_events_internal_table,Event>::type is_event_processable;
1966 // forward to the correct do_process
1967 static void process(Event const& evt,library_sm* self_,HandledEnum& result)
1969 do_process(evt,self_,result,is_event_processable());
1972 // the event is processable, let's try!
1973 static void do_process(Event const& evt,library_sm* self_,HandledEnum& result, ::boost::mpl::true_)
1975 if (result != HANDLED_TRUE)
1977 typedef dispatch_table<library_sm,complete_table,Event,CompilePolicy> table;
1978 HandledEnum res_internal = table::instance.entries[0](*self_, 0, self_->m_states[0], evt);
1979 result = (HandledEnum)((int)result | (int)res_internal);
1982 // version doing nothing if the event is not in the internal stt and we can save ourselves the time trying to process
1983 static void do_process(Event const& ,library_sm* ,HandledEnum& , ::boost::mpl::false_)
1989 template <class StateType,class Enable=void>
1990 struct region_processing_helper
1993 region_processing_helper(library_sm* self_,HandledEnum& result_)
1994 :self(self_),result(result_){}
1995 template<class Event>
1996 void process(Event const& evt)
1998 // use this table as if it came directly from the user
1999 typedef dispatch_table<library_sm,complete_table,Event,CompilePolicy> table;
2000 // +1 because index 0 is reserved for this fsm
2002 table::instance.entries[self->m_states[0]+1](
2003 *self, 0, self->m_states[0], evt);
2004 result = (HandledEnum)((int)result | (int)res);
2005 // process the event in the internal table of this fsm if the event is processable (present in the table)
2006 process_fsm_internal_table<Event>::process(evt,self,result);
2009 HandledEnum& result;
2011 // version with visitors
2012 template <class StateType>
2013 struct region_processing_helper<StateType,typename ::boost::enable_if<
2014 ::boost::mpl::is_sequence<typename StateType::initial_state> >::type>
2017 // process event in one region
2018 template <class region_id,int Dummy=0>
2021 template<class Event>
2022 static void process(Event const& evt,library_sm* self_,HandledEnum& result_)
2024 // use this table as if it came directly from the user
2025 typedef dispatch_table<library_sm,complete_table,Event,CompilePolicy> table;
2026 // +1 because index 0 is reserved for this fsm
2028 table::instance.entries[self_->m_states[region_id::value]+1](
2029 *self_, region_id::value , self_->m_states[region_id::value], evt);
2030 result_ = (HandledEnum)((int)result_ | (int)res);
2031 In< ::boost::mpl::int_<region_id::value+1> >::process(evt,self_,result_);
2034 template <int Dummy>
2035 struct In< ::boost::mpl::int_<nr_regions::value>,Dummy>
2037 // end of processing
2038 template<class Event>
2039 static void process(Event const& evt,library_sm* self_,HandledEnum& result_)
2041 // process the event in the internal table of this fsm if the event is processable (present in the table)
2042 process_fsm_internal_table<Event>::process(evt,self_,result_);
2046 region_processing_helper(library_sm* self_,HandledEnum& result_)
2047 :self(self_),result(result_){}
2048 template<class Event>
2049 void process(Event const& evt)
2051 In< ::boost::mpl::int_<0> >::process(evt,self,result);
2055 HandledEnum& result;
2058 // Main function used internally to make transitions
2059 // Can only be called for internally (for example in an action method) generated events.
2060 template<class Event>
2061 execute_return process_event_internal(Event const& evt,
2062 EventSource source = EVENT_SOURCE_DEFAULT)
2064 // if the state machine has terminate or interrupt flags, check them, otherwise skip
2065 if (is_event_handling_blocked_helper<Event>
2066 ( ::boost::mpl::bool_<has_fsm_blocking_states<library_sm>::type::value>() ) )
2068 return HANDLED_TRUE;
2071 // if a message queue is needed and processing is on the way
2072 if (!do_pre_msg_queue_helper<Event>
2073 (evt,::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>()))
2075 // wait for the end of current processing
2076 return HANDLED_TRUE;
2081 HandledEnum handled = this->do_process_helper<Event>(
2083 ::boost::mpl::bool_<is_no_exception_thrown<library_sm>::type::value>(),
2084 (EVENT_SOURCE_DIRECT & source));
2086 // at this point we allow the next transition be executed without enqueing
2087 // so that completion events and deferred events execute now (if any)
2088 do_allow_event_processing_after_transition(
2089 ::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>());
2091 // Process completion transitions BEFORE any other event in the
2092 // pool (UML Standard 2.3 15.3.14)
2093 handle_eventless_transitions_helper<library_sm>
2094 eventless_helper(this,(HANDLED_TRUE & handled));
2095 eventless_helper.process_completion_event(source);
2097 // After handling, take care of the deferred events, but only if
2098 // we're not already processing from the deferred queue.
2099 do_handle_prio_msg_queue_deferred_queue(
2101 ::boost::mpl::bool_<has_event_queue_before_deferred_queue<library_sm>::type::value>());
2106 // minimum event processing without exceptions, queues, etc.
2107 template<class Event>
2108 HandledEnum do_process_event(Event const& evt, bool is_direct_call)
2110 HandledEnum handled = HANDLED_FALSE;
2112 // dispatch the event to every region
2113 region_processing_helper<Derived> helper(this,handled);
2114 helper.process(evt);
2116 // if the event has not been handled and we have orthogonal zones, then
2117 // generate an error on every active state
2118 // for state machine states contained in other state machines, do not handle
2119 // but let the containing sm handle the error, unless the event was generated in this fsm
2120 // (by calling process_event on this fsm object, is_direct_call == true)
2121 // completion events do not produce an error
2122 if ( (!is_contained() || is_direct_call) && !handled && !is_completion_event<Event>::type::value)
2124 for (int i=0; i<nr_regions::value;++i)
2126 this->no_transition(evt,*this,this->m_states[i]);
2132 // default row arguments for the compilers which accept this
2133 template <class Event>
2134 bool no_guard(Event const&){return true;}
2135 template <class Event>
2136 void no_action(Event const&){}
2138 #ifndef BOOST_NO_RTTI
2139 HandledEnum process_any_event( ::boost::any const& evt);
2143 // composite accept implementation. First calls accept on the composite, then accept on all its active states.
2144 void composite_accept()
2147 this->visit_current_states();
2150 #define MSM_COMPOSITE_ACCEPT_SUB(z, n, unused) ARG ## n vis ## n
2151 #define MSM_COMPOSITE_ACCEPT_SUB2(z, n, unused) boost::ref( vis ## n )
2152 #define MSM_COMPOSITE_ACCEPT_EXECUTE(z, n, unused) \
2153 template <BOOST_PP_ENUM_PARAMS(n, class ARG)> \
2154 void composite_accept(BOOST_PP_ENUM(n, MSM_COMPOSITE_ACCEPT_SUB, ~ ) ) \
2156 this->accept(BOOST_PP_ENUM_PARAMS(n,vis)); \
2157 this->visit_current_states(BOOST_PP_ENUM(n,MSM_COMPOSITE_ACCEPT_SUB2, ~)); \
2159 BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_COMPOSITE_ACCEPT_EXECUTE, ~)
2160 #undef MSM_COMPOSITE_ACCEPT_EXECUTE
2161 #undef MSM_COMPOSITE_ACCEPT_SUB
2162 #undef MSM_COMPOSITE_ACCEPT_SUB2
2164 // helper used to call the init states at the start of the state machine
2165 template <class Event>
2168 call_init(Event const& an_event,library_sm* self_):
2169 evt(an_event),self(self_){}
2170 template <class State>
2171 void operator()(boost::msm::wrap<State> const&)
2173 execute_entry(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
2179 // helper for flag handling. Uses OR by default on orthogonal zones.
2180 template <class Flag,bool orthogonalStates>
2183 static bool helper(library_sm const& sm,flag_handler* )
2185 // by default we use OR to accumulate the flags
2186 return sm.is_flag_active<Flag,Flag_OR>();
2189 template <class Flag>
2190 struct FlagHelper<Flag,false>
2192 static bool helper(library_sm const& sm,flag_handler* flags_entries)
2194 // just one active state, so we can call operator[] with 0
2195 return flags_entries[sm.current_state()[0]](sm);
2199 // defines a true and false functions plus a forwarding one for composite states
2200 template <class StateType,class Flag>
2203 static bool flag_true(library_sm const& )
2207 static bool flag_false(library_sm const& )
2211 static bool forward(library_sm const& fsm)
2213 return ::boost::fusion::at_key<StateType>(fsm.m_substate_list).template is_flag_active<Flag>();
2216 template <class Flag>
2220 // helper function, helps hiding the forward function for non-state machines states.
2222 void helper (flag_handler* an_entry,int offset, ::boost::mpl::true_ const & )
2224 // composite => forward
2225 an_entry[offset] = &FlagHandler<T,Flag>::forward;
2228 void helper (flag_handler* an_entry,int offset, ::boost::mpl::false_ const & )
2231 an_entry[offset] = &FlagHandler<T,Flag>::flag_false;
2234 flag_handler* entries;
2237 init_flags(flag_handler* entries_)
2241 // Flags initializer function object, used with mpl::for_each
2242 template <class StateType>
2243 void operator()( ::boost::msm::wrap<StateType> const& )
2245 typedef typename get_flag_list<StateType>::type flags;
2246 typedef typename ::boost::mpl::contains<flags,Flag >::type found;
2248 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,StateType>::type::value));
2249 if (found::type::value)
2251 // the type defined the flag => true
2252 entries[state_id] = &FlagHandler<StateType,Flag>::flag_true;
2257 typedef typename ::boost::mpl::and_<
2258 typename is_composite_state<StateType>::type,
2259 typename ::boost::mpl::not_<
2260 typename has_non_forwarding_flag<Flag>::type>::type >::type composite_no_forward;
2262 helper<StateType>(entries,state_id,::boost::mpl::bool_<composite_no_forward::type::value>());
2266 // maintains for every flag a static array containing the flag value for every state
2267 template <class Flag>
2268 flag_handler* get_entries_for_flag() const
2270 BOOST_STATIC_CONSTANT(int, max_state = (mpl::size<state_list>::value));
2272 static flag_handler flags_entries[max_state];
2273 // build a state list
2274 ::boost::mpl::for_each<state_list, boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2275 (init_flags<Flag>(flags_entries));
2276 return flags_entries;
2279 // helper used to create a state using the correct constructor
2280 template <class State, class Enable=void>
2281 struct create_state_helper
2283 static void set_sm(library_sm* )
2285 // state doesn't need its sm
2288 // create a state requiring a pointer to the state machine
2289 template <class State>
2290 struct create_state_helper<State,typename boost::enable_if<typename State::needs_sm >::type>
2292 static void set_sm(library_sm* sm)
2294 // create and set the fsm
2295 ::boost::fusion::at_key<State>(sm->m_substate_list).set_sm_ptr(sm);
2298 // main unspecialized helper class
2299 template <class StateType,int ARGS>
2300 struct visitor_args;
2302 #define MSM_VISITOR_ARGS_SUB(z, n, unused) BOOST_PP_CAT(::boost::placeholders::_,BOOST_PP_ADD(n,1))
2303 #define MSM_VISITOR_ARGS_TYPEDEF_SUB(z, n, unused) typename StateType::accept_sig::argument ## n
2305 #define MSM_VISITOR_ARGS_EXECUTE(z, n, unused) \
2306 template <class StateType> \
2307 struct visitor_args<StateType,n> \
2309 template <class State> \
2310 static typename enable_if_c<!is_composite_state<State>::value,void >::type \
2311 helper (library_sm* sm, \
2312 int id,StateType& astate) \
2314 sm->m_visitors.insert(id, boost::bind(&StateType::accept, \
2315 ::boost::ref(astate) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_SUB, ~) )); \
2317 template <class State> \
2318 static typename enable_if_c<is_composite_state<State>::value,void >::type \
2319 helper (library_sm* sm, \
2320 int id,StateType& astate) \
2322 void (StateType::*caccept)(BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_TYPEDEF_SUB, ~ ) ) \
2323 = &StateType::composite_accept; \
2324 sm->m_visitors.insert(id, boost::bind(caccept, \
2325 ::boost::ref(astate) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_SUB, ~) )); \
2328 BOOST_PP_REPEAT(BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_VISITOR_ARGS_EXECUTE, ~)
2329 #undef MSM_VISITOR_ARGS_EXECUTE
2330 #undef MSM_VISITOR_ARGS_SUB
2332 // the IBM compiler seems to have problems with nested classes
2333 // the same seems to apply to the Apple version of gcc 4.0.1 (just in case we do for < 4.1)
2334 // and also to MS VC < 8
2335 #if defined (__IBMCPP__) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2338 template<class ContainingSM>
2339 void set_containing_sm(ContainingSM* sm)
2342 ::boost::fusion::for_each(m_substate_list,add_state<ContainingSM>(this,sm));
2344 #if defined (__IBMCPP__) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2347 // A function object for use with mpl::for_each that stuffs
2348 // states into the state list.
2349 template<class ContainingSM>
2352 add_state(library_sm* self_,ContainingSM* sm)
2353 : self(self_),containing_sm(sm){}
2355 // State is a sub fsm with exit pseudo states and gets a pointer to this fsm, so it can build a callback
2356 template <class StateType>
2357 typename ::boost::enable_if<
2358 typename is_composite_state<StateType>::type,void >::type
2359 new_state_helper(boost::msm::back::dummy<0> = 0) const
2361 ::boost::fusion::at_key<StateType>(self->m_substate_list).set_containing_sm(containing_sm);
2363 // State is a sub fsm without exit pseudo states and does not get a callback to this fsm
2364 // or state is a normal state and needs nothing except creation
2365 template <class StateType>
2366 typename ::boost::enable_if<
2367 typename boost::mpl::and_<typename boost::mpl::not_
2368 <typename is_composite_state<StateType>::type>::type,
2369 typename boost::mpl::not_
2370 <typename is_pseudo_exit<StateType>::type>::type
2372 new_state_helper( ::boost::msm::back::dummy<1> = 0) const
2376 // state is exit pseudo state and gets callback to target fsm
2377 template <class StateType>
2378 typename ::boost::enable_if<typename is_pseudo_exit<StateType>::type,void >::type
2379 new_state_helper( ::boost::msm::back::dummy<2> = 0) const
2381 execute_return (ContainingSM::*pf) (typename StateType::event const& evt)=
2382 &ContainingSM::process_event;
2383 ::boost::function<execute_return (typename StateType::event const&)> fct =
2384 ::boost::bind(pf,containing_sm,::boost::placeholders::_1);
2385 ::boost::fusion::at_key<StateType>(self->m_substate_list).set_forward_fct(fct);
2387 // for every defined state in the sm
2388 template <class State>
2389 void operator()( State const&) const
2391 //create a new state with the defined id and type
2392 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,State>::value));
2394 this->new_state_helper<State>(),
2395 create_state_helper<State>::set_sm(self);
2396 // create a visitor callback
2397 visitor_helper(state_id,::boost::fusion::at_key<State>(self->m_substate_list),
2398 ::boost::mpl::bool_<has_accept_sig<State>::type::value>());
2401 // support possible use of a visitor if accept_sig is defined
2402 template <class StateType>
2403 void visitor_helper(int id,StateType& astate, ::boost::mpl::true_ const & ) const
2405 visitor_args<StateType,StateType::accept_sig::args_number>::
2406 template helper<StateType>(self,id,astate);
2408 template <class StateType>
2409 void visitor_helper(int ,StateType& , ::boost::mpl::false_ const &) const
2415 ContainingSM* containing_sm;
2418 // helper used to copy every state if needed
2421 copy_helper(library_sm* sm):
2423 template <class StateType>
2424 void operator()( ::boost::msm::wrap<StateType> const& )
2426 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,StateType>::type::value));
2427 // possibly also set the visitor
2428 visitor_helper<StateType>(state_id);
2430 // and for states that keep a pointer to the fsm, reset the pointer
2431 create_state_helper<StateType>::set_sm(m_sm);
2433 template <class StateType>
2434 typename ::boost::enable_if<typename has_accept_sig<StateType>::type,void >::type
2435 visitor_helper(int id) const
2437 visitor_args<StateType,StateType::accept_sig::args_number>::template helper<StateType>
2438 (m_sm,id,::boost::fusion::at_key<StateType>(m_sm->m_substate_list));
2440 template <class StateType>
2441 typename ::boost::disable_if<typename has_accept_sig<StateType>::type,void >::type
2442 visitor_helper(int) const
2449 // helper to copy the active states attribute
2450 template <class region_id,int Dummy=0>
2451 struct region_copy_helper
2453 static void do_copy(library_sm* self_,library_sm const& rhs)
2455 self_->m_states[region_id::value] = rhs.m_states[region_id::value];
2456 region_copy_helper< ::boost::mpl::int_<region_id::value+1> >::do_copy(self_,rhs);
2459 template <int Dummy>
2460 struct region_copy_helper< ::boost::mpl::int_<nr_regions::value>,Dummy>
2462 // end of processing
2463 static void do_copy(library_sm*,library_sm const& ){}
2465 // copy functions for deep copy (no need of a 2nd version for NoCopy as noncopyable handles it)
2466 void do_copy (library_sm const& rhs,
2467 ::boost::msm::back::dummy<0> = 0)
2469 // deep copy simply assigns the data
2470 region_copy_helper< ::boost::mpl::int_<0> >::do_copy(this,rhs);
2471 m_events_queue = rhs.m_events_queue;
2472 m_deferred_events_queue = rhs.m_deferred_events_queue;
2473 m_history = rhs.m_history;
2474 m_event_processing = rhs.m_event_processing;
2475 m_is_included = rhs.m_is_included;
2476 m_substate_list = rhs.m_substate_list;
2477 // except for the states themselves, which get duplicated
2479 ::boost::mpl::for_each<state_list, ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2480 (copy_helper(this));
2483 // helper used to call the correct entry/exit method
2484 // unfortunately in O(number of states in the sub-sm) but should be better than a virtual call
2485 template<class Event,bool is_entry>
2486 struct entry_exit_helper
2488 entry_exit_helper(int id,Event const& e,library_sm* self_):
2489 state_id(id),evt(e),self(self_){}
2490 // helper for entry actions
2491 template <class IsEntry,class State>
2492 typename ::boost::enable_if<typename IsEntry::type,void >::type
2493 helper( ::boost::msm::back::dummy<0> = 0)
2495 BOOST_STATIC_CONSTANT(int, id = (get_state_id<stt,State>::value));
2498 execute_entry<State>(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
2501 // helper for exit actions
2502 template <class IsEntry,class State>
2503 typename boost::disable_if<typename IsEntry::type,void >::type
2504 helper( ::boost::msm::back::dummy<1> = 0)
2506 BOOST_STATIC_CONSTANT(int, id = (get_state_id<stt,State>::value));
2509 execute_exit<State>(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
2512 // iterates through all states to find the one to be activated
2513 template <class State>
2514 void operator()( ::boost::msm::wrap<State> const&)
2516 entry_exit_helper<Event,is_entry>::template helper< ::boost::mpl::bool_<is_entry>,State >();
2524 // helper to start the fsm
2525 template <class region_id,int Dummy=0>
2526 struct region_start_helper
2528 template<class Event>
2529 static void do_start(library_sm* self_,Event const& incomingEvent)
2531 //forward the event for handling by sub state machines
2532 ::boost::mpl::for_each<state_list, ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2533 (entry_exit_helper<Event,true>(self_->m_states[region_id::value],incomingEvent,self_));
2535 < ::boost::mpl::int_<region_id::value+1> >::do_start(self_,incomingEvent);
2538 template <int Dummy>
2539 struct region_start_helper< ::boost::mpl::int_<nr_regions::value>,Dummy>
2541 // end of processing
2542 template<class Event>
2543 static void do_start(library_sm*,Event const& ){}
2545 // start for states machines which are themselves embedded in other state machines (composites)
2546 template <class Event>
2547 void internal_start(Event const& incomingEvent)
2549 region_start_helper< ::boost::mpl::int_<0> >::do_start(this,incomingEvent);
2550 // give a chance to handle an anonymous (eventless) transition
2551 handle_eventless_transitions_helper<library_sm> eventless_helper(this,true);
2552 eventless_helper.process_completion_event();
2555 template <class StateType>
2556 struct find_region_id
2558 template <int region,int Dummy=0>
2561 enum {region_index=region};
2563 // if the user provides no region, find it!
2567 typedef typename build_orthogonal_regions<
2570 >::type all_regions;
2571 enum {region_index= find_region_index<all_regions,StateType>::value };
2573 enum {region_index = In<StateType::zone_index>::region_index };
2575 // helper used to set the correct state as active state upon entry into a fsm
2576 struct direct_event_start_helper
2578 direct_event_start_helper(library_sm* self_):self(self_){}
2579 // this variant is for the standard case, entry due to activation of the containing FSM
2580 template <class EventType,class FsmType>
2581 typename ::boost::disable_if<typename has_direct_entry<EventType>::type,void>::type
2582 operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<0> = 0)
2584 (static_cast<Derived*>(self))->on_entry(evt,fsm);
2585 self->internal_start(evt);
2588 // this variant is for the direct entry case (just one entry, not a sequence of entries)
2589 template <class EventType,class FsmType>
2590 typename ::boost::enable_if<
2591 typename ::boost::mpl::and_<
2592 typename ::boost::mpl::not_< typename is_pseudo_entry<
2593 typename EventType::active_state>::type >::type,
2594 typename ::boost::mpl::and_<typename has_direct_entry<EventType>::type,
2595 typename ::boost::mpl::not_<typename ::boost::mpl::is_sequence
2596 <typename EventType::active_state>::type >::type
2599 operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2601 (static_cast<Derived*>(self))->on_entry(evt,fsm);
2602 int state_id = get_state_id<stt,typename EventType::active_state::wrapped_entry>::value;
2603 BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index >= 0);
2604 BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index < nr_regions::value);
2605 // just set the correct zone, the others will be default/history initialized
2606 self->m_states[find_region_id<typename EventType::active_state::wrapped_entry>::region_index] = state_id;
2607 self->internal_start(evt.m_event);
2610 // this variant is for the fork entry case (a sequence on entries)
2611 template <class EventType,class FsmType>
2612 typename ::boost::enable_if<
2613 typename ::boost::mpl::and_<
2614 typename ::boost::mpl::not_<
2615 typename is_pseudo_entry<typename EventType::active_state>::type >::type,
2616 typename ::boost::mpl::and_<typename has_direct_entry<EventType>::type,
2617 typename ::boost::mpl::is_sequence<
2618 typename EventType::active_state>::type
2621 operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0)
2623 (static_cast<Derived*>(self))->on_entry(evt,fsm);
2624 ::boost::mpl::for_each<typename EventType::active_state,
2625 ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2626 (fork_helper<EventType>(self,evt));
2627 // set the correct zones, the others (if any) will be default/history initialized
2628 self->internal_start(evt.m_event);
2631 // this variant is for the pseudo state entry case
2632 template <class EventType,class FsmType>
2633 typename ::boost::enable_if<
2634 typename is_pseudo_entry<typename EventType::active_state >::type,void
2636 operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<3> = 0)
2639 (static_cast<Derived*>(self))->on_entry(evt,fsm);
2640 int state_id = get_state_id<stt,typename EventType::active_state::wrapped_entry>::value;
2641 BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index >= 0);
2642 BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index < nr_regions::value);
2643 // given region starts with the entry pseudo state as active state
2644 self->m_states[find_region_id<typename EventType::active_state::wrapped_entry>::region_index] = state_id;
2645 self->internal_start(evt.m_event);
2646 // and we process the transition in the zone of the newly active state
2647 // (entry pseudo states are, according to UML, a state connecting 1 transition outside to 1 inside
2648 self->process_event(evt.m_event);
2651 // helper for the fork case, does almost like the direct entry
2653 template <class EventType>
2656 fork_helper(library_sm* self_,EventType const& evt_):
2657 helper_self(self_),helper_evt(evt_){}
2658 template <class StateType>
2659 void operator()( ::boost::msm::wrap<StateType> const& )
2661 int state_id = get_state_id<stt,typename StateType::wrapped_entry>::value;
2662 BOOST_STATIC_ASSERT(find_region_id<typename StateType::wrapped_entry>::region_index >= 0);
2663 BOOST_STATIC_ASSERT(find_region_id<typename StateType::wrapped_entry>::region_index < nr_regions::value);
2664 helper_self->m_states[find_region_id<typename StateType::wrapped_entry>::region_index] = state_id;
2667 library_sm* helper_self;
2668 EventType const& helper_evt;
2673 template <class region_id,int Dummy=0>
2674 struct region_entry_exit_helper
2676 template<class Event>
2677 static void do_entry(library_sm* self_,Event const& incomingEvent)
2679 self_->m_states[region_id::value] =
2680 self_->m_history.history_entry(incomingEvent)[region_id::value];
2681 region_entry_exit_helper
2682 < ::boost::mpl::int_<region_id::value+1> >::do_entry(self_,incomingEvent);
2684 template<class Event>
2685 static void do_exit(library_sm* self_,Event const& incomingEvent)
2687 ::boost::mpl::for_each<state_list, ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2688 (entry_exit_helper<Event,false>(self_->m_states[region_id::value],incomingEvent,self_));
2689 region_entry_exit_helper
2690 < ::boost::mpl::int_<region_id::value+1> >::do_exit(self_,incomingEvent);
2693 template <int Dummy>
2694 struct region_entry_exit_helper< ::boost::mpl::int_<nr_regions::value>,Dummy>
2696 // end of processing
2697 template<class Event>
2698 static void do_entry(library_sm*,Event const& ){}
2699 template<class Event>
2700 static void do_exit(library_sm*,Event const& ){}
2702 // entry/exit for states machines which are themselves embedded in other state machines (composites)
2703 template <class Event,class FsmType>
2704 void do_entry(Event const& incomingEvent,FsmType& fsm)
2706 // by default we activate the history/init states, can be overwritten by direct_event_start_helper
2707 region_entry_exit_helper< ::boost::mpl::int_<0> >::do_entry(this,incomingEvent);
2708 // block immediate handling of events
2709 m_event_processing = true;
2710 // if the event is generating a direct entry/fork, set the current state(s) to the direct state(s)
2711 direct_event_start_helper(this)(incomingEvent,fsm);
2712 // handle messages which were generated and blocked in the init calls
2713 m_event_processing = false;
2714 // look for deferred events waiting
2715 handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
2716 defer_helper.do_handle_deferred(true);
2717 process_message_queue(this);
2719 template <class Event,class FsmType>
2720 void do_exit(Event const& incomingEvent,FsmType& fsm)
2722 // first recursively exit the sub machines
2723 // forward the event for handling by sub state machines
2724 region_entry_exit_helper< ::boost::mpl::int_<0> >::do_exit(this,incomingEvent);
2725 // then call our own exit
2726 (static_cast<Derived*>(this))->on_exit(incomingEvent,fsm);
2727 // give the history a chance to handle this (or not).
2728 m_history.history_exit(this->m_states);
2729 // history decides what happens with deferred events
2730 if (!m_history.process_deferred_events(incomingEvent))
2732 clear_deferred_queue();
2736 // the IBM and VC<8 compilers seem to have problems with the friend declaration of dispatch_table
2737 #if defined (__IBMCPP__) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2740 // no transition for event.
2741 template <class Event>
2742 static HandledEnum call_no_transition(library_sm& , int , int , Event const& )
2744 return HANDLED_FALSE;
2746 // no transition for event for internal transitions (not an error).
2747 template <class Event>
2748 static HandledEnum call_no_transition_internal(library_sm& , int , int , Event const& )
2750 //// reject to give others a chance to handle
2751 //return HANDLED_GUARD_REJECT;
2752 return HANDLED_FALSE;
2754 // called for deferred events. Address set in the dispatch_table at init
2755 template <class Event>
2756 static HandledEnum defer_transition(library_sm& fsm, int , int , Event const& e)
2759 return HANDLED_DEFERRED;
2761 // called for completion events. Default address set in the dispatch_table at init
2762 // prevents no-transition detection for completion events
2763 template <class Event>
2764 static HandledEnum default_eventless_transition(library_sm&, int, int , Event const&)
2766 return HANDLED_FALSE;
2768 #if defined (__IBMCPP__) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2771 // removes one event from the message queue and processes it
2772 template <class StateType>
2773 void process_message_queue(StateType*,
2774 typename ::boost::disable_if<typename is_no_message_queue<StateType>::type,void >::type* = 0)
2776 // Iteratively process all events from the message queue.
2777 while (!m_events_queue.m_events_queue.empty())
2779 transition_fct next = m_events_queue.m_events_queue.front();
2780 m_events_queue.m_events_queue.pop_front();
2784 template <class StateType>
2785 void process_message_queue(StateType*,
2786 typename ::boost::enable_if<typename is_no_message_queue<StateType>::type,void >::type* = 0)
2788 // nothing to process
2790 // helper function. In cases where the event is wrapped (target is a direct entry states)
2791 // we want to send only the real event to on_entry, not the wrapper.
2792 template <class EventType>
2794 typename boost::enable_if<typename has_direct_entry<EventType>::type,typename EventType::contained_event const& >::type
2795 remove_direct_entry_event_wrapper(EventType const& evt,boost::msm::back::dummy<0> = 0)
2799 template <class EventType>
2800 static typename boost::disable_if<typename has_direct_entry<EventType>::type,EventType const& >::type
2801 remove_direct_entry_event_wrapper(EventType const& evt,boost::msm::back::dummy<1> = 0)
2803 // identity. No wrapper
2806 // calls the entry/exit or on_entry/on_exit depending on the state type
2807 // (avoids calling virtually)
2809 template <class StateType,class EventType,class FsmType>
2811 typename boost::enable_if<typename is_composite_state<StateType>::type,void >::type
2812 execute_entry(StateType& astate,EventType const& evt,FsmType& fsm,boost::msm::back::dummy<0> = 0)
2814 // calls on_entry on the fsm then handles direct entries, fork, entry pseudo state
2815 astate.do_entry(evt,fsm);
2817 // variant for states
2818 template <class StateType,class EventType,class FsmType>
2820 typename ::boost::disable_if<
2821 typename ::boost::mpl::or_<typename is_composite_state<StateType>::type,
2822 typename is_pseudo_exit<StateType>::type >::type,void >::type
2823 execute_entry(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2825 // simple call to on_entry
2826 astate.on_entry(remove_direct_entry_event_wrapper(evt),fsm);
2828 // variant for exit pseudo states
2829 template <class StateType,class EventType,class FsmType>
2831 typename ::boost::enable_if<typename is_pseudo_exit<StateType>::type,void >::type
2832 execute_entry(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0)
2834 // calls on_entry on the state then forward the event to the transition which should be defined inside the
2836 astate.on_entry(evt,fsm);
2837 astate.forward_event(evt);
2839 template <class StateType,class EventType,class FsmType>
2841 typename ::boost::enable_if<typename is_composite_state<StateType>::type,void >::type
2842 execute_exit(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<0> = 0)
2844 astate.do_exit(evt,fsm);
2846 template <class StateType,class EventType,class FsmType>
2848 typename ::boost::disable_if<typename is_composite_state<StateType>::type,void >::type
2849 execute_exit(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2851 // simple call to on_exit
2852 astate.on_exit(evt,fsm);
2855 // helper allowing special handling of direct entries / fork
2856 template <class StateType,class TargetType,class EventType,class FsmType>
2858 typename ::boost::disable_if<
2859 typename ::boost::mpl::or_<typename has_explicit_entry_state<TargetType>::type,
2860 ::boost::mpl::is_sequence<TargetType> >::type,void>::type
2861 convert_event_and_execute_entry(StateType& astate,EventType const& evt, FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2863 // if the target is a normal state, do the standard entry handling
2864 execute_entry<StateType>(astate,evt,fsm);
2866 template <class StateType,class TargetType,class EventType,class FsmType>
2868 typename ::boost::enable_if<
2869 typename ::boost::mpl::or_<typename has_explicit_entry_state<TargetType>::type,
2870 ::boost::mpl::is_sequence<TargetType> >::type,void >::type
2871 convert_event_and_execute_entry(StateType& astate,EventType const& evt, FsmType& fsm, ::boost::msm::back::dummy<0> = 0)
2873 // for the direct entry, pack the event in a wrapper so that we handle it differently during fsm entry
2874 execute_entry(astate,msm::back::direct_entry_event<TargetType,EventType>(evt),fsm);
2877 // creates all the states
2878 template <class ContainingSM>
2879 void fill_states(ContainingSM* containing_sm=0)
2881 // checks that regions are truly orthogonal
2882 FsmCheckPolicy::template check_orthogonality<library_sm>();
2883 // checks that all states are reachable
2884 FsmCheckPolicy::template check_unreachable_states<library_sm>();
2886 BOOST_STATIC_CONSTANT(int, max_state = (mpl::size<state_list>::value));
2887 // allocate the place without reallocation
2888 m_visitors.fill_visitors(max_state);
2889 ::boost::fusion::for_each(m_substate_list,add_state<ContainingSM>(this,containing_sm));
2894 template <class StateType,class Enable=void>
2895 struct msg_queue_helper
2898 msg_queue_helper():m_events_queue(){}
2899 events_queue_t m_events_queue;
2901 template <class StateType>
2902 struct msg_queue_helper<StateType,
2903 typename ::boost::enable_if<typename is_no_message_queue<StateType>::type >::type>
2907 template <class Fsm,class Stt, class Event, class Compile>
2908 friend struct dispatch_table;
2911 int m_states[nr_regions::value];
2912 msg_queue_helper<library_sm> m_events_queue;
2913 deferred_msg_queue_helper
2914 <library_sm> m_deferred_events_queue;
2915 concrete_history m_history;
2916 bool m_event_processing;
2918 visitor_fct_helper<BaseState> m_visitors;
2919 substate_list m_substate_list;
2924 } } }// boost::msm::back
2925 #endif //BOOST_MSM_BACK_STATEMACHINE_H