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

source code of boost/libs/msm/include/boost/msm/back/state_machine.hpp