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