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

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