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