1 // Copyright 2008 Christophe Henry
2 // henry UNDERSCORE christophe AT hotmail DOT com
3 // This is an extended version of the state machine available in the boost::mpl library
4 // Distributed under the same license as the original.
5 // Copyright for the original version:
6 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
7 // under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 
11 #ifndef BOOST_MSM_BACK_STATEMACHINE_H
12 #define BOOST_MSM_BACK_STATEMACHINE_H
13 
14 #include <exception>
15 #include <vector>
16 #include <functional>
17 #include <numeric>
18 #include <utility>
19 
20 #include <boost/detail/no_exceptions_support.hpp>
21 
22 #include <boost/mpl/contains.hpp>
23 #include <boost/mpl/deref.hpp>
24 #include <boost/mpl/assert.hpp>
25 
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>
37 
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>
43 
44 #include <boost/bind.hpp>
45 #include <boost/bind/apply.hpp>
46 #include <boost/function.hpp>
47 #ifndef BOOST_NO_RTTI
48 #include <boost/any.hpp>
49 #endif
50 
51 #include <boost/serialization/base_object.hpp>
52 
53 #include <boost/parameter.hpp>
54 
55 #include <boost/msm/active_state_switching_policies.hpp>
56 #include <boost/msm/row_tags.hpp>
57 #include <boost/msm/msm_grammar.hpp>
58 #include <boost/msm/back/fold_to_list.hpp>
59 #include <boost/msm/back/metafunctions.hpp>
60 #include <boost/msm/back/history_policies.hpp>
61 #include <boost/msm/back/common_types.hpp>
62 #include <boost/msm/back/args.hpp>
63 #include <boost/msm/back/default_compile_policy.hpp>
64 #include <boost/msm/back/dispatch_table.hpp>
65 #include <boost/msm/back/no_fsm_check.hpp>
66 #include <boost/msm/back/queue_container_deque.hpp>
67 
68 BOOST_MPL_HAS_XXX_TRAIT_DEF(accept_sig)
69 BOOST_MPL_HAS_XXX_TRAIT_DEF(no_automatic_create)
70 BOOST_MPL_HAS_XXX_TRAIT_DEF(non_forwarding_flag)
71 BOOST_MPL_HAS_XXX_TRAIT_DEF(direct_entry)
72 BOOST_MPL_HAS_XXX_TRAIT_DEF(initial_event)
73 BOOST_MPL_HAS_XXX_TRAIT_DEF(final_event)
74 BOOST_MPL_HAS_XXX_TRAIT_DEF(do_serialize)
75 BOOST_MPL_HAS_XXX_TRAIT_DEF(history_policy)
76 BOOST_MPL_HAS_XXX_TRAIT_DEF(fsm_check)
77 BOOST_MPL_HAS_XXX_TRAIT_DEF(compile_policy)
78 BOOST_MPL_HAS_XXX_TRAIT_DEF(queue_container_policy)
79 BOOST_MPL_HAS_XXX_TRAIT_DEF(using_declared_table)
80 
81 #ifndef BOOST_MSM_CONSTRUCTOR_ARG_SIZE
82 #define BOOST_MSM_CONSTRUCTOR_ARG_SIZE 5 // default max number of arguments for constructors
83 #endif
84 
85 namespace boost { namespace msm { namespace back
86 {
87 // event used internally for wrapping a direct entry
88 template <class StateType,class Event>
89 struct direct_entry_event
90 {
91     typedef int direct_entry;
92     typedef StateType active_state;
93     typedef Event contained_event;
94 
direct_entry_eventboost::msm::back::direct_entry_event95     direct_entry_event(Event const& evt):m_event(evt){}
96     Event const& m_event;
97 };
98 
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;
103 
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)
109 
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::_ >
114     >
115   , ::boost::parameter::optional<
116         ::boost::parameter::deduced< ::boost::msm::back::tag::compile_policy>, has_compile_policy< ::boost::mpl::_ >
117     >
118   , ::boost::parameter::optional<
119         ::boost::parameter::deduced< ::boost::msm::back::tag::fsm_check_policy>, has_fsm_check< ::boost::mpl::_ >
120     >
121   , ::boost::parameter::optional<
122         ::boost::parameter::deduced< ::boost::msm::back::tag::queue_container_policy>,
123         has_queue_container_policy< ::boost::mpl::_ >
124     >
125 > state_machine_signature;
126 
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>
132 {};
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>
136 {};
137 
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 >
141 template <
142       class A0
143     , class A1 = parameter::void_
144     , class A2 = parameter::void_
145     , class A3 = parameter::void_
146     , class A4 = parameter::void_
147 >
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
151     >::type
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
155                          >::type
156       >
157 {
158 public:
159     // Create ArgumentPack
160     typedef typename
161         state_machine_signature::bind<A0,A1,A2,A3,A4>::type
162         state_machine_args;
163 
164     // Extract first logical parameter.
165     typedef typename ::boost::parameter::binding<
166         state_machine_args, ::boost::msm::back::tag::front_end>::type Derived;
167 
168     typedef typename ::boost::parameter::binding<
169         state_machine_args, ::boost::msm::back::tag::history_policy, NoHistory >::type              HistoryPolicy;
170 
171     typedef typename ::boost::parameter::binding<
172         state_machine_args, ::boost::msm::back::tag::compile_policy, favor_runtime_speed >::type    CompilePolicy;
173 
174     typedef typename ::boost::parameter::binding<
175         state_machine_args, ::boost::msm::back::tag::fsm_check_policy, no_fsm_check >::type         FsmCheckPolicy;
176 
177     typedef typename ::boost::parameter::binding<
178         state_machine_args, ::boost::msm::back::tag::queue_container_policy,
179         queue_container_deque >::type                                                               QueueContainerPolicy;
180 
181 private:
182 
183     typedef boost::msm::back::state_machine<
184         A0,A1,A2,A3,A4>                             library_sm;
185 
186     typedef ::boost::function<
187         execute_return ()>                          transition_fct;
188     typedef ::boost::function<
189         execute_return () >                         deferred_fct;
190     typedef typename QueueContainerPolicy::
191         template In<
192         std::pair<deferred_fct,bool> >::type        deferred_events_queue_t;
193     typedef typename QueueContainerPolicy::
194         template In<transition_fct>::type           events_queue_t;
195 
196     typedef typename boost::mpl::eval_if<
197         typename is_active_state_switch_policy<Derived>::type,
198         get_active_state_switch_policy<Derived>,
199         // default
200         ::boost::mpl::identity<active_state_switch_after_entry>
201     >::type active_state_switching;
202 
203     typedef bool (*flag_handler)(library_sm const&);
204 
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;
208 
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
213     {
214     public:
visitor_fct_helperboost::msm::back::state_machine::visitor_fct_helper215         visitor_fct_helper(){}
fill_visitorsboost::msm::back::state_machine::visitor_fct_helper216         void fill_visitors(int)
217         {
218         }
219         template <class FCT>
insertboost::msm::back::state_machine::visitor_fct_helper220         void insert(int,FCT)
221         {
222         }
223         template <class VISITOR>
executeboost::msm::back::state_machine::visitor_fct_helper224         void execute(int,VISITOR)
225         {
226         }
227     };
228     // version with visitors
229     template <class StateType>
230     struct visitor_fct_helper<StateType,typename ::boost::enable_if<has_accept_sig<StateType> >::type>
231     {
232     public:
visitor_fct_helperboost::msm::back::state_machine::visitor_fct_helper233         visitor_fct_helper():m_state_visitors(){}
fill_visitorsboost::msm::back::state_machine::visitor_fct_helper234         void fill_visitors(int number_of_states)
235         {
236             m_state_visitors.resize(number_of_states);
237         }
238         template <class FCT>
insertboost::msm::back::state_machine::visitor_fct_helper239         void insert(int index,FCT fct)
240         {
241             m_state_visitors[index]=fct;
242         }
executeboost::msm::back::state_machine::visitor_fct_helper243         void execute(int index)
244         {
245             m_state_visitors[index]();
246         }
247 
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, ~ ) )         \
253         {                                                                           \
254             m_state_visitors[index](BOOST_PP_ENUM_PARAMS(n,vis));                   \
255         }
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
259     private:
260         typedef typename StateType::accept_sig::type                  visitor_fct;
261         typedef std::vector<visitor_fct>                              visitors;
262 
263         visitors                                                      m_state_visitors;
264     };
265 
266     template <class StateType,class Enable=int>
267     struct deferred_msg_queue_helper
268     {
clearboost::msm::back::state_machine::deferred_msg_queue_helper269         void clear(){}
270     };
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>
275     {
276     public:
deferred_msg_queue_helperboost::msm::back::state_machine::deferred_msg_queue_helper277         deferred_msg_queue_helper():m_deferred_events_queue(){}
clearboost::msm::back::state_machine::deferred_msg_queue_helper278         void clear()
279         {
280             m_deferred_events_queue.clear();
281         }
282         deferred_events_queue_t         m_deferred_events_queue;
283     };
284 
285  public:
286     // tags
287     typedef int composite_tag;
288 
289     // in case someone needs to know
290     typedef HistoryPolicy               history_policy;
291 
292     struct InitEvent { };
293     struct ExitEvent { };
294     // flag handling
295     struct Flag_AND
296     {
297         typedef std::logical_and<bool> type;
298     };
299     struct Flag_OR
300     {
301      typedef std::logical_or<bool> type;
302     };
303     typedef typename Derived::BaseAllStates     BaseState;
304     typedef Derived                             ConcreteSM;
305 
306     // if the front-end fsm provides an initial_event typedef, replace InitEvent by this one
307     typedef typename ::boost::mpl::eval_if<
308         typename has_initial_event<Derived>::type,
309         get_initial_event<Derived>,
310         ::boost::mpl::identity<InitEvent>
311     >::type fsm_initial_event;
312 
313     // if the front-end fsm provides an exit_event typedef, replace ExitEvent by this one
314     typedef typename ::boost::mpl::eval_if<
315         typename has_final_event<Derived>::type,
316         get_final_event<Derived>,
317         ::boost::mpl::identity<ExitEvent>
318     >::type fsm_final_event;
319 
320     template <class ExitPoint>
321     struct exit_pt : public ExitPoint
322     {
323         // tags
324         typedef ExitPoint           wrapped_exit;
325         typedef int                 pseudo_exit;
326         typedef library_sm          owner;
327         typedef int                 no_automatic_create;
328         typedef typename
329             ExitPoint::event        Event;
330         typedef ::boost::function<execute_return (Event const&)>
331                                     forwarding_function;
332 
333         // forward event to the higher-level FSM
334         template <class ForwardEvent>
forward_eventboost::msm::back::state_machine::exit_pt335         void forward_event(ForwardEvent const& incomingEvent)
336         {
337             // use helper to forward or not
338             ForwardHelper< ::boost::is_convertible<ForwardEvent,Event>::value>::helper(incomingEvent,m_forward);
339         }
set_forward_fctboost::msm::back::state_machine::exit_pt340         void set_forward_fct(::boost::function<execute_return (Event const&)> fct)
341         {
342             m_forward = fct;
343         }
exit_ptboost::msm::back::state_machine::exit_pt344         exit_pt():m_forward(){}
345         // by assignments, we keep our forwarding functor unchanged as our containing SM did not change
346     template <class RHS>
exit_ptboost::msm::back::state_machine::exit_pt347         exit_pt(RHS&):m_forward(){}
operator =boost::msm::back::state_machine::exit_pt348         exit_pt<ExitPoint>& operator= (const exit_pt<ExitPoint>& )
349         {
350             return *this;
351         }
352     private:
353          forwarding_function          m_forward;
354 
355          // using partial specialization instead of enable_if because of VC8 bug
356         template <bool OwnEvent, int Dummy=0>
357         struct ForwardHelper
358         {
359             template <class ForwardEvent>
helperboost::msm::back::state_machine::exit_pt::ForwardHelper360             static void helper(ForwardEvent const& ,forwarding_function& )
361             {
362                 // Not our event, assert
363                 BOOST_ASSERT(false);
364             }
365         };
366         template <int Dummy>
367         struct ForwardHelper<true,Dummy>
368         {
369             template <class ForwardEvent>
helperboost::msm::back::state_machine::exit_pt::ForwardHelper370             static void helper(ForwardEvent const& incomingEvent,forwarding_function& forward_fct)
371             {
372                 // call if handler set, if not, this state is simply a terminate state
373                 if (forward_fct)
374                     forward_fct(incomingEvent);
375             }
376         };
377 
378     };
379     template <class EntryPoint>
380     struct entry_pt : public EntryPoint
381     {
382         // tags
383         typedef EntryPoint          wrapped_entry;
384         typedef int                 pseudo_entry;
385         typedef library_sm          owner;
386         typedef int                 no_automatic_create;
387     };
388     template <class EntryPoint>
389     struct direct : public EntryPoint
390     {
391         // tags
392         typedef EntryPoint          wrapped_entry;
393         typedef int                 explicit_entry_state;
394         typedef library_sm          owner;
395         typedef int                 no_automatic_create;
396     };
397     typedef typename get_number_of_regions<typename Derived::initial_state>::type nr_regions;
398     // Template used to form rows in the transition table
399     template<
400         typename ROW
401     >
402     struct row_
403     {
404         //typedef typename ROW::Source T1;
405         typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
406         typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
407         typedef typename ROW::Evt transition_event;
408         // if the source is an exit pseudo state, then
409         // current_state_type becomes the result of get_owner
410         // meaning the containing SM from which the exit occurs
411         typedef typename ::boost::mpl::eval_if<
412                 typename has_pseudo_exit<T1>::type,
413                 get_owner<T1,library_sm>,
414                 ::boost::mpl::identity<typename ROW::Source> >::type current_state_type;
415 
416         // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry
417         // else if Target is an explicit_entry, next_state_type becomes the result of get_owner
418         // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself
419         typedef typename ::boost::mpl::eval_if<
420             typename ::boost::mpl::is_sequence<T2>::type,
421             get_fork_owner<T2,library_sm>,
422             ::boost::mpl::eval_if<
423                     typename has_no_automatic_create<T2>::type,
424                     get_owner<T2,library_sm>,
425                     ::boost::mpl::identity<T2> >
426         >::type next_state_type;
427 
428         // if a guard condition is here, call it to check that the event is accepted
check_guardboost::msm::back::state_machine::row_429         static bool check_guard(library_sm& fsm,transition_event const& evt)
430         {
431             if ( ROW::guard_call(fsm,evt,
432                                  ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
433                                  ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
434                                  fsm.m_substate_list ) )
435                 return true;
436             return false;
437         }
438         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::row_439         static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt)
440         {
441 
442             BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
443             BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
444             BOOST_ASSERT(state == (current_state));
445             // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
446             if (has_pseudo_exit<T1>::type::value &&
447                 !is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
448             {
449                 return HANDLED_FALSE;
450             }
451             if (!check_guard(fsm,evt))
452             {
453                 // guard rejected the event, we stay in the current one
454                 return HANDLED_GUARD_REJECT;
455             }
456             fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state);
457 
458             // the guard condition has already been checked
459             execute_exit<current_state_type>
460                 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),evt,fsm);
461             fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state);
462 
463             // then call the action method
464             HandledEnum res = ROW::action_call(fsm,evt,
465                              ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
466                              ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
467                              fsm.m_substate_list);
468             fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state);
469 
470             // and finally the entry method of the new current state
471             convert_event_and_execute_entry<next_state_type,T2>
472                 (::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),evt,fsm);
473             fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state);
474             return res;
475         }
476     };
477 
478     // row having only a guard condition
479     template<
480         typename ROW
481     >
482     struct g_row_
483     {
484         //typedef typename ROW::Source T1;
485         typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
486         typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
487         typedef typename ROW::Evt transition_event;
488         // if the source is an exit pseudo state, then
489         // current_state_type becomes the result of get_owner
490         // meaning the containing SM from which the exit occurs
491         typedef typename ::boost::mpl::eval_if<
492                 typename has_pseudo_exit<T1>::type,
493                 get_owner<T1,library_sm>,
494                 ::boost::mpl::identity<typename ROW::Source> >::type current_state_type;
495 
496         // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry
497         // else if Target is an explicit_entry, next_state_type becomes the result of get_owner
498         // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself
499         typedef typename ::boost::mpl::eval_if<
500             typename ::boost::mpl::is_sequence<T2>::type,
501             get_fork_owner<T2,library_sm>,
502             ::boost::mpl::eval_if<
503                     typename has_no_automatic_create<T2>::type,
504                     get_owner<T2,library_sm>,
505                     ::boost::mpl::identity<T2> >
506         >::type next_state_type;
507 
508         // if a guard condition is defined, call it to check that the event is accepted
check_guardboost::msm::back::state_machine::g_row_509         static bool check_guard(library_sm& fsm,transition_event const& evt)
510         {
511             if ( ROW::guard_call(fsm,evt,
512                                  ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
513                                  ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
514                                  fsm.m_substate_list ))
515                 return true;
516             return false;
517         }
518         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::g_row_519         static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt)
520         {
521             BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
522             BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
523             BOOST_ASSERT(state == (current_state));
524             // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
525             if (has_pseudo_exit<T1>::type::value &&
526                 !is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
527             {
528                 return HANDLED_FALSE;
529             }
530             if (!check_guard(fsm,evt))
531             {
532                 // guard rejected the event, we stay in the current one
533                 return HANDLED_GUARD_REJECT;
534             }
535             fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state);
536 
537             // the guard condition has already been checked
538             execute_exit<current_state_type>
539                 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),evt,fsm);
540             fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state);
541             fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state);
542 
543             // and finally the entry method of the new current state
544             convert_event_and_execute_entry<next_state_type,T2>
545                 (::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),evt,fsm);
546             fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state);
547             return HANDLED_TRUE;
548         }
549     };
550 
551     // row having only an action method
552     template<
553         typename ROW
554     >
555     struct a_row_
556     {
557         //typedef typename ROW::Source T1;
558         typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
559         typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
560         typedef typename ROW::Evt transition_event;
561         // if the source is an exit pseudo state, then
562         // current_state_type becomes the result of get_owner
563         // meaning the containing SM from which the exit occurs
564         typedef typename ::boost::mpl::eval_if<
565                 typename has_pseudo_exit<T1>::type,
566                 get_owner<T1,library_sm>,
567                 ::boost::mpl::identity<typename ROW::Source> >::type current_state_type;
568 
569         // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry
570         // else if Target is an explicit_entry, next_state_type becomes the result of get_owner
571         // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself
572         typedef typename ::boost::mpl::eval_if<
573             typename ::boost::mpl::is_sequence<T2>::type,
574             get_fork_owner<T2,library_sm>,
575             ::boost::mpl::eval_if<
576                     typename has_no_automatic_create<T2>::type,
577                     get_owner<T2,library_sm>,
578                     ::boost::mpl::identity<T2> >
579         >::type next_state_type;
580 
581         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::a_row_582         static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt)
583         {
584             BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
585             BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
586             BOOST_ASSERT(state == (current_state));
587 
588             // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
589             if (has_pseudo_exit<T1>::type::value &&
590                 !is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
591             {
592                 return HANDLED_FALSE;
593             }
594             fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state);
595 
596             // no need to check the guard condition
597             // first call the exit method of the current state
598             execute_exit<current_state_type>
599                 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),evt,fsm);
600             fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state);
601 
602             // then call the action method
603             HandledEnum res = ROW::action_call(fsm,evt,
604                             ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
605                             ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
606                             fsm.m_substate_list);
607             fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state);
608 
609             // and finally the entry method of the new current state
610             convert_event_and_execute_entry<next_state_type,T2>
611                 (::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),evt,fsm);
612             fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state);
613             return res;
614         }
615     };
616 
617     // row having no guard condition or action, simply transitions
618     template<
619         typename ROW
620     >
621     struct _row_
622     {
623         //typedef typename ROW::Source T1;
624         typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
625         typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
626         typedef typename ROW::Evt transition_event;
627         // if the source is an exit pseudo state, then
628         // current_state_type becomes the result of get_owner
629         // meaning the containing SM from which the exit occurs
630         typedef typename ::boost::mpl::eval_if<
631                 typename has_pseudo_exit<T1>::type,
632                 get_owner<T1,library_sm>,
633                 ::boost::mpl::identity<typename ROW::Source> >::type current_state_type;
634 
635         // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry
636         // else if Target is an explicit_entry, next_state_type becomes the result of get_owner
637         // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself
638         typedef typename ::boost::mpl::eval_if<
639             typename ::boost::mpl::is_sequence<T2>::type,
640             get_fork_owner<T2,library_sm>,
641             ::boost::mpl::eval_if<
642                     typename has_no_automatic_create<T2>::type,
643                     get_owner<T2,library_sm>,
644                     ::boost::mpl::identity<T2> >
645         >::type next_state_type;
646 
647         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::_row_648         static HandledEnum execute(library_sm& fsm, int region_index, int state, transition_event const& evt)
649         {
650             BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
651             BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
652             BOOST_ASSERT(state == (current_state));
653 
654             // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
655             if (has_pseudo_exit<T1>::type::value &&
656                 !is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
657             {
658                 return HANDLED_FALSE;
659             }
660             fsm.m_states[region_index] = active_state_switching::after_guard(current_state,next_state);
661 
662             // first call the exit method of the current state
663             execute_exit<current_state_type>
664                 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),evt,fsm);
665             fsm.m_states[region_index] = active_state_switching::after_exit(current_state,next_state);
666             fsm.m_states[region_index] = active_state_switching::after_action(current_state,next_state);
667 
668 
669             // and finally the entry method of the new current state
670             convert_event_and_execute_entry<next_state_type,T2>
671                 (::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),evt,fsm);
672             fsm.m_states[region_index] = active_state_switching::after_entry(current_state,next_state);
673             return HANDLED_TRUE;
674         }
675     };
676     // "i" rows are rows for internal transitions
677     template<
678         typename ROW
679     >
680     struct irow_
681     {
682         typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
683         typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
684         typedef typename ROW::Evt transition_event;
685         typedef typename ROW::Source current_state_type;
686         typedef T2 next_state_type;
687 
688         // if a guard condition is here, call it to check that the event is accepted
check_guardboost::msm::back::state_machine::irow_689         static bool check_guard(library_sm& fsm,transition_event const& evt)
690         {
691             if ( ROW::guard_call(fsm,evt,
692                                  ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
693                                  ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
694                                  fsm.m_substate_list))
695                 return true;
696             return false;
697         }
698         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::irow_699         static HandledEnum execute(library_sm& fsm, int , int state, transition_event const& evt)
700         {
701 
702             BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
703             BOOST_ASSERT(state == (current_state));
704             if (!check_guard(fsm,evt))
705             {
706                 // guard rejected the event, we stay in the current one
707                 return HANDLED_GUARD_REJECT;
708             }
709 
710             // call the action method
711             HandledEnum res = ROW::action_call(fsm,evt,
712                              ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
713                              ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
714                              fsm.m_substate_list);
715             return res;
716         }
717     };
718 
719     // row having only a guard condition
720     template<
721         typename ROW
722     >
723     struct g_irow_
724     {
725         typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
726         typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
727         typedef typename ROW::Evt transition_event;
728         typedef typename ROW::Source current_state_type;
729         typedef T2 next_state_type;
730 
731         // if a guard condition is defined, call it to check that the event is accepted
check_guardboost::msm::back::state_machine::g_irow_732         static bool check_guard(library_sm& fsm,transition_event const& evt)
733         {
734             if ( ROW::guard_call(fsm,evt,
735                                  ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
736                                  ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
737                                  fsm.m_substate_list) )
738                 return true;
739             return false;
740         }
741         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::g_irow_742         static HandledEnum execute(library_sm& fsm, int , int state, transition_event const& evt)
743         {
744             BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
745             BOOST_ASSERT(state == (current_state));
746             if (!check_guard(fsm,evt))
747             {
748                 // guard rejected the event, we stay in the current one
749                 return HANDLED_GUARD_REJECT;
750             }
751             return HANDLED_TRUE;
752         }
753     };
754 
755     // row having only an action method
756     template<
757         typename ROW
758     >
759     struct a_irow_
760     {
761         typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
762         typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
763 
764         typedef typename ROW::Evt transition_event;
765         typedef typename ROW::Source current_state_type;
766         typedef T2 next_state_type;
767 
768         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::a_irow_769         static HandledEnum execute(library_sm& fsm, int , int state, transition_event const& evt)
770         {
771             BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
772             BOOST_ASSERT(state == (current_state));
773 
774             // call the action method
775             HandledEnum res = ROW::action_call(fsm,evt,
776                             ::boost::fusion::at_key<current_state_type>(fsm.m_substate_list),
777                             ::boost::fusion::at_key<next_state_type>(fsm.m_substate_list),
778                             fsm.m_substate_list);
779 
780             return res;
781         }
782     };
783     // row simply ignoring the event
784     template<
785         typename ROW
786     >
787     struct _irow_
788     {
789         typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
790         typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
791         typedef typename ROW::Evt transition_event;
792         typedef typename ROW::Source current_state_type;
793         typedef T2 next_state_type;
794 
795         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::_irow_796         static HandledEnum execute(library_sm& , int , int state, transition_event const& )
797         {
798             BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<stt,current_state_type>::type::value));
799             BOOST_ASSERT(state == (current_state));
800             return HANDLED_TRUE;
801         }
802     };
803     // transitions internal to this state machine (no substate involved)
804     template<
805         typename ROW,
806         typename StateType
807     >
808     struct internal_
809     {
810         typedef StateType current_state_type;
811         typedef StateType next_state_type;
812         typedef typename ROW::Evt transition_event;
813 
814         // if a guard condition is here, call it to check that the event is accepted
check_guardboost::msm::back::state_machine::internal_815         static bool check_guard(library_sm& fsm,transition_event const& evt)
816         {
817             if ( ROW::guard_call(fsm,evt,
818                 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
819                 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
820                 fsm.m_substate_list) )
821                 return true;
822             return false;
823         }
824         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::internal_825         static HandledEnum execute(library_sm& fsm, int , int , transition_event const& evt)
826         {
827             if (!check_guard(fsm,evt))
828             {
829                 // guard rejected the event, we stay in the current one
830                 return HANDLED_GUARD_REJECT;
831             }
832 
833             // then call the action method
834             HandledEnum res = ROW::action_call(fsm,evt,
835                 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
836                 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
837                 fsm.m_substate_list);
838             return res;
839         }
840     };
841     template<
842         typename ROW
843     >
844     struct internal_ <ROW,library_sm>
845     {
846         typedef library_sm current_state_type;
847         typedef library_sm next_state_type;
848         typedef typename ROW::Evt transition_event;
849 
850         // if a guard condition is here, call it to check that the event is accepted
check_guardboost::msm::back::state_machine::internal_851         static bool check_guard(library_sm& fsm,transition_event const& evt)
852         {
853             if ( ROW::guard_call(fsm,evt,
854                 fsm,
855                 fsm,
856                 fsm.m_substate_list) )
857                 return true;
858             return false;
859         }
860         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::internal_861         static HandledEnum execute(library_sm& fsm, int , int , transition_event const& evt)
862         {
863             if (!check_guard(fsm,evt))
864             {
865                 // guard rejected the event, we stay in the current one
866                 return HANDLED_GUARD_REJECT;
867             }
868 
869             // then call the action method
870             HandledEnum res = ROW::action_call(fsm,evt,
871                 fsm,
872                 fsm,
873                 fsm.m_substate_list);
874             return res;
875         }
876     };
877 
878     template<
879         typename ROW,
880         typename StateType
881     >
882     struct a_internal_
883     {
884         typedef StateType current_state_type;
885         typedef StateType next_state_type;
886         typedef typename ROW::Evt transition_event;
887 
888         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::a_internal_889         static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt)
890         {
891             // then call the action method
892             HandledEnum res = ROW::action_call(fsm,evt,
893                 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
894                 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
895                 fsm.m_substate_list);
896             return res;
897         }
898     };
899     template<
900         typename ROW
901     >
902     struct a_internal_ <ROW,library_sm>
903     {
904         typedef library_sm current_state_type;
905         typedef library_sm next_state_type;
906         typedef typename ROW::Evt transition_event;
907 
908         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::a_internal_909         static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt)
910         {
911             // then call the action method
912             HandledEnum res = ROW::action_call(fsm,evt,
913                 fsm,
914                 fsm,
915                 fsm.m_substate_list);
916             return res;
917         }
918     };
919     template<
920         typename ROW,
921         typename StateType
922     >
923     struct g_internal_
924     {
925         typedef StateType current_state_type;
926         typedef StateType next_state_type;
927         typedef typename ROW::Evt transition_event;
928 
929         // if a guard condition is here, call it to check that the event is accepted
check_guardboost::msm::back::state_machine::g_internal_930         static bool check_guard(library_sm& fsm,transition_event const& evt)
931         {
932             if ( ROW::guard_call(fsm,evt,
933                 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
934                 ::boost::fusion::at_key<StateType>(fsm.m_substate_list),
935                 fsm.m_substate_list) )
936                 return true;
937             return false;
938         }
939         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::g_internal_940         static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt)
941         {
942             if (!check_guard(fsm,evt))
943             {
944                 // guard rejected the event, we stay in the current one
945                 return HANDLED_GUARD_REJECT;
946             }
947             return HANDLED_TRUE;
948         }
949     };
950     template<
951         typename ROW
952     >
953     struct g_internal_ <ROW,library_sm>
954     {
955         typedef library_sm current_state_type;
956         typedef library_sm next_state_type;
957         typedef typename ROW::Evt transition_event;
958 
959         // if a guard condition is here, call it to check that the event is accepted
check_guardboost::msm::back::state_machine::g_internal_960         static bool check_guard(library_sm& fsm,transition_event const& evt)
961         {
962             if ( ROW::guard_call(fsm,evt,
963                 fsm,
964                 fsm,
965                 fsm.m_substate_list) )
966                 return true;
967             return false;
968         }
969         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::g_internal_970         static HandledEnum execute(library_sm& fsm, int, int, transition_event const& evt)
971         {
972             if (!check_guard(fsm,evt))
973             {
974                 // guard rejected the event, we stay in the current one
975                 return HANDLED_GUARD_REJECT;
976             }
977             return HANDLED_TRUE;
978         }
979     };
980     template<
981         typename ROW,
982         typename StateType
983     >
984     struct _internal_
985     {
986         typedef StateType current_state_type;
987         typedef StateType next_state_type;
988         typedef typename ROW::Evt transition_event;
executeboost::msm::back::state_machine::_internal_989         static HandledEnum execute(library_sm& , int , int , transition_event const& )
990         {
991             return HANDLED_TRUE;
992         }
993     };
994     template<
995         typename ROW
996     >
997     struct _internal_ <ROW,library_sm>
998     {
999         typedef library_sm current_state_type;
1000         typedef library_sm next_state_type;
1001         typedef typename ROW::Evt transition_event;
executeboost::msm::back::state_machine::_internal_1002         static HandledEnum execute(library_sm& , int , int , transition_event const& )
1003         {
1004             return HANDLED_TRUE;
1005         }
1006     };
1007     // Template used to form forwarding rows in the transition table for every row of a composite SM
1008     template<
1009         typename T1
1010         , class Evt
1011     >
1012     struct frow
1013     {
1014         typedef T1                  current_state_type;
1015         typedef T1                  next_state_type;
1016         typedef Evt                 transition_event;
1017         // tag to find out if a row is a forwarding row
1018         typedef int                 is_frow;
1019 
1020         // Take the transition action and return the next state.
executeboost::msm::back::state_machine::frow1021         static HandledEnum execute(library_sm& fsm, int region_index, int , transition_event const& evt)
1022         {
1023             // false as second parameter because this event is forwarded from outer fsm
1024             execute_return res =
1025                 (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list)).process_event_internal(evt,false);
1026             fsm.m_states[region_index]=get_state_id<stt,T1>::type::value;
1027             return res;
1028         }
1029         // helper metafunctions used by dispatch table and give the frow a new event
1030         // (used to avoid double entries in a table because of base events)
1031         template <class NewEvent>
1032         struct replace_event
1033         {
1034             typedef frow<T1,NewEvent> type;
1035         };
1036     };
1037 
1038     template <class Tag, class Transition,class StateType>
1039     struct create_backend_stt
1040     {
1041     };
1042     template <class Transition,class StateType>
1043     struct create_backend_stt<g_row_tag,Transition,StateType>
1044     {
1045         typedef g_row_<Transition> type;
1046     };
1047     template <class Transition,class StateType>
1048     struct create_backend_stt<a_row_tag,Transition,StateType>
1049     {
1050         typedef a_row_<Transition> type;
1051     };
1052     template <class Transition,class StateType>
1053     struct create_backend_stt<_row_tag,Transition,StateType>
1054     {
1055         typedef _row_<Transition> type;
1056     };
1057     template <class Transition,class StateType>
1058     struct create_backend_stt<row_tag,Transition,StateType>
1059     {
1060         typedef row_<Transition> type;
1061     };
1062     // internal transitions
1063     template <class Transition,class StateType>
1064     struct create_backend_stt<g_irow_tag,Transition,StateType>
1065     {
1066         typedef g_irow_<Transition> type;
1067     };
1068     template <class Transition,class StateType>
1069     struct create_backend_stt<a_irow_tag,Transition,StateType>
1070     {
1071         typedef a_irow_<Transition> type;
1072     };
1073     template <class Transition,class StateType>
1074     struct create_backend_stt<irow_tag,Transition,StateType>
1075     {
1076         typedef irow_<Transition> type;
1077     };
1078     template <class Transition,class StateType>
1079     struct create_backend_stt<_irow_tag,Transition,StateType>
1080     {
1081         typedef _irow_<Transition> type;
1082     };
1083     template <class Transition,class StateType>
1084     struct create_backend_stt<sm_a_i_row_tag,Transition,StateType>
1085     {
1086         typedef a_internal_<Transition,StateType> type;
1087     };
1088     template <class Transition,class StateType>
1089     struct create_backend_stt<sm_g_i_row_tag,Transition,StateType>
1090     {
1091         typedef g_internal_<Transition,StateType> type;
1092     };
1093     template <class Transition,class StateType>
1094     struct create_backend_stt<sm_i_row_tag,Transition,StateType>
1095     {
1096         typedef internal_<Transition,StateType> type;
1097     };
1098     template <class Transition,class StateType>
1099     struct create_backend_stt<sm__i_row_tag,Transition,StateType>
1100     {
1101         typedef _internal_<Transition,StateType> type;
1102     };
1103     template <class Transition,class StateType=void>
1104     struct make_row_tag
1105     {
1106         typedef typename create_backend_stt<typename Transition::row_type_tag,Transition,StateType>::type type;
1107     };
1108 
1109     // add to the stt the initial states which could be missing (if not being involved in a transition)
1110     template <class BaseType, class stt_simulated = typename BaseType::transition_table>
1111     struct create_real_stt
1112     {
1113         //typedef typename BaseType::transition_table stt_simulated;
1114         typedef typename ::boost::mpl::fold<
1115             stt_simulated,mpl::vector0<>,
1116             ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
1117                                      make_row_tag< ::boost::mpl::placeholders::_2 , BaseType > >
1118         >::type type;
1119     };
1120 
1121     template <class Table,class Intermediate,class StateType>
1122     struct add_forwarding_row_helper
1123     {
1124         typedef typename generate_event_set<Table>::type all_events;
1125         typedef typename ::boost::mpl::fold<
1126             all_events, Intermediate,
1127             ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
1128             frow<StateType, ::boost::mpl::placeholders::_2> > >::type type;
1129     };
1130     // gets the transition table from a composite and make from it a forwarding row
1131     template <class StateType,class IsComposite>
1132     struct get_internal_transition_table
1133     {
1134         // first get the table of a composite
1135         typedef typename recursive_get_transition_table<StateType>::type original_table;
1136 
1137         // we now look for the events the composite has in its internal transitions
1138         // the internal ones are searched recursively in sub-sub... states
1139         // we go recursively because our states can also have internal tables or substates etc.
1140         typedef typename recursive_get_internal_transition_table<StateType, ::boost::mpl::true_>::type recursive_istt;
1141         typedef typename ::boost::mpl::fold<
1142                     recursive_istt,::boost::mpl::vector0<>,
1143                     ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
1144                                              make_row_tag< ::boost::mpl::placeholders::_2 , StateType> >
1145                 >::type recursive_istt_with_tag;
1146 
1147         typedef typename ::boost::mpl::insert_range< original_table, typename ::boost::mpl::end<original_table>::type,
1148                                                      recursive_istt_with_tag>::type table_with_all_events;
1149 
1150         // and add for every event a forwarding row
1151         typedef typename ::boost::mpl::eval_if<
1152                 typename CompilePolicy::add_forwarding_rows,
1153                 add_forwarding_row_helper<table_with_all_events,::boost::mpl::vector0<>,StateType>,
1154                 ::boost::mpl::identity< ::boost::mpl::vector0<> >
1155         >::type type;
1156     };
1157     template <class StateType>
1158     struct get_internal_transition_table<StateType, ::boost::mpl::false_ >
1159     {
1160         typedef typename create_real_stt<StateType, typename StateType::internal_transition_table >::type type;
1161     };
1162     // typedefs used internally
1163     typedef typename create_real_stt<Derived>::type real_transition_table;
1164     typedef typename create_stt<library_sm>::type stt;
1165     typedef typename get_initial_states<typename Derived::initial_state>::type initial_states;
1166     typedef typename generate_state_set<stt>::type state_list;
1167     typedef typename HistoryPolicy::template apply<nr_regions::value>::type concrete_history;
1168 
1169     typedef typename ::boost::fusion::result_of::as_set<state_list>::type substate_list;
1170     typedef typename ::boost::msm::back::generate_event_set<
1171         typename create_real_stt<library_sm, typename library_sm::internal_transition_table >::type
1172     >::type processable_events_internal_table;
1173 
1174     // extends the transition table with rows from composite states
1175     template <class Composite>
1176     struct extend_table
1177     {
1178         // add the init states
1179         //typedef typename create_stt<Composite>::type stt;
1180         typedef typename Composite::stt Stt;
1181 
1182         // add the internal events defined in the internal_transition_table
1183         // Note: these are added first because they must have a lesser prio
1184         // than the deeper transitions in the sub regions
1185         // table made of a stt + internal transitions of composite
1186         typedef typename ::boost::mpl::fold<
1187             typename Composite::internal_transition_table,::boost::mpl::vector0<>,
1188             ::boost::mpl::push_back< ::boost::mpl::placeholders::_1,
1189                                      make_row_tag< ::boost::mpl::placeholders::_2 , Composite> >
1190         >::type internal_stt;
1191 
1192         typedef typename ::boost::mpl::insert_range<
1193             Stt,
1194             typename ::boost::mpl::end<Stt>::type,
1195             internal_stt
1196             //typename get_internal_transition_table<Composite, ::boost::mpl::true_ >::type
1197         >::type stt_plus_internal;
1198 
1199         // for every state, add its transition table (if any)
1200         // transformed as frow
1201         typedef typename ::boost::mpl::fold<state_list,stt_plus_internal,
1202                 ::boost::mpl::insert_range<
1203                         ::boost::mpl::placeholders::_1,
1204                         ::boost::mpl::end< ::boost::mpl::placeholders::_1>,
1205                         get_internal_transition_table<
1206                                 ::boost::mpl::placeholders::_2,
1207                                 is_composite_state< ::boost::mpl::placeholders::_2> > >
1208         >::type type;
1209     };
1210     // extend the table with tables from composite states
1211     typedef typename extend_table<library_sm>::type complete_table;
1212      // build a sequence of regions
1213      typedef typename get_regions_as_sequence<typename Derived::initial_state>::type seq_initial_states;
1214     // Member functions
1215 
1216     // start the state machine (calls entry of the initial state)
start()1217     void start()
1218     {
1219          // reinitialize our list of currently active states with the ones defined in Derived::initial_state
1220          ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1221                         (init_states(m_states));
1222         // call on_entry on this SM
1223         (static_cast<Derived*>(this))->on_entry(fsm_initial_event(),*this);
1224         ::boost::mpl::for_each<initial_states, boost::msm::wrap<mpl::placeholders::_1> >
1225             (call_init<fsm_initial_event>(fsm_initial_event(),this));
1226         // give a chance to handle an anonymous (eventless) transition
1227         handle_eventless_transitions_helper<library_sm> eventless_helper(this,true);
1228         eventless_helper.process_completion_event();
1229     }
1230 
1231     // start the state machine (calls entry of the initial state passing incomingEvent to on_entry's)
1232     template <class Event>
start(Event const & incomingEvent)1233     void start(Event const& incomingEvent)
1234     {
1235         // reinitialize our list of currently active states with the ones defined in Derived::initial_state
1236         ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1237                         (init_states(m_states));
1238         // call on_entry on this SM
1239         (static_cast<Derived*>(this))->on_entry(incomingEvent,*this);
1240         ::boost::mpl::for_each<initial_states, boost::msm::wrap<mpl::placeholders::_1> >
1241             (call_init<Event>(incomingEvent,this));
1242         // give a chance to handle an anonymous (eventless) transition
1243         handle_eventless_transitions_helper<library_sm> eventless_helper(this,true);
1244         eventless_helper.process_completion_event();
1245     }
1246 
1247     // stop the state machine (calls exit of the current state)
stop()1248     void stop()
1249     {
1250         do_exit(fsm_final_event(),*this);
1251     }
1252 
1253     // stop the state machine (calls exit of the current state passing finalEvent to on_exit's)
1254     template <class Event>
stop(Event const & finalEvent)1255     void stop(Event const& finalEvent)
1256     {
1257         do_exit(finalEvent,*this);
1258     }
1259 
1260     // Main function used by clients of the derived FSM to make transitions.
1261     template<class Event>
process_event(Event const & evt)1262     execute_return process_event(Event const& evt)
1263     {
1264         return process_event_internal(evt,true);
1265     }
1266 
1267     template <class EventType>
enqueue_event_helper(EventType const & evt,::boost::mpl::false_ const &)1268     void enqueue_event_helper(EventType const& evt, ::boost::mpl::false_ const &)
1269     {
1270         execute_return (library_sm::*pf) (EventType const& evt) =
1271             &library_sm::process_event;
1272 
1273         transition_fct f = ::boost::bind(pf,this,evt);
1274         m_events_queue.m_events_queue.push_back(f);
1275     }
1276     template <class EventType>
enqueue_event_helper(EventType const &,::boost::mpl::true_ const &)1277     void enqueue_event_helper(EventType const& , ::boost::mpl::true_ const &)
1278     {
1279         // no queue
1280     }
1281 
execute_queued_events_helper(::boost::mpl::false_ const &)1282     void execute_queued_events_helper(::boost::mpl::false_ const &)
1283     {
1284         while(!m_events_queue.m_events_queue.empty())
1285         {
1286             transition_fct to_call = m_events_queue.m_events_queue.front();
1287             m_events_queue.m_events_queue.pop_front();
1288             to_call();
1289         }
1290     }
execute_queued_events_helper(::boost::mpl::true_ const &)1291     void execute_queued_events_helper(::boost::mpl::true_ const &)
1292     {
1293         // no queue required
1294     }
execute_single_queued_event_helper(::boost::mpl::false_ const &)1295     void execute_single_queued_event_helper(::boost::mpl::false_ const &)
1296     {
1297         transition_fct to_call = m_events_queue.m_events_queue.front();
1298         m_events_queue.m_events_queue.pop_front();
1299         to_call();
1300     }
execute_single_queued_event_helper(::boost::mpl::true_ const &)1301     void execute_single_queued_event_helper(::boost::mpl::true_ const &)
1302     {
1303         // no queue required
1304     }
1305     // enqueues an event in the message queue
1306     // call execute_queued_events to process all queued events.
1307     // Be careful if you do this during event processing, the event will be processed immediately
1308     // and not kept in the queue
1309     template <class EventType>
enqueue_event(EventType const & evt)1310     void enqueue_event(EventType const& evt)
1311     {
1312         enqueue_event_helper<EventType>(evt, typename is_no_message_queue<library_sm>::type());
1313     }
1314 
1315     // empty the queue and process events
execute_queued_events()1316     void execute_queued_events()
1317     {
1318         execute_queued_events_helper(typename is_no_message_queue<library_sm>::type());
1319     }
execute_single_queued_event()1320     void execute_single_queued_event()
1321     {
1322         execute_single_queued_event_helper(typename is_no_message_queue<library_sm>::type());
1323     }
get_message_queue_size() const1324     typename events_queue_t::size_type get_message_queue_size() const
1325     {
1326         return m_events_queue.m_events_queue.size();
1327     }
1328 
get_message_queue()1329     events_queue_t& get_message_queue()
1330     {
1331         return m_events_queue.m_events_queue;
1332     }
1333 
get_message_queue() const1334     const events_queue_t& get_message_queue() const
1335     {
1336         return m_events_queue.m_events_queue;
1337     }
1338 
clear_deferred_queue()1339     void clear_deferred_queue()
1340     {
1341         m_deferred_events_queue.clear();
1342     }
1343 
get_deferred_queue()1344     deferred_events_queue_t& get_deferred_queue()
1345     {
1346         return m_deferred_events_queue.m_deferred_events_queue;
1347     }
1348 
get_deferred_queue() const1349     const deferred_events_queue_t& get_deferred_queue() const
1350     {
1351         return m_deferred_events_queue.m_deferred_events_queue;
1352     }
1353 
1354     // Getter that returns the current state of the FSM
current_state() const1355     const int* current_state() const
1356     {
1357         return this->m_states;
1358     }
1359 
1360     template <class Archive>
1361     struct serialize_state
1362     {
serialize_stateboost::msm::back::state_machine::serialize_state1363         serialize_state(Archive& ar):ar_(ar){}
1364 
1365         template<typename T>
1366         typename ::boost::enable_if<
1367             typename ::boost::mpl::or_<
1368                 typename has_do_serialize<T>::type,
1369                 typename is_composite_state<T>::type
1370             >::type
1371             ,void
1372         >::type
operator ()boost::msm::back::state_machine::serialize_state1373         operator()(T& t) const
1374         {
1375             ar_ & t;
1376         }
1377         template<typename T>
1378         typename ::boost::disable_if<
1379             typename ::boost::mpl::or_<
1380                 typename has_do_serialize<T>::type,
1381                 typename is_composite_state<T>::type
1382             >::type
1383             ,void
1384         >::type
operator ()boost::msm::back::state_machine::serialize_state1385         operator()(T&) const
1386         {
1387             // no state to serialize
1388         }
1389         Archive& ar_;
1390     };
1391 
1392     template<class Archive>
serialize(Archive & ar,const unsigned int)1393     void serialize(Archive & ar, const unsigned int)
1394     {
1395         // invoke serialization of the base class
1396         (serialize_state<Archive>(ar))(boost::serialization::base_object<Derived>(*this));
1397         // now our attributes
1398         ar & m_states;
1399         // queues cannot be serialized => skip
1400         ar & m_history;
1401         ar & m_event_processing;
1402         ar & m_is_included;
1403         // visitors cannot be serialized => skip
1404         ::boost::fusion::for_each(m_substate_list, serialize_state<Archive>(ar));
1405     }
1406 
1407     // linearly search for the state with the given id
1408     struct get_state_id_helper
1409     {
get_state_id_helperboost::msm::back::state_machine::get_state_id_helper1410         get_state_id_helper(int id,const BaseState** res,const library_sm* self_):
1411         result_state(res),searched_id(id),self(self_) {}
1412 
1413         template <class StateType>
operator ()boost::msm::back::state_machine::get_state_id_helper1414         void operator()(boost::msm::wrap<StateType> const&)
1415         {
1416             // look for the state id until found
1417             BOOST_STATIC_CONSTANT(int, id = (get_state_id<stt,StateType>::value));
1418             if (!*result_state && (id == searched_id))
1419             {
1420                 *result_state = &::boost::fusion::at_key<StateType>(self->m_substate_list);
1421             }
1422         }
1423         const BaseState**  result_state;
1424         int                searched_id;
1425         const library_sm* self;
1426     };
1427     // return the state whose id is passed or 0 if not found
1428     // caution if you need this, you probably need polymorphic states
1429     // complexity: O(number of states)
get_state_by_id(int id)1430     BaseState* get_state_by_id(int id)
1431     {
1432         const BaseState*  result_state=0;
1433         ::boost::mpl::for_each<state_list,
1434             ::boost::msm::wrap< ::boost::mpl::placeholders::_1> > (get_state_id_helper(id,&result_state,this));
1435         return const_cast<BaseState*>(result_state);
1436     }
get_state_by_id(int id) const1437     const BaseState* get_state_by_id(int id) const
1438     {
1439         const BaseState*  result_state=0;
1440         ::boost::mpl::for_each<state_list,
1441             ::boost::msm::wrap< ::boost::mpl::placeholders::_1> > (get_state_id_helper(id,&result_state,this));
1442         return result_state;
1443     }
1444     // true if the sm is used in another sm
is_contained() const1445     bool is_contained() const
1446     {
1447         return m_is_included;
1448     }
1449     // get the history policy class
get_history()1450     concrete_history& get_history()
1451     {
1452         return m_history;
1453     }
get_history() const1454     concrete_history const& get_history() const
1455     {
1456         return m_history;
1457     }
1458     // get a state (const version)
1459     // as a pointer
1460     template <class State>
1461     typename ::boost::enable_if<typename ::boost::is_pointer<State>::type,State >::type
get_state(::boost::msm::back::dummy<0>=0) const1462     get_state(::boost::msm::back::dummy<0> = 0) const
1463     {
1464         return const_cast<State >
1465             (&
1466                 (::boost::fusion::at_key<
1467                     typename ::boost::remove_const<typename ::boost::remove_pointer<State>::type>::type>(m_substate_list)));
1468     }
1469     // as a reference
1470     template <class State>
1471     typename ::boost::enable_if<typename ::boost::is_reference<State>::type,State >::type
get_state(::boost::msm::back::dummy<1>=0) const1472     get_state(::boost::msm::back::dummy<1> = 0) const
1473     {
1474         return const_cast<State >
1475             ( ::boost::fusion::at_key<
1476                 typename ::boost::remove_const<typename ::boost::remove_reference<State>::type>::type>(m_substate_list) );
1477     }
1478     // get a state (non const version)
1479     // as a pointer
1480     template <class State>
1481     typename ::boost::enable_if<typename ::boost::is_pointer<State>::type,State >::type
get_state(::boost::msm::back::dummy<0>=0)1482     get_state(::boost::msm::back::dummy<0> = 0)
1483     {
1484         return &(static_cast<typename boost::add_reference<typename ::boost::remove_pointer<State>::type>::type >
1485         (::boost::fusion::at_key<typename ::boost::remove_pointer<State>::type>(m_substate_list)));
1486     }
1487     // as a reference
1488     template <class State>
1489     typename ::boost::enable_if<typename ::boost::is_reference<State>::type,State >::type
get_state(::boost::msm::back::dummy<1>=0)1490     get_state(::boost::msm::back::dummy<1> = 0)
1491     {
1492         return ::boost::fusion::at_key<typename ::boost::remove_reference<State>::type>(m_substate_list);
1493     }
1494     // checks if a flag is active using the BinaryOp as folding function
1495     template <class Flag,class BinaryOp>
is_flag_active() const1496     bool is_flag_active() const
1497     {
1498         flag_handler* flags_entries = get_entries_for_flag<Flag>();
1499         bool res = (*flags_entries[ m_states[0] ])(*this);
1500         for (int i = 1; i < nr_regions::value ; ++i)
1501         {
1502             res = typename BinaryOp::type() (res,(*flags_entries[ m_states[i] ])(*this));
1503         }
1504         return res;
1505     }
1506     // checks if a flag is active using no binary op if 1 region, or OR if > 1 regions
1507     template <class Flag>
is_flag_active() const1508     bool is_flag_active() const
1509     {
1510         return FlagHelper<Flag,(nr_regions::value>1)>::helper(*this,get_entries_for_flag<Flag>());
1511     }
1512     // visit the currently active states (if these are defined as visitable
1513     // by implementing accept)
visit_current_states()1514     void visit_current_states()
1515     {
1516         for (int i=0; i<nr_regions::value;++i)
1517         {
1518             m_visitors.execute(m_states[i]);
1519         }
1520     }
1521 #define MSM_VISIT_STATE_SUB(z, n, unused) ARG ## n vis ## n
1522 #define MSM_VISIT_STATE_EXECUTE(z, n, unused)                                    \
1523         template <BOOST_PP_ENUM_PARAMS(n, class ARG)>                               \
1524         void visit_current_states(BOOST_PP_ENUM(n, MSM_VISIT_STATE_SUB, ~ ) )         \
1525         {                                                                           \
1526             for (int i=0; i<nr_regions::value;++i)                                                      \
1527             {                                                                                           \
1528                 m_visitors.execute(m_states[i],BOOST_PP_ENUM_PARAMS(n,vis));                            \
1529             }                                                                                           \
1530         }
1531         BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_VISIT_STATE_EXECUTE, ~)
1532 #undef MSM_VISIT_STATE_EXECUTE
1533 #undef MSM_VISIT_STATE_SUB
1534 
1535     // puts the given event into the deferred queue
1536     template <class Event>
defer_event(Event const & e)1537     void defer_event(Event const& e)
1538     {
1539         // to call this function, you need either a state with a deferred_events typedef
1540         // or that the fsm provides the activate_deferred_events typedef
1541         BOOST_MPL_ASSERT(( has_fsm_deferred_events<library_sm> ));
1542         execute_return (library_sm::*pf) (Event const& evt)= &library_sm::process_event;
1543         Event temp (e);
1544         ::boost::function<execute_return () > f= ::boost::bind(pf, this,temp);
1545         post_deferred_event(f);
1546     }
1547 
1548  protected:    // interface for the derived class
1549 
1550      // helper used to fill the initial states
1551      struct init_states
1552      {
init_statesboost::msm::back::state_machine::init_states1553          init_states(int* const init):m_initial_states(init),m_index(-1){}
1554 
1555          // History initializer function object, used with mpl::for_each
1556          template <class State>
operator ()boost::msm::back::state_machine::init_states1557          void operator()(::boost::msm::wrap<State> const&)
1558          {
1559              m_initial_states[++m_index]=get_state_id<stt,State>::type::value;
1560          }
1561          int* const m_initial_states;
1562          int m_index;
1563      };
1564  public:
1565      struct update_state
1566      {
update_stateboost::msm::back::state_machine::update_state1567          update_state(substate_list& to_overwrite_):to_overwrite(&to_overwrite_){}
1568          template<typename StateType>
operator ()boost::msm::back::state_machine::update_state1569          void operator()(StateType const& astate) const
1570          {
1571              ::boost::fusion::at_key<StateType>(*to_overwrite)=astate;
1572          }
1573          substate_list* to_overwrite;
1574      };
1575      template <class Expr>
set_states(Expr const & expr)1576      void set_states(Expr const& expr)
1577      {
1578          ::boost::fusion::for_each(
1579              ::boost::fusion::as_vector(FoldToList()(expr, boost::fusion::nil())),update_state(this->m_substate_list));
1580      }
1581 
1582      // Construct with the default initial states
1583      state_machine<A0,A1,A2,A3,A4 >()
1584          :Derived()
1585          ,m_events_queue()
1586          ,m_deferred_events_queue()
1587          ,m_history()
1588          ,m_event_processing(false)
1589          ,m_is_included(false)
1590          ,m_visitors()
1591          ,m_substate_list()
1592      {
1593          // initialize our list of states with the ones defined in Derived::initial_state
1594          ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1595                         (init_states(m_states));
1596          m_history.set_initial_states(m_states);
1597          // create states
1598          fill_states(this);
1599      }
1600      template <class Expr>
state_machine(Expr const & expr,typename::boost::enable_if<typename::boost::proto::is_expr<Expr>::type>::type * =0)1601      state_machine<A0,A1,A2,A3,A4 >
1602          (Expr const& expr,typename ::boost::enable_if<typename ::boost::proto::is_expr<Expr>::type >::type* =0)
1603          :Derived()
1604          ,m_events_queue()
1605          ,m_deferred_events_queue()
1606          ,m_history()
1607          ,m_event_processing(false)
1608          ,m_is_included(false)
1609          ,m_visitors()
1610          ,m_substate_list()
1611      {
1612          BOOST_MPL_ASSERT_MSG(
1613              ( ::boost::proto::matches<Expr, FoldToList>::value),
1614              THE_STATES_EXPRESSION_PASSED_DOES_NOT_MATCH_GRAMMAR,
1615              (FoldToList));
1616 
1617          // initialize our list of states with the ones defined in Derived::initial_state
1618          ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
1619                         (init_states(m_states));
1620          m_history.set_initial_states(m_states);
1621          // create states
1622          set_states(expr);
1623          fill_states(this);
1624      }
1625      // Construct with the default initial states and some default argument(s)
1626 #define MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB(z, n, unused) ARG ## n t ## n
1627 #define MSM_CONSTRUCTOR_HELPER_EXECUTE(z, n, unused)                                \
1628         template <BOOST_PP_ENUM_PARAMS(n, class ARG)>                               \
1629         state_machine<A0,A1,A2,A3,A4                                                \
1630         >(BOOST_PP_ENUM(n, MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB, ~ ),                 \
1631         typename ::boost::disable_if<typename ::boost::proto::is_expr<ARG0>::type >::type* =0 )                \
1632         :Derived(BOOST_PP_ENUM_PARAMS(n,t))                                         \
1633          ,m_events_queue()                                                          \
1634          ,m_deferred_events_queue()                                                 \
1635          ,m_history()                                                               \
1636          ,m_event_processing(false)                                                 \
1637          ,m_is_included(false)                                                      \
1638          ,m_visitors()                                                              \
1639          ,m_substate_list()                                                         \
1640      {                                                                              \
1641          ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> > \
1642                         (init_states(m_states));                                    \
1643          m_history.set_initial_states(m_states);                                    \
1644          fill_states(this);                                                         \
1645      }                                                                              \
1646         template <class Expr,BOOST_PP_ENUM_PARAMS(n, class ARG)>                    \
1647         state_machine<A0,A1,A2,A3,A4                                                \
1648         >(Expr const& expr,BOOST_PP_ENUM(n, MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB, ~ ), \
1649         typename ::boost::enable_if<typename ::boost::proto::is_expr<Expr>::type >::type* =0 ) \
1650         :Derived(BOOST_PP_ENUM_PARAMS(n,t))                                         \
1651          ,m_events_queue()                                                          \
1652          ,m_deferred_events_queue()                                                 \
1653          ,m_history()                                                               \
1654          ,m_event_processing(false)                                                 \
1655          ,m_is_included(false)                                                      \
1656          ,m_visitors()                                                              \
1657          ,m_substate_list()                                                         \
1658      {                                                                              \
1659          BOOST_MPL_ASSERT_MSG(                                                      \
1660          ( ::boost::proto::matches<Expr, FoldToList>::value),                       \
1661              THE_STATES_EXPRESSION_PASSED_DOES_NOT_MATCH_GRAMMAR,                   \
1662              (FoldToList));                                                         \
1663          ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> > \
1664                         (init_states(m_states));                                    \
1665          m_history.set_initial_states(m_states);                                    \
1666          set_states(expr);                                                          \
1667          fill_states(this);                                                         \
1668      }
1669 
1670      BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_CONSTRUCTOR_ARG_SIZE,1), MSM_CONSTRUCTOR_HELPER_EXECUTE, ~)
1671 #undef MSM_CONSTRUCTOR_HELPER_EXECUTE
1672 #undef MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB
1673 
1674 
1675 
1676      // assignment operator using the copy policy to decide if non_copyable, shallow or deep copying is necessary
operator =(library_sm const & rhs)1677      library_sm& operator= (library_sm const& rhs)
1678      {
1679          if (this != &rhs)
1680          {
1681             Derived::operator=(rhs);
1682             do_copy(rhs);
1683          }
1684         return *this;
1685      }
1686      state_machine<A0,A1,A2,A3,A4>
1687          (library_sm const& rhs)
1688          : Derived(rhs)
1689      {
1690         if (this != &rhs)
1691         {
1692             // initialize our list of states with the ones defined in Derived::initial_state
1693             fill_states(this);
1694             do_copy(rhs);
1695         }
1696      }
1697 
1698     // the following 2 functions handle the terminate/interrupt states handling
1699     // if one of these states is found, the first one is used
1700     template <class Event>
is_event_handling_blocked_helper(::boost::mpl::true_ const &)1701     bool is_event_handling_blocked_helper( ::boost::mpl::true_ const &)
1702     {
1703         // if the state machine is terminated, do not handle any event
1704         if (is_flag_active< ::boost::msm::TerminateFlag>())
1705             return true;
1706         // if the state machine is interrupted, do not handle any event
1707         // unless the event is the end interrupt event
1708         if ( is_flag_active< ::boost::msm::InterruptedFlag>() &&
1709             !is_flag_active< ::boost::msm::EndInterruptFlag<Event> >())
1710             return true;
1711         return false;
1712     }
1713     // otherwise simple handling, no flag => continue
1714     template <class Event>
is_event_handling_blocked_helper(::boost::mpl::false_ const &)1715     bool is_event_handling_blocked_helper( ::boost::mpl::false_ const &)
1716     {
1717         // no terminate/interrupt states detected
1718         return false;
1719     }
1720     // the following functions handle pre/post-process handling  of a message queue
1721     template <class StateType,class EventType>
do_pre_msg_queue_helper(EventType const &,::boost::mpl::true_ const &)1722     bool do_pre_msg_queue_helper(EventType const&, ::boost::mpl::true_ const &)
1723     {
1724         // no message queue needed
1725         return true;
1726     }
1727     template <class StateType,class EventType>
do_pre_msg_queue_helper(EventType const & evt,::boost::mpl::false_ const &)1728     bool do_pre_msg_queue_helper(EventType const& evt, ::boost::mpl::false_ const &)
1729     {
1730         execute_return (library_sm::*pf) (EventType const& evt) =
1731             &library_sm::process_event;
1732         // if we are already processing an event
1733         if (m_event_processing)
1734         {
1735             // event has to be put into the queue
1736             transition_fct f = ::boost::bind(pf,this,evt);
1737             m_events_queue.m_events_queue.push_back(f);
1738             return false;
1739         }
1740         // event can be handled, processing
1741         m_event_processing = true;
1742         return true;
1743     }
do_post_msg_queue_helper(::boost::mpl::true_ const &)1744     void do_post_msg_queue_helper( ::boost::mpl::true_ const &)
1745     {
1746         // no message queue needed
1747     }
do_post_msg_queue_helper(::boost::mpl::false_ const &)1748     void do_post_msg_queue_helper( ::boost::mpl::false_ const &)
1749     {
1750         m_event_processing = false;
1751         process_message_queue(this);
1752     }
1753     // the following 2 functions handle the processing either with a try/catch protection or without
1754     template <class StateType,class EventType>
do_process_helper(EventType const & evt,::boost::mpl::true_ const &,bool is_direct_call)1755     HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::true_ const &, bool is_direct_call)
1756     {
1757         return this->do_process_event(evt,is_direct_call);
1758     }
1759     template <class StateType,class EventType>
do_process_helper(EventType const & evt,::boost::mpl::false_ const &,bool is_direct_call)1760     HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::false_ const &, bool is_direct_call)
1761     {
1762         // when compiling without exception support there is no formal parameter "e" in the catch handler.
1763         // Declaring a local variable here does not hurt and will be "used" to make the code in the handler
1764         // compilable although the code will never be executed.
1765         std::exception e;
1766         BOOST_TRY
1767         {
1768             return this->do_process_event(evt,is_direct_call);
1769         }
1770         BOOST_CATCH (std::exception& e)
1771         {
1772             // give a chance to the concrete state machine to handle
1773             this->exception_caught(evt,*this,e);
1774         }
1775         BOOST_CATCH_END
1776         return HANDLED_TRUE;
1777     }
1778     // handling of deferred events
1779     // if none is found in the SM, take the following empty main version
1780     template <class StateType, class Enable = int>
1781     struct handle_defer_helper
1782     {
handle_defer_helperboost::msm::back::state_machine::handle_defer_helper1783         handle_defer_helper(deferred_msg_queue_helper<library_sm>& ){}
do_pre_handle_deferredboost::msm::back::state_machine::handle_defer_helper1784         void do_pre_handle_deferred()
1785         {
1786         }
1787 
do_post_handle_deferredboost::msm::back::state_machine::handle_defer_helper1788         void do_post_handle_deferred(HandledEnum)
1789         {
1790         }
1791     };
1792     // otherwise the standard version handling the deferred events
1793     template <class StateType>
1794     struct handle_defer_helper
1795         <StateType, typename enable_if< typename ::boost::msm::back::has_fsm_deferred_events<StateType>::type,int >::type>
1796     {
handle_defer_helperboost::msm::back::state_machine::handle_defer_helper1797         handle_defer_helper(deferred_msg_queue_helper<library_sm>& a_queue):
1798             events_queue(a_queue),next_deferred_event(){}
do_pre_handle_deferredboost::msm::back::state_machine::handle_defer_helper1799         void do_pre_handle_deferred()
1800         {
1801         }
1802 
do_post_handle_deferredboost::msm::back::state_machine::handle_defer_helper1803         void do_post_handle_deferred(HandledEnum handled)
1804         {
1805             if (handled == HANDLED_TRUE)
1806             {
1807                 // a transition has been taken, it makes sense again to try processing waiting deferred events
1808                 // reset all events to not tested
1809                 for (std::size_t i = 0; i < events_queue.m_deferred_events_queue.size(); ++i)
1810                 {
1811                     events_queue.m_deferred_events_queue[i].second=false;
1812                 }
1813                 // test first event
1814                 if (!events_queue.m_deferred_events_queue.empty())
1815                 {
1816                     deferred_fct next = events_queue.m_deferred_events_queue.front().first;
1817                     events_queue.m_deferred_events_queue.pop_front();
1818                     next();
1819                 }
1820             }
1821             else
1822             {
1823                 // look for next deferred event, if any
1824                 typename deferred_events_queue_t::iterator it =
1825                     std::find_if(events_queue.m_deferred_events_queue.begin(),
1826                                  events_queue.m_deferred_events_queue.end(),
1827                                  boost::bind(&std::pair<deferred_fct,bool>::second, _1) == false);
1828                 if (it != events_queue.m_deferred_events_queue.end())
1829                 {
1830                     (*it).second = true;
1831                     deferred_fct next = (*it).first;
1832                     events_queue.m_deferred_events_queue.erase(it);
1833                     next();
1834                 }
1835             }
1836         }
1837 
1838     private:
1839         deferred_msg_queue_helper<library_sm>&  events_queue;
1840         deferred_fct                            next_deferred_event;
1841     };
1842 
1843     // handling of eventless transitions
1844     // if none is found in the SM, nothing to do
1845     template <class StateType, class Enable = void>
1846     struct handle_eventless_transitions_helper
1847     {
handle_eventless_transitions_helperboost::msm::back::state_machine::handle_eventless_transitions_helper1848         handle_eventless_transitions_helper(library_sm* , bool ){}
process_completion_eventboost::msm::back::state_machine::handle_eventless_transitions_helper1849         void process_completion_event(){}
1850     };
1851     // otherwise
1852     template <class StateType>
1853     struct handle_eventless_transitions_helper
1854         <StateType, typename enable_if< typename ::boost::msm::back::has_fsm_eventless_transition<StateType>::type >::type>
1855     {
handle_eventless_transitions_helperboost::msm::back::state_machine::handle_eventless_transitions_helper1856         handle_eventless_transitions_helper(library_sm* self_, bool handled_):self(self_),handled(handled_){}
process_completion_eventboost::msm::back::state_machine::handle_eventless_transitions_helper1857         void process_completion_event()
1858         {
1859             typedef typename ::boost::mpl::deref<
1860                 typename ::boost::mpl::begin<
1861                     typename find_completion_events<StateType>::type
1862                         >::type
1863             >::type first_completion_event;
1864             if (handled)
1865             {
1866                 self->process_event(first_completion_event() );
1867             }
1868         }
1869 
1870     private:
1871         library_sm* self;
1872         bool        handled;
1873     };
1874 
1875     // helper class called in case the event to process has been found in the fsm's internal stt and is therefore processable
1876     template<class Event>
1877     struct process_fsm_internal_table
1878     {
1879         typedef typename ::boost::mpl::has_key<processable_events_internal_table,Event>::type is_event_processable;
1880 
1881         // forward to the correct do_process
processboost::msm::back::state_machine::process_fsm_internal_table1882         static void process(Event const& evt,library_sm* self_,HandledEnum& result)
1883         {
1884             do_process(evt,self_,result,is_event_processable());
1885         }
1886     private:
1887         // the event is processable, let's try!
do_processboost::msm::back::state_machine::process_fsm_internal_table1888         static void do_process(Event const& evt,library_sm* self_,HandledEnum& result, ::boost::mpl::true_)
1889         {
1890             if (result != HANDLED_TRUE)
1891             {
1892                 typedef dispatch_table<library_sm,complete_table,Event,CompilePolicy> table;
1893                 HandledEnum res_internal = table::instance.entries[0](*self_, 0, self_->m_states[0], evt);
1894                 result = (HandledEnum)((int)result | (int)res_internal);
1895             }
1896         }
1897         // version doing nothing if the event is not in the internal stt and we can save ourselves the time trying to process
do_processboost::msm::back::state_machine::process_fsm_internal_table1898         static void do_process(Event const& ,library_sm* ,HandledEnum& , ::boost::mpl::false_)
1899         {
1900             // do nothing
1901         }
1902     };
1903 
1904     template <class StateType,class Enable=void>
1905     struct region_processing_helper
1906     {
1907     public:
region_processing_helperboost::msm::back::state_machine::region_processing_helper1908         region_processing_helper(library_sm* self_,HandledEnum& result_)
1909             :self(self_),result(result_){}
1910         template<class Event>
processboost::msm::back::state_machine::region_processing_helper1911         void process(Event const& evt)
1912         {
1913             // use this table as if it came directly from the user
1914             typedef dispatch_table<library_sm,complete_table,Event,CompilePolicy> table;
1915             // +1 because index 0 is reserved for this fsm
1916             HandledEnum res =
1917                 table::instance.entries[self->m_states[0]+1](
1918                 *self, 0, self->m_states[0], evt);
1919             result = (HandledEnum)((int)result | (int)res);
1920             // process the event in the internal table of this fsm if the event is processable (present in the table)
1921             process_fsm_internal_table<Event>::process(evt,self,result);
1922         }
1923         library_sm*     self;
1924         HandledEnum&    result;
1925     };
1926     // version with visitors
1927     template <class StateType>
1928     struct region_processing_helper<StateType,typename ::boost::enable_if<
1929                         ::boost::mpl::is_sequence<typename StateType::initial_state> >::type>
1930     {
1931         private:
1932         // process event in one region
1933         template <class region_id,int Dummy=0>
1934         struct In
1935         {
1936             template<class Event>
processboost::msm::back::state_machine::region_processing_helper::In1937             static void process(Event const& evt,library_sm* self_,HandledEnum& result_)
1938             {
1939                 // use this table as if it came directly from the user
1940                 typedef dispatch_table<library_sm,complete_table,Event,CompilePolicy> table;
1941                 // +1 because index 0 is reserved for this fsm
1942                 HandledEnum res =
1943                     table::instance.entries[self_->m_states[region_id::value]+1](
1944                     *self_, region_id::value , self_->m_states[region_id::value], evt);
1945                 result_ = (HandledEnum)((int)result_ | (int)res);
1946                 In< ::boost::mpl::int_<region_id::value+1> >::process(evt,self_,result_);
1947             }
1948         };
1949         template <int Dummy>
1950         struct In< ::boost::mpl::int_<nr_regions::value>,Dummy>
1951         {
1952             // end of processing
1953             template<class Event>
processboost::msm::back::state_machine::region_processing_helper::In1954             static void process(Event const& evt,library_sm* self_,HandledEnum& result_)
1955             {
1956                 // process the event in the internal table of this fsm if the event is processable (present in the table)
1957                 process_fsm_internal_table<Event>::process(evt,self_,result_);
1958             }
1959         };
1960         public:
region_processing_helperboost::msm::back::state_machine::region_processing_helper1961         region_processing_helper(library_sm* self_,HandledEnum& result_)
1962             :self(self_),result(result_){}
1963         template<class Event>
processboost::msm::back::state_machine::region_processing_helper1964         void process(Event const& evt)
1965         {
1966             In< ::boost::mpl::int_<0> >::process(evt,self,result);
1967         }
1968 
1969         library_sm*     self;
1970         HandledEnum&    result;
1971     };
1972 
1973     // Main function used internally to make transitions
1974     // Can only be called for internally (for example in an action method) generated events.
1975     template<class Event>
process_event_internal(Event const & evt,bool is_direct_call)1976     execute_return process_event_internal(Event const& evt, bool is_direct_call)
1977     {
1978         HandledEnum ret_handled=HANDLED_FALSE;
1979         // if the state machine has terminate or interrupt flags, check them, otherwise skip
1980         if (is_event_handling_blocked_helper<Event>
1981                 ( ::boost::mpl::bool_<has_fsm_blocking_states<library_sm>::type::value>() ) )
1982             return HANDLED_TRUE;
1983         // if a message queue is needed and processing is on the way
1984         if (!do_pre_msg_queue_helper<Event>
1985                 (evt,::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>()) )
1986         {
1987             // wait for the end of current processing
1988             return HANDLED_TRUE;
1989         }
1990         else
1991         {
1992             // prepare the next deferred event for handling
1993             // if one defer is found in the SM, otherwise skip
1994             handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
1995             defer_helper.do_pre_handle_deferred();
1996             // process event
1997             HandledEnum handled = this->do_process_helper<Event>
1998                 (evt,::boost::mpl::bool_<is_no_exception_thrown<library_sm>::type::value>(),is_direct_call);
1999             if (handled)
2000             {
2001                 ret_handled = handled;
2002             }
2003 
2004             // process completion transitions BEFORE any other event in the pool (UML Standard 2.3 15.3.14)
2005             handle_eventless_transitions_helper<library_sm> eventless_helper(this,(handled == HANDLED_TRUE));
2006             eventless_helper.process_completion_event();
2007 
2008             // after handling, take care of the deferred events
2009             defer_helper.do_post_handle_deferred(handled);
2010 
2011             // now check if some events were generated in a transition and was not handled
2012             // because of another processing, and if yes, start handling them
2013             do_post_msg_queue_helper(::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>());
2014 
2015             return ret_handled;
2016         }
2017     }
2018 
2019     // minimum event processing without exceptions, queues, etc.
2020     template<class Event>
do_process_event(Event const & evt,bool is_direct_call)2021     HandledEnum do_process_event(Event const& evt, bool is_direct_call)
2022     {
2023         HandledEnum handled = HANDLED_FALSE;
2024         // dispatch the event to every region
2025         region_processing_helper<Derived> helper(this,handled);
2026         helper.process(evt);
2027 
2028         // if the event has not been handled and we have orthogonal zones, then
2029         // generate an error on every active state
2030         // for state machine states contained in other state machines, do not handle
2031         // but let the containing sm handle the error, unless the event was generated in this fsm
2032         // (by calling process_event on this fsm object, is_direct_call == true)
2033         // completion events do not produce an error
2034         if ( (!is_contained() || is_direct_call) && !handled && !is_completion_event<Event>::type::value)
2035         {
2036             for (int i=0; i<nr_regions::value;++i)
2037             {
2038                 this->no_transition(evt,*this,this->m_states[i]);
2039             }
2040         }
2041         return handled;
2042     }
2043 
2044     // default row arguments for the compilers which accept this
2045     template <class Event>
no_guard(Event const &)2046     bool no_guard(Event const&){return true;}
2047     template <class Event>
no_action(Event const &)2048     void no_action(Event const&){}
2049 
2050 #ifndef BOOST_NO_RTTI
2051     HandledEnum process_any_event( ::boost::any const& evt);
2052 #endif
2053 
2054 private:
2055     // composite accept implementation. First calls accept on the composite, then accept on all its active states.
composite_accept()2056     void composite_accept()
2057     {
2058         this->accept();
2059         this->visit_current_states();
2060     }
2061 
2062 #define MSM_COMPOSITE_ACCEPT_SUB(z, n, unused) ARG ## n vis ## n
2063 #define MSM_COMPOSITE_ACCEPT_SUB2(z, n, unused) boost::ref( vis ## n )
2064 #define MSM_COMPOSITE_ACCEPT_EXECUTE(z, n, unused)                                      \
2065         template <BOOST_PP_ENUM_PARAMS(n, class ARG)>                                   \
2066         void composite_accept(BOOST_PP_ENUM(n, MSM_COMPOSITE_ACCEPT_SUB, ~ ) )               \
2067         {                                                                               \
2068             this->accept(BOOST_PP_ENUM_PARAMS(n,vis));                                        \
2069             this->visit_current_states(BOOST_PP_ENUM(n,MSM_COMPOSITE_ACCEPT_SUB2, ~));        \
2070         }
2071         BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_COMPOSITE_ACCEPT_EXECUTE, ~)
2072 #undef MSM_COMPOSITE_ACCEPT_EXECUTE
2073 #undef MSM_COMPOSITE_ACCEPT_SUB
2074 #undef MSM_COMPOSITE_ACCEPT_SUB2
2075 
2076     // helper used to call the init states at the start of the state machine
2077     template <class Event>
2078     struct call_init
2079     {
call_initboost::msm::back::state_machine::call_init2080         call_init(Event const& an_event,library_sm* self_):
2081                 evt(an_event),self(self_){}
2082         template <class State>
operator ()boost::msm::back::state_machine::call_init2083         void operator()(boost::msm::wrap<State> const&)
2084         {
2085             execute_entry(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
2086         }
2087     private:
2088         Event const& evt;
2089         library_sm* self;
2090     };
2091     // helper for flag handling. Uses OR by default on orthogonal zones.
2092     template <class Flag,bool orthogonalStates>
2093     struct FlagHelper
2094     {
helperboost::msm::back::state_machine::FlagHelper2095         static bool helper(library_sm const& sm,flag_handler* )
2096         {
2097             // by default we use OR to accumulate the flags
2098             return sm.is_flag_active<Flag,Flag_OR>();
2099         }
2100     };
2101     template <class Flag>
2102     struct FlagHelper<Flag,false>
2103     {
helperboost::msm::back::state_machine::FlagHelper2104         static bool helper(library_sm const& sm,flag_handler* flags_entries)
2105         {
2106             // just one active state, so we can call operator[] with 0
2107             return flags_entries[sm.current_state()[0]](sm);
2108         }
2109     };
2110     // handling of flag
2111     // defines a true and false functions plus a forwarding one for composite states
2112     template <class StateType,class Flag>
2113     struct FlagHandler
2114     {
flag_trueboost::msm::back::state_machine::FlagHandler2115         static bool flag_true(library_sm const& )
2116         {
2117             return true;
2118         }
flag_falseboost::msm::back::state_machine::FlagHandler2119         static bool flag_false(library_sm const& )
2120         {
2121             return false;
2122         }
forwardboost::msm::back::state_machine::FlagHandler2123         static bool forward(library_sm const& fsm)
2124         {
2125             return ::boost::fusion::at_key<StateType>(fsm.m_substate_list).template is_flag_active<Flag>();
2126         }
2127     };
2128     template <class Flag>
2129     struct init_flags
2130     {
2131     private:
2132         // helper function, helps hiding the forward function for non-state machines states.
2133         template <class T>
helperboost::msm::back::state_machine::init_flags2134         void helper (flag_handler* an_entry,int offset, ::boost::mpl::true_ const &  )
2135         {
2136             // composite => forward
2137             an_entry[offset] = &FlagHandler<T,Flag>::forward;
2138         }
2139         template <class T>
helperboost::msm::back::state_machine::init_flags2140         void helper (flag_handler* an_entry,int offset, ::boost::mpl::false_ const &  )
2141         {
2142             // default no flag
2143             an_entry[offset] = &FlagHandler<T,Flag>::flag_false;
2144         }
2145         // attributes
2146         flag_handler* entries;
2147 
2148     public:
init_flagsboost::msm::back::state_machine::init_flags2149         init_flags(flag_handler* entries_)
2150             : entries(entries_)
2151         {}
2152 
2153         // Flags initializer function object, used with mpl::for_each
2154         template <class StateType>
operator ()boost::msm::back::state_machine::init_flags2155         void operator()( ::boost::msm::wrap<StateType> const& )
2156         {
2157             typedef typename get_flag_list<StateType>::type flags;
2158             typedef typename ::boost::mpl::contains<flags,Flag >::type found;
2159             typedef typename is_composite_state<StateType>::type composite;
2160 
2161             BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,StateType>::type::value));
2162             if (found::type::value)
2163             {
2164                 // the type defined the flag => true
2165                 entries[state_id] = &FlagHandler<StateType,Flag>::flag_true;
2166             }
2167             else
2168             {
2169                 // false or forward
2170                 typedef typename ::boost::mpl::and_<
2171                             typename is_composite_state<StateType>::type,
2172                             typename ::boost::mpl::not_<
2173                                     typename has_non_forwarding_flag<Flag>::type>::type >::type composite_no_forward;
2174 
2175                 helper<StateType>(entries,state_id,::boost::mpl::bool_<composite_no_forward::type::value>());
2176             }
2177         }
2178     };
2179     // maintains for every flag a static array containing the flag value for every state
2180     template <class Flag>
get_entries_for_flag() const2181     flag_handler* get_entries_for_flag() const
2182     {
2183         BOOST_STATIC_CONSTANT(int, max_state = (mpl::size<state_list>::value));
2184 
2185         static flag_handler flags_entries[max_state];
2186         // build a state list
2187         ::boost::mpl::for_each<state_list, boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2188                         (init_flags<Flag>(flags_entries));
2189         return flags_entries;
2190     }
2191 
2192     // helper used to create a state using the correct constructor
2193     template <class State, class Enable=void>
2194     struct create_state_helper
2195     {
set_smboost::msm::back::state_machine::create_state_helper2196         static void set_sm(library_sm* )
2197         {
2198             // state doesn't need its sm
2199         }
2200     };
2201     // create a state requiring a pointer to the state machine
2202     template <class State>
2203     struct create_state_helper<State,typename boost::enable_if<typename State::needs_sm >::type>
2204     {
set_smboost::msm::back::state_machine::create_state_helper2205         static void set_sm(library_sm* sm)
2206         {
2207             // create and set the fsm
2208             ::boost::fusion::at_key<State>(sm->m_substate_list).set_sm_ptr(sm);
2209         }
2210     };
2211         // main unspecialized helper class
2212         template <class StateType,int ARGS>
2213         struct visitor_args;
2214 
2215 #define MSM_VISITOR_ARGS_SUB(z, n, unused) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1))
2216 #define MSM_VISITOR_ARGS_TYPEDEF_SUB(z, n, unused) typename StateType::accept_sig::argument ## n
2217 
2218 #define MSM_VISITOR_ARGS_EXECUTE(z, n, unused)                                              \
2219     template <class StateType>                                                              \
2220     struct visitor_args<StateType,n>                                                        \
2221     {                                                                                       \
2222         template <class State>                                                              \
2223         static typename enable_if_c<!is_composite_state<State>::value,void >::type          \
2224         helper (library_sm* sm,                                                             \
2225         int id,StateType& astate)                                                           \
2226         {                                                                                   \
2227             sm->m_visitors.insert(id, boost::bind(&StateType::accept,                       \
2228                 ::boost::ref(astate) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_SUB, ~) ));   \
2229         }                                                                                   \
2230         template <class State>                                                              \
2231         static typename enable_if_c<is_composite_state<State>::value,void >::type           \
2232         helper (library_sm* sm,                                                             \
2233         int id,StateType& astate)                                                           \
2234         {                                                                                   \
2235             void (StateType::*caccept)(BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_TYPEDEF_SUB, ~ ) )           \
2236                                         = &StateType::composite_accept;                     \
2237             sm->m_visitors.insert(id, boost::bind(caccept,             \
2238             ::boost::ref(astate) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, MSM_VISITOR_ARGS_SUB, ~) ));                 \
2239         }                                                                                   \
2240 };
2241 BOOST_PP_REPEAT(BOOST_PP_ADD(BOOST_MSM_VISITOR_ARG_SIZE,1), MSM_VISITOR_ARGS_EXECUTE, ~)
2242 #undef MSM_VISITOR_ARGS_EXECUTE
2243 #undef MSM_VISITOR_ARGS_SUB
2244 
2245 // the IBM compiler seems to have problems with nested classes
2246 // the same seems to apply to the Apple version of gcc 4.0.1 (just in case we do for < 4.1)
2247 // and also to MS VC < 8
2248 #if defined (__IBMCPP__) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2249      public:
2250 #endif
2251     template<class ContainingSM>
set_containing_sm(ContainingSM * sm)2252     void set_containing_sm(ContainingSM* sm)
2253     {
2254         m_is_included=true;
2255         ::boost::fusion::for_each(m_substate_list,add_state<ContainingSM>(this,sm));
2256     }
2257 #if defined (__IBMCPP__) || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2258      private:
2259 #endif
2260     // A function object for use with mpl::for_each that stuffs
2261     // states into the state list.
2262     template<class ContainingSM>
2263     struct add_state
2264     {
add_stateboost::msm::back::state_machine::add_state2265         add_state(library_sm* self_,ContainingSM* sm)
2266             : self(self_),containing_sm(sm){}
2267 
2268         // State is a sub fsm with exit pseudo states and gets a pointer to this fsm, so it can build a callback
2269         template <class StateType>
2270         typename ::boost::enable_if<
2271             typename is_composite_state<StateType>::type,void >::type
new_state_helperboost::msm::back::state_machine::add_state2272         new_state_helper(boost::msm::back::dummy<0> = 0) const
2273         {
2274             ::boost::fusion::at_key<StateType>(self->m_substate_list).set_containing_sm(containing_sm);
2275         }
2276         // State is a sub fsm without exit pseudo states and does not get a callback to this fsm
2277         // or state is a normal state and needs nothing except creation
2278         template <class StateType>
2279         typename ::boost::enable_if<
2280             typename boost::mpl::and_<typename boost::mpl::not_
2281                                                     <typename is_composite_state<StateType>::type>::type,
2282                                       typename boost::mpl::not_
2283                                                     <typename is_pseudo_exit<StateType>::type>::type
2284                    >::type,void>::type
new_state_helperboost::msm::back::state_machine::add_state2285         new_state_helper( ::boost::msm::back::dummy<1> = 0) const
2286         {
2287             //nothing to do
2288         }
2289         // state is exit pseudo state and gets callback to target fsm
2290         template <class StateType>
2291         typename ::boost::enable_if<typename is_pseudo_exit<StateType>::type,void >::type
new_state_helperboost::msm::back::state_machine::add_state2292         new_state_helper( ::boost::msm::back::dummy<2> = 0) const
2293         {
2294             execute_return (ContainingSM::*pf) (typename StateType::event const& evt)=
2295                 &ContainingSM::process_event;
2296             ::boost::function<execute_return (typename StateType::event const&)> fct =
2297                 ::boost::bind(pf,containing_sm,_1);
2298             ::boost::fusion::at_key<StateType>(self->m_substate_list).set_forward_fct(fct);
2299         }
2300         // for every defined state in the sm
2301         template <class State>
operator ()boost::msm::back::state_machine::add_state2302         void operator()( State const&) const
2303         {
2304             //create a new state with the defined id and type
2305             BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,State>::value));
2306 
2307             this->new_state_helper<State>(),
2308             create_state_helper<State>::set_sm(self);
2309             // create a visitor callback
2310             visitor_helper(state_id,::boost::fusion::at_key<State>(self->m_substate_list),
2311                            ::boost::mpl::bool_<has_accept_sig<State>::type::value>());
2312         }
2313     private:
2314         // support possible use of a visitor if accept_sig is defined
2315         template <class StateType>
visitor_helperboost::msm::back::state_machine::add_state2316         void visitor_helper(int id,StateType& astate, ::boost::mpl::true_ const & ) const
2317         {
2318             visitor_args<StateType,StateType::accept_sig::args_number>::
2319                 template helper<StateType>(self,id,astate);
2320         }
2321         template <class StateType>
visitor_helperboost::msm::back::state_machine::add_state2322         void visitor_helper(int ,StateType& , ::boost::mpl::false_ const &) const
2323         {
2324             // nothing to do
2325         }
2326 
2327         library_sm*      self;
2328         ContainingSM*    containing_sm;
2329     };
2330 
2331      // helper used to copy every state if needed
2332      struct copy_helper
2333      {
copy_helperboost::msm::back::state_machine::copy_helper2334          copy_helper(library_sm* sm):
2335            m_sm(sm){}
2336          template <class StateType>
operator ()boost::msm::back::state_machine::copy_helper2337          void operator()( ::boost::msm::wrap<StateType> const& )
2338          {
2339             BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,StateType>::type::value));
2340             // possibly also set the visitor
2341             visitor_helper<StateType>(state_id);
2342 
2343             // and for states that keep a pointer to the fsm, reset the pointer
2344             create_state_helper<StateType>::set_sm(m_sm);
2345          }
2346          template <class StateType>
2347          typename ::boost::enable_if<typename has_accept_sig<StateType>::type,void >::type
visitor_helperboost::msm::back::state_machine::copy_helper2348              visitor_helper(int id) const
2349          {
2350              visitor_args<StateType,StateType::accept_sig::args_number>::template helper<StateType>
2351                  (m_sm,id,::boost::fusion::at_key<StateType>(m_sm->m_substate_list));
2352          }
2353          template <class StateType>
2354          typename ::boost::disable_if<typename has_accept_sig<StateType>::type,void >::type
visitor_helperboost::msm::back::state_machine::copy_helper2355              visitor_helper(int) const
2356          {
2357              // nothing to do
2358          }
2359 
2360          library_sm*     m_sm;
2361      };
2362      // helper to copy the active states attribute
2363      template <class region_id,int Dummy=0>
2364      struct region_copy_helper
2365      {
do_copyboost::msm::back::state_machine::region_copy_helper2366          static void do_copy(library_sm* self_,library_sm const& rhs)
2367          {
2368              self_->m_states[region_id::value] = rhs.m_states[region_id::value];
2369              region_copy_helper< ::boost::mpl::int_<region_id::value+1> >::do_copy(self_,rhs);
2370          }
2371      };
2372      template <int Dummy>
2373      struct region_copy_helper< ::boost::mpl::int_<nr_regions::value>,Dummy>
2374      {
2375          // end of processing
do_copyboost::msm::back::state_machine::region_copy_helper2376          static void do_copy(library_sm*,library_sm const& ){}
2377      };
2378      // copy functions for deep copy (no need of a 2nd version for NoCopy as noncopyable handles it)
do_copy(library_sm const & rhs,::boost::msm::back::dummy<0>=0)2379      void do_copy (library_sm const& rhs,
2380               ::boost::msm::back::dummy<0> = 0)
2381      {
2382          // deep copy simply assigns the data
2383          region_copy_helper< ::boost::mpl::int_<0> >::do_copy(this,rhs);
2384          m_events_queue = rhs.m_events_queue;
2385          m_deferred_events_queue = rhs.m_deferred_events_queue;
2386          m_history = rhs.m_history;
2387          m_event_processing = rhs.m_event_processing;
2388          m_is_included = rhs.m_is_included;
2389          m_substate_list = rhs.m_substate_list;
2390          // except for the states themselves, which get duplicated
2391 
2392          ::boost::mpl::for_each<state_list, ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2393                         (copy_helper(this));
2394      }
2395 
2396      // helper used to call the correct entry/exit method
2397      // unfortunately in O(number of states in the sub-sm) but should be better than a virtual call
2398      template<class Event,bool is_entry>
2399      struct entry_exit_helper
2400      {
entry_exit_helperboost::msm::back::state_machine::entry_exit_helper2401          entry_exit_helper(int id,Event const& e,library_sm* self_):
2402             state_id(id),evt(e),self(self_){}
2403          // helper for entry actions
2404          template <class IsEntry,class State>
2405          typename ::boost::enable_if<typename IsEntry::type,void >::type
helperboost::msm::back::state_machine::entry_exit_helper2406          helper( ::boost::msm::back::dummy<0> = 0)
2407          {
2408              BOOST_STATIC_CONSTANT(int, id = (get_state_id<stt,State>::value));
2409              if (id == state_id)
2410              {
2411                  execute_entry<State>(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
2412              }
2413          }
2414          // helper for exit actions
2415          template <class IsEntry,class State>
2416          typename boost::disable_if<typename IsEntry::type,void >::type
helperboost::msm::back::state_machine::entry_exit_helper2417          helper( ::boost::msm::back::dummy<1> = 0)
2418          {
2419              BOOST_STATIC_CONSTANT(int, id = (get_state_id<stt,State>::value));
2420              if (id == state_id)
2421              {
2422                  execute_exit<State>(::boost::fusion::at_key<State>(self->m_substate_list),evt,*self);
2423              }
2424          }
2425          // iterates through all states to find the one to be activated
2426          template <class State>
operator ()boost::msm::back::state_machine::entry_exit_helper2427          void operator()( ::boost::msm::wrap<State> const&)
2428          {
2429              entry_exit_helper<Event,is_entry>::template helper< ::boost::mpl::bool_<is_entry>,State >();
2430          }
2431      private:
2432          int            state_id;
2433          Event const&   evt;
2434          library_sm*    self;
2435      };
2436 
2437      // helper to start the fsm
2438      template <class region_id,int Dummy=0>
2439      struct region_start_helper
2440      {
2441          template<class Event>
do_startboost::msm::back::state_machine::region_start_helper2442          static void do_start(library_sm* self_,Event const& incomingEvent)
2443          {
2444              //forward the event for handling by sub state machines
2445              ::boost::mpl::for_each<state_list, ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2446                  (entry_exit_helper<Event,true>(self_->m_states[region_id::value],incomingEvent,self_));
2447              region_start_helper
2448                  < ::boost::mpl::int_<region_id::value+1> >::do_start(self_,incomingEvent);
2449          }
2450      };
2451      template <int Dummy>
2452      struct region_start_helper< ::boost::mpl::int_<nr_regions::value>,Dummy>
2453      {
2454          // end of processing
2455          template<class Event>
do_startboost::msm::back::state_machine::region_start_helper2456          static void do_start(library_sm*,Event const& ){}
2457      };
2458      // start for states machines which are themselves embedded in other state machines (composites)
2459      template <class Event>
internal_start(Event const & incomingEvent)2460      void internal_start(Event const& incomingEvent)
2461      {
2462          region_start_helper< ::boost::mpl::int_<0> >::do_start(this,incomingEvent);
2463          // give a chance to handle an anonymous (eventless) transition
2464          handle_eventless_transitions_helper<library_sm> eventless_helper(this,true);
2465          eventless_helper.process_completion_event();
2466      }
2467 
2468      template <class StateType>
2469      struct find_region_id
2470      {
2471          template <int region,int Dummy=0>
2472          struct In
2473          {
2474              enum {region_index=region};
2475          };
2476          // if the user provides no region, find it!
2477          template<int Dummy>
2478          struct In<-1,Dummy>
2479          {
2480              typedef typename build_orthogonal_regions<
2481                  library_sm,
2482                  initial_states
2483              >::type all_regions;
2484              enum {region_index= find_region_index<all_regions,StateType>::value };
2485          };
2486          enum {region_index = In<StateType::zone_index>::region_index };
2487      };
2488      // helper used to set the correct state as active state upon entry into a fsm
2489      struct direct_event_start_helper
2490      {
direct_event_start_helperboost::msm::back::state_machine::direct_event_start_helper2491          direct_event_start_helper(library_sm* self_):self(self_){}
2492          // this variant is for the standard case, entry due to activation of the containing FSM
2493          template <class EventType,class FsmType>
2494          typename ::boost::disable_if<typename has_direct_entry<EventType>::type,void>::type
operator ()boost::msm::back::state_machine::direct_event_start_helper2495              operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<0> = 0)
2496          {
2497              (static_cast<Derived*>(self))->on_entry(evt,fsm);
2498              self->internal_start(evt);
2499          }
2500 
2501          // this variant is for the direct entry case (just one entry, not a sequence of entries)
2502          template <class EventType,class FsmType>
2503          typename ::boost::enable_if<
2504              typename ::boost::mpl::and_<
2505                         typename ::boost::mpl::not_< typename is_pseudo_entry<
2506                                     typename EventType::active_state>::type >::type,
2507                         typename ::boost::mpl::and_<typename has_direct_entry<EventType>::type,
2508                                                     typename ::boost::mpl::not_<typename ::boost::mpl::is_sequence
2509                                                             <typename EventType::active_state>::type >::type
2510                                                     >::type>::type,void
2511                                   >::type
operator ()boost::msm::back::state_machine::direct_event_start_helper2512          operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2513          {
2514              (static_cast<Derived*>(self))->on_entry(evt,fsm);
2515              int state_id = get_state_id<stt,typename EventType::active_state::wrapped_entry>::value;
2516              BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index >= 0);
2517              BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index < nr_regions::value);
2518              // just set the correct zone, the others will be default/history initialized
2519              self->m_states[find_region_id<typename EventType::active_state::wrapped_entry>::region_index] = state_id;
2520              self->internal_start(evt.m_event);
2521          }
2522 
2523          // this variant is for the fork entry case (a sequence on entries)
2524          template <class EventType,class FsmType>
2525          typename ::boost::enable_if<
2526              typename ::boost::mpl::and_<
2527                     typename ::boost::mpl::not_<
2528                                     typename is_pseudo_entry<typename EventType::active_state>::type >::type,
2529                     typename ::boost::mpl::and_<typename has_direct_entry<EventType>::type,
2530                                                 typename ::boost::mpl::is_sequence<
2531                                                                 typename EventType::active_state>::type
2532                                                 >::type>::type,void
2533                                 >::type
operator ()boost::msm::back::state_machine::direct_event_start_helper2534          operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0)
2535          {
2536              (static_cast<Derived*>(self))->on_entry(evt,fsm);
2537              ::boost::mpl::for_each<typename EventType::active_state,
2538                                     ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2539                                                         (fork_helper<EventType>(self,evt));
2540              // set the correct zones, the others (if any) will be default/history initialized
2541              self->internal_start(evt.m_event);
2542          }
2543 
2544          // this variant is for the pseudo state entry case
2545          template <class EventType,class FsmType>
2546          typename ::boost::enable_if<
2547              typename is_pseudo_entry<typename EventType::active_state >::type,void
2548                                     >::type
operator ()boost::msm::back::state_machine::direct_event_start_helper2549          operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<3> = 0)
2550          {
2551              // entry on the FSM
2552              (static_cast<Derived*>(self))->on_entry(evt,fsm);
2553              int state_id = get_state_id<stt,typename EventType::active_state::wrapped_entry>::value;
2554              BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index >= 0);
2555              BOOST_STATIC_ASSERT(find_region_id<typename EventType::active_state::wrapped_entry>::region_index < nr_regions::value);
2556              // given region starts with the entry pseudo state as active state
2557              self->m_states[find_region_id<typename EventType::active_state::wrapped_entry>::region_index] = state_id;
2558              self->internal_start(evt.m_event);
2559              // and we process the transition in the zone of the newly active state
2560              // (entry pseudo states are, according to UML, a state connecting 1 transition outside to 1 inside
2561              self->process_event(evt.m_event);
2562          }
2563      private:
2564          // helper for the fork case, does almost like the direct entry
2565          library_sm* self;
2566          template <class EventType>
2567          struct fork_helper
2568          {
fork_helperboost::msm::back::state_machine::direct_event_start_helper::fork_helper2569              fork_helper(library_sm* self_,EventType const& evt_):
2570                 helper_self(self_),helper_evt(evt_){}
2571              template <class StateType>
operator ()boost::msm::back::state_machine::direct_event_start_helper::fork_helper2572              void operator()( ::boost::msm::wrap<StateType> const& )
2573              {
2574                  int state_id = get_state_id<stt,typename StateType::wrapped_entry>::value;
2575                  BOOST_STATIC_ASSERT(find_region_id<typename StateType::wrapped_entry>::region_index >= 0);
2576                  BOOST_STATIC_ASSERT(find_region_id<typename StateType::wrapped_entry>::region_index < nr_regions::value);
2577                  helper_self->m_states[find_region_id<typename StateType::wrapped_entry>::region_index] = state_id;
2578              }
2579          private:
2580              library_sm*        helper_self;
2581              EventType const&   helper_evt;
2582          };
2583      };
2584 
2585      // helper for entry
2586      template <class region_id,int Dummy=0>
2587      struct region_entry_exit_helper
2588      {
2589          template<class Event>
do_entryboost::msm::back::state_machine::region_entry_exit_helper2590          static void do_entry(library_sm* self_,Event const& incomingEvent)
2591          {
2592              self_->m_states[region_id::value] =
2593                  self_->m_history.history_entry(incomingEvent)[region_id::value];
2594              region_entry_exit_helper
2595                  < ::boost::mpl::int_<region_id::value+1> >::do_entry(self_,incomingEvent);
2596          }
2597          template<class Event>
do_exitboost::msm::back::state_machine::region_entry_exit_helper2598          static void do_exit(library_sm* self_,Event const& incomingEvent)
2599          {
2600              ::boost::mpl::for_each<state_list, ::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
2601                  (entry_exit_helper<Event,false>(self_->m_states[region_id::value],incomingEvent,self_));
2602              region_entry_exit_helper
2603                  < ::boost::mpl::int_<region_id::value+1> >::do_exit(self_,incomingEvent);
2604          }
2605      };
2606      template <int Dummy>
2607      struct region_entry_exit_helper< ::boost::mpl::int_<nr_regions::value>,Dummy>
2608      {
2609          // end of processing
2610          template<class Event>
do_entryboost::msm::back::state_machine::region_entry_exit_helper2611          static void do_entry(library_sm*,Event const& ){}
2612          template<class Event>
do_exitboost::msm::back::state_machine::region_entry_exit_helper2613          static void do_exit(library_sm*,Event const& ){}
2614      };
2615      // entry/exit for states machines which are themselves embedded in other state machines (composites)
2616      template <class Event,class FsmType>
do_entry(Event const & incomingEvent,FsmType & fsm)2617      void do_entry(Event const& incomingEvent,FsmType& fsm)
2618      {
2619         // by default we activate the history/init states, can be overwritten by direct_event_start_helper
2620         region_entry_exit_helper< ::boost::mpl::int_<0> >::do_entry(this,incomingEvent);
2621         // block immediate handling of events
2622         m_event_processing = true;
2623         // if the event is generating a direct entry/fork, set the current state(s) to the direct state(s)
2624         direct_event_start_helper(this)(incomingEvent,fsm);
2625         // handle messages which were generated and blocked in the init calls
2626         m_event_processing = false;
2627         // look for deferred events waiting
2628         handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
2629         defer_helper.do_post_handle_deferred(HANDLED_TRUE);
2630         process_message_queue(this);
2631      }
2632      template <class Event,class FsmType>
do_exit(Event const & incomingEvent,FsmType & fsm)2633      void do_exit(Event const& incomingEvent,FsmType& fsm)
2634      {
2635         // first recursively exit the sub machines
2636         // forward the event for handling by sub state machines
2637         region_entry_exit_helper< ::boost::mpl::int_<0> >::do_exit(this,incomingEvent);
2638         // then call our own exit
2639         (static_cast<Derived*>(this))->on_exit(incomingEvent,fsm);
2640         // give the history a chance to handle this (or not).
2641         m_history.history_exit(this->m_states);
2642         // history decides what happens with deferred events
2643         if (!m_history.process_deferred_events(incomingEvent))
2644         {
2645             clear_deferred_queue();
2646         }
2647      }
2648 
2649     // the IBM and VC<8 compilers seem to have problems with the friend declaration of dispatch_table
2650 #if defined (__IBMCPP__) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2651      public:
2652 #endif
2653     // no transition for event.
2654     template <class Event>
call_no_transition(library_sm &,int,int,Event const &)2655     static HandledEnum call_no_transition(library_sm& , int , int , Event const& )
2656     {
2657         return HANDLED_FALSE;
2658     }
2659     // no transition for event for internal transitions (not an error).
2660     template <class Event>
call_no_transition_internal(library_sm &,int,int,Event const &)2661     static HandledEnum call_no_transition_internal(library_sm& , int , int , Event const& )
2662     {
2663         //// reject to give others a chance to handle
2664         //return HANDLED_GUARD_REJECT;
2665         return HANDLED_FALSE;
2666     }
2667     // called for deferred events. Address set in the dispatch_table at init
2668     template <class Event>
defer_transition(library_sm & fsm,int,int,Event const & e)2669     static HandledEnum defer_transition(library_sm& fsm, int , int , Event const& e)
2670     {
2671         fsm.defer_event(e);
2672         return HANDLED_DEFERRED;
2673     }
2674     // called for completion events. Default address set in the dispatch_table at init
2675     // prevents no-transition detection for completion events
2676     template <class Event>
default_eventless_transition(library_sm &,int,int,Event const &)2677     static HandledEnum default_eventless_transition(library_sm&, int, int , Event const&)
2678     {
2679         return HANDLED_FALSE;
2680     }
2681 #if defined (__IBMCPP__) || (defined(_MSC_VER) && (_MSC_VER < 1400))
2682      private:
2683 #endif
2684     // puts a deferred event in the queue
post_deferred_event(deferred_fct & deferred)2685     void post_deferred_event(deferred_fct& deferred)
2686     {
2687         m_deferred_events_queue.m_deferred_events_queue.push_back(std::make_pair(deferred,true));
2688     }
2689     // removes one event from the message queue and processes it
2690     template <class StateType>
process_message_queue(StateType *,typename::boost::disable_if<typename is_no_message_queue<StateType>::type,void>::type * =0)2691     void process_message_queue(StateType*,
2692                                typename ::boost::disable_if<typename is_no_message_queue<StateType>::type,void >::type* = 0)
2693     {
2694         if (!m_events_queue.m_events_queue.empty())
2695         {
2696             transition_fct to_call = m_events_queue.m_events_queue.front();
2697             m_events_queue.m_events_queue.pop_front();
2698             to_call();
2699         }
2700     }
2701     template <class StateType>
process_message_queue(StateType *,typename::boost::enable_if<typename is_no_message_queue<StateType>::type,void>::type * =0)2702     void process_message_queue(StateType*,
2703                                typename ::boost::enable_if<typename is_no_message_queue<StateType>::type,void >::type* = 0)
2704     {
2705         // nothing to process
2706     }
2707     // helper function. In cases where the event is wrapped (target is a direct entry states)
2708     // we want to send only the real event to on_entry, not the wrapper.
2709     template <class EventType>
2710     static
2711     typename boost::enable_if<typename has_direct_entry<EventType>::type,typename EventType::contained_event const& >::type
remove_direct_entry_event_wrapper(EventType const & evt,boost::msm::back::dummy<0>=0)2712     remove_direct_entry_event_wrapper(EventType const& evt,boost::msm::back::dummy<0> = 0)
2713     {
2714         return evt.m_event;
2715     }
2716     template <class EventType>
2717     static typename boost::disable_if<typename has_direct_entry<EventType>::type,EventType const& >::type
remove_direct_entry_event_wrapper(EventType const & evt,boost::msm::back::dummy<1>=0)2718     remove_direct_entry_event_wrapper(EventType const& evt,boost::msm::back::dummy<1> = 0)
2719     {
2720         // identity. No wrapper
2721         return evt;
2722     }
2723     // calls the entry/exit or on_entry/on_exit depending on the state type
2724     // (avoids calling virtually)
2725     // variant for FSMs
2726     template <class StateType,class EventType,class FsmType>
2727     static
2728         typename boost::enable_if<typename is_composite_state<StateType>::type,void >::type
execute_entry(StateType & astate,EventType const & evt,FsmType & fsm,boost::msm::back::dummy<0>=0)2729         execute_entry(StateType& astate,EventType const& evt,FsmType& fsm,boost::msm::back::dummy<0> = 0)
2730     {
2731         // calls on_entry on the fsm then handles direct entries, fork, entry pseudo state
2732         astate.do_entry(evt,fsm);
2733     }
2734     // variant for states
2735     template <class StateType,class EventType,class FsmType>
2736     static
2737         typename ::boost::disable_if<
2738             typename ::boost::mpl::or_<typename is_composite_state<StateType>::type,
2739                                        typename is_pseudo_exit<StateType>::type >::type,void >::type
execute_entry(StateType & astate,EventType const & evt,FsmType & fsm,::boost::msm::back::dummy<1>=0)2740     execute_entry(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2741     {
2742         // simple call to on_entry
2743         astate.on_entry(remove_direct_entry_event_wrapper(evt),fsm);
2744     }
2745     // variant for exit pseudo states
2746     template <class StateType,class EventType,class FsmType>
2747     static
2748         typename ::boost::enable_if<typename is_pseudo_exit<StateType>::type,void >::type
execute_entry(StateType & astate,EventType const & evt,FsmType & fsm,::boost::msm::back::dummy<2>=0)2749     execute_entry(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0)
2750     {
2751         // calls on_entry on the state then forward the event to the transition which should be defined inside the
2752         // contained fsm
2753         astate.on_entry(evt,fsm);
2754         astate.forward_event(evt);
2755     }
2756     template <class StateType,class EventType,class FsmType>
2757     static
2758         typename ::boost::enable_if<typename is_composite_state<StateType>::type,void >::type
execute_exit(StateType & astate,EventType const & evt,FsmType & fsm,::boost::msm::back::dummy<0>=0)2759     execute_exit(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<0> = 0)
2760     {
2761         astate.do_exit(evt,fsm);
2762     }
2763     template <class StateType,class EventType,class FsmType>
2764     static
2765         typename ::boost::disable_if<typename is_composite_state<StateType>::type,void >::type
execute_exit(StateType & astate,EventType const & evt,FsmType & fsm,::boost::msm::back::dummy<1>=0)2766     execute_exit(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2767     {
2768         // simple call to on_exit
2769         astate.on_exit(evt,fsm);
2770     }
2771 
2772     // helper allowing special handling of direct entries / fork
2773     template <class StateType,class TargetType,class EventType,class FsmType>
2774     static
2775         typename ::boost::disable_if<
2776             typename ::boost::mpl::or_<typename has_explicit_entry_state<TargetType>::type,
2777                                        ::boost::mpl::is_sequence<TargetType> >::type,void>::type
convert_event_and_execute_entry(StateType & astate,EventType const & evt,FsmType & fsm,::boost::msm::back::dummy<1>=0)2778     convert_event_and_execute_entry(StateType& astate,EventType const& evt, FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
2779     {
2780         // if the target is a normal state, do the standard entry handling
2781         execute_entry<StateType>(astate,evt,fsm);
2782     }
2783     template <class StateType,class TargetType,class EventType,class FsmType>
2784     static
2785         typename ::boost::enable_if<
2786             typename ::boost::mpl::or_<typename has_explicit_entry_state<TargetType>::type,
2787                                        ::boost::mpl::is_sequence<TargetType> >::type,void >::type
convert_event_and_execute_entry(StateType & astate,EventType const & evt,FsmType & fsm,::boost::msm::back::dummy<0>=0)2788     convert_event_and_execute_entry(StateType& astate,EventType const& evt, FsmType& fsm, ::boost::msm::back::dummy<0> = 0)
2789     {
2790         // for the direct entry, pack the event in a wrapper so that we handle it differently during fsm entry
2791         execute_entry(astate,msm::back::direct_entry_event<TargetType,EventType>(evt),fsm);
2792     }
2793 
2794     // creates all the states
2795     template <class ContainingSM>
fill_states(ContainingSM * containing_sm=0)2796     void fill_states(ContainingSM* containing_sm=0)
2797     {
2798         // checks that regions are truly orthogonal
2799         FsmCheckPolicy::template check_orthogonality<library_sm>();
2800         // checks that all states are reachable
2801         FsmCheckPolicy::template check_unreachable_states<library_sm>();
2802 
2803         BOOST_STATIC_CONSTANT(int, max_state = (mpl::size<state_list>::value));
2804         // allocate the place without reallocation
2805         m_visitors.fill_visitors(max_state);
2806         ::boost::fusion::for_each(m_substate_list,add_state<ContainingSM>(this,containing_sm));
2807 
2808     }
2809 
2810 private:
2811     template <class StateType,class Enable=void>
2812     struct msg_queue_helper
2813     {
2814     public:
msg_queue_helperboost::msm::back::state_machine::msg_queue_helper2815         msg_queue_helper():m_events_queue(){}
2816         events_queue_t              m_events_queue;
2817     };
2818     template <class StateType>
2819     struct msg_queue_helper<StateType,
2820         typename ::boost::enable_if<typename is_no_message_queue<StateType>::type >::type>
2821     {
2822     };
2823 
2824     template <class Fsm,class Stt, class Event, class Compile>
2825     friend struct dispatch_table;
2826 
2827     // data members
2828     int                             m_states[nr_regions::value];
2829     msg_queue_helper<library_sm>    m_events_queue;
2830     deferred_msg_queue_helper
2831         <library_sm>                m_deferred_events_queue;
2832     concrete_history                m_history;
2833     bool                            m_event_processing;
2834     bool                            m_is_included;
2835     visitor_fct_helper<BaseState>   m_visitors;
2836     substate_list                   m_substate_list;
2837 
2838 
2839 };
2840 
2841 } } }// boost::msm::back
2842 #endif //BOOST_MSM_BACK_STATEMACHINE_H
2843 
2844