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