]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/msm/include/boost/msm/back/state_machine.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / msm / include / boost / msm / back / state_machine.hpp
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
95 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:
215 visitor_fct_helper(){}
216 void fill_visitors(int)
217 {
218 }
219 template <class FCT>
220 void insert(int,FCT)
221 {
222 }
223 template <class VISITOR>
224 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:
233 visitor_fct_helper():m_state_visitors(){}
234 void fill_visitors(int number_of_states)
235 {
236 m_state_visitors.resize(number_of_states);
237 }
238 template <class FCT>
239 void insert(int index,FCT fct)
240 {
241 m_state_visitors[index]=fct;
242 }
243 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 {
269 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:
277 deferred_msg_queue_helper():m_deferred_events_queue(){}
278 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>
335 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 }
340 void set_forward_fct(::boost::function<execute_return (Event const&)> fct)
341 {
342 m_forward = fct;
343 }
344 exit_pt():m_forward(){}
345 // by assignments, we keep our forwarding functor unchanged as our containing SM did not change
346 template <class RHS>
347 exit_pt(RHS&):m_forward(){}
348 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>
360 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>
370 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
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.
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
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.
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.
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.
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
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.
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
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.
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.
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.
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
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.
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
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.
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.
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.
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
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.
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
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.
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;
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;
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.
1021 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)
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>
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)
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>
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>
1262 execute_return process_event(Event const& evt)
1263 {
1264 return process_event_internal(evt,true);
1265 }
1266
1267 template <class EventType>
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>
1277 void enqueue_event_helper(EventType const& , ::boost::mpl::true_ const &)
1278 {
1279 // no queue
1280 }
1281
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 }
1291 void execute_queued_events_helper(::boost::mpl::true_ const &)
1292 {
1293 // no queue required
1294 }
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 }
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>
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
1316 void execute_queued_events()
1317 {
1318 execute_queued_events_helper(typename is_no_message_queue<library_sm>::type());
1319 }
1320 void execute_single_queued_event()
1321 {
1322 execute_single_queued_event_helper(typename is_no_message_queue<library_sm>::type());
1323 }
1324 typename events_queue_t::size_type get_message_queue_size() const
1325 {
1326 return m_events_queue.m_events_queue.size();
1327 }
1328
1329 events_queue_t& get_message_queue()
1330 {
1331 return m_events_queue.m_events_queue;
1332 }
1333
1334 const events_queue_t& get_message_queue() const
1335 {
1336 return m_events_queue.m_events_queue;
1337 }
1338
1339 void clear_deferred_queue()
1340 {
1341 m_deferred_events_queue.clear();
1342 }
1343
1344 deferred_events_queue_t& get_deferred_queue()
1345 {
1346 return m_deferred_events_queue.m_deferred_events_queue;
1347 }
1348
1349 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
1355 const int* current_state() const
1356 {
1357 return this->m_states;
1358 }
1359
1360 template <class Archive>
1361 struct serialize_state
1362 {
1363 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
1373 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
1385 operator()(T&) const
1386 {
1387 // no state to serialize
1388 }
1389 Archive& ar_;
1390 };
1391
1392 template<class Archive>
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 {
1410 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>
1414 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)
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 }
1437 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
1445 bool is_contained() const
1446 {
1447 return m_is_included;
1448 }
1449 // get the history policy class
1450 concrete_history& get_history()
1451 {
1452 return m_history;
1453 }
1454 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
1462 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
1472 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
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
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>
1496 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>
1508 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)
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>
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 {
1553 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>
1557 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 {
1567 update_state(substate_list& to_overwrite_):to_overwrite(&to_overwrite_){}
1568 template<typename StateType>
1569 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>
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>
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
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>
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>
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>
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>
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 }
1744 void do_post_msg_queue_helper( ::boost::mpl::true_ const &)
1745 {
1746 // no message queue needed
1747 }
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>
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>
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 {
1783 handle_defer_helper(deferred_msg_queue_helper<library_sm>& ){}
1784 void do_pre_handle_deferred()
1785 {
1786 }
1787
1788 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 {
1797 handle_defer_helper(deferred_msg_queue_helper<library_sm>& a_queue):
1798 events_queue(a_queue),next_deferred_event(){}
1799 void do_pre_handle_deferred()
1800 {
1801 }
1802
1803 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 {
1848 handle_eventless_transitions_helper(library_sm* , bool ){}
1849 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 {
1856 handle_eventless_transitions_helper(library_sm* self_, bool handled_):self(self_),handled(handled_){}
1857 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
1882 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!
1888 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
1898 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:
1908 region_processing_helper(library_sm* self_,HandledEnum& result_)
1909 :self(self_),result(result_){}
1910 template<class Event>
1911 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>
1937 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>
1954 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:
1961 region_processing_helper(library_sm* self_,HandledEnum& result_)
1962 :self(self_),result(result_){}
1963 template<class Event>
1964 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>
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>
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>
2046 bool no_guard(Event const&){return true;}
2047 template <class Event>
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.
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 {
2080 call_init(Event const& an_event,library_sm* self_):
2081 evt(an_event),self(self_){}
2082 template <class State>
2083 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 {
2095 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 {
2104 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 {
2115 static bool flag_true(library_sm const& )
2116 {
2117 return true;
2118 }
2119 static bool flag_false(library_sm const& )
2120 {
2121 return false;
2122 }
2123 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>
2134 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>
2140 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:
2149 init_flags(flag_handler* entries_)
2150 : entries(entries_)
2151 {}
2152
2153 // Flags initializer function object, used with mpl::for_each
2154 template <class StateType>
2155 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>
2181 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 {
2196 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 {
2205 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>
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 {
2265 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
2272 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
2285 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
2292 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>
2302 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>
2316 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>
2322 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 {
2334 copy_helper(library_sm* sm):
2335 m_sm(sm){}
2336 template <class StateType>
2337 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
2348 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
2355 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 {
2366 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
2376 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)
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 {
2401 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
2406 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
2417 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>
2427 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>
2442 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>
2456 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>
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 {
2491 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
2495 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
2512 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
2534 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
2549 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 {
2569 fork_helper(library_sm* self_,EventType const& evt_):
2570 helper_self(self_),helper_evt(evt_){}
2571 template <class StateType>
2572 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>
2590 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>
2598 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>
2611 static void do_entry(library_sm*,Event const& ){}
2612 template<class Event>
2613 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>
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>
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>
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>
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>
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>
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
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>
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>
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
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
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
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
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
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
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
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
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
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>
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:
2815 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