1 #ifndef BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED 2 #define BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED 3 ////////////////////////////////////////////////////////////////////////////// 4 // Copyright 2002-2010 Andreas Huber Doenni 5 // Distributed under the Boost Software License, Version 1.0. (See accompany- 6 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 ////////////////////////////////////////////////////////////////////////////// 8 9 10 11 #include <boost/statechart/event.hpp> 12 #include <boost/statechart/null_exception_translator.hpp> 13 #include <boost/statechart/result.hpp> 14 15 #include <boost/statechart/detail/rtti_policy.hpp> 16 #include <boost/statechart/detail/state_base.hpp> 17 #include <boost/statechart/detail/leaf_state.hpp> 18 #include <boost/statechart/detail/node_state.hpp> 19 #include <boost/statechart/detail/constructor.hpp> 20 #include <boost/statechart/detail/avoid_unused_warning.hpp> 21 22 #include <boost/mpl/list.hpp> 23 #include <boost/mpl/clear.hpp> 24 #include <boost/mpl/if.hpp> 25 #include <boost/mpl/at.hpp> 26 #include <boost/mpl/integral_c.hpp> 27 #include <boost/mpl/minus.hpp> 28 #include <boost/mpl/equal_to.hpp> 29 30 #include <boost/intrusive_ptr.hpp> 31 #include <boost/type_traits/is_pointer.hpp> 32 #include <boost/type_traits/remove_reference.hpp> 33 #include <boost/noncopyable.hpp> 34 #include <boost/assert.hpp> 35 #include <boost/static_assert.hpp> 36 #include <boost/polymorphic_cast.hpp> // boost::polymorphic_downcast 37 // BOOST_NO_EXCEPTIONS, BOOST_MSVC, BOOST_MSVC_STD_ITERATOR 38 #include <boost/config.hpp> 39 40 #include <boost/detail/allocator_utilities.hpp> 41 42 #ifdef BOOST_MSVC 43 # pragma warning( push ) 44 # pragma warning( disable: 4702 ) // unreachable code (in release mode only) 45 #endif 46 47 #include <map> 48 49 #ifdef BOOST_MSVC 50 # pragma warning( pop ) 51 #endif 52 53 #include <memory> // std::allocator 54 #include <typeinfo> // std::bad_cast 55 #include <functional> // std::less 56 #include <iterator> 57 58 59 60 namespace boost 61 { 62 namespace statechart 63 { 64 namespace detail 65 { 66 67 68 69 ////////////////////////////////////////////////////////////////////////////// 70 template< class StateBaseType, class EventBaseType, class IdType > 71 class send_function 72 { 73 public: 74 ////////////////////////////////////////////////////////////////////////// send_function(StateBaseType & toState,const EventBaseType & evt,IdType eventType)75 send_function( 76 StateBaseType & toState, 77 const EventBaseType & evt, 78 IdType eventType 79 ) : 80 toState_( toState ), evt_( evt ), eventType_( eventType ) 81 { 82 } 83 operator ()()84 result operator()() 85 { 86 return detail::result_utility::make_result( 87 toState_.react_impl( evt_, eventType_ ) ); 88 } 89 90 private: 91 ////////////////////////////////////////////////////////////////////////// 92 // avoids C4512 (assignment operator could not be generated) 93 send_function & operator=( const send_function & ); 94 95 StateBaseType & toState_; 96 const EventBaseType & evt_; 97 IdType eventType_; 98 }; 99 100 101 ////////////////////////////////////////////////////////////////////////////// 102 struct state_cast_impl_pointer_target 103 { 104 public: 105 ////////////////////////////////////////////////////////////////////////// 106 template< class StateBaseType > deref_if_necessaryboost::statechart::detail::state_cast_impl_pointer_target107 static const StateBaseType * deref_if_necessary( 108 const StateBaseType * pState ) 109 { 110 return pState; 111 } 112 113 template< class Target, class IdType > type_idboost::statechart::detail::state_cast_impl_pointer_target114 static IdType type_id() 115 { 116 Target p = 0; 117 return type_id_impl< IdType >( p ); 118 } 119 foundboost::statechart::detail::state_cast_impl_pointer_target120 static bool found( const void * pFound ) 121 { 122 return pFound != 0; 123 } 124 125 template< class Target > not_foundboost::statechart::detail::state_cast_impl_pointer_target126 static Target not_found() 127 { 128 return 0; 129 } 130 131 private: 132 ////////////////////////////////////////////////////////////////////////// 133 template< class IdType, class Type > type_id_implboost::statechart::detail::state_cast_impl_pointer_target134 static IdType type_id_impl( const Type * ) 135 { 136 return Type::static_type(); 137 } 138 }; 139 140 struct state_cast_impl_reference_target 141 { 142 template< class StateBaseType > deref_if_necessaryboost::statechart::detail::state_cast_impl_reference_target143 static const StateBaseType & deref_if_necessary( 144 const StateBaseType * pState ) 145 { 146 return *pState; 147 } 148 149 template< class Target, class IdType > type_idboost::statechart::detail::state_cast_impl_reference_target150 static IdType type_id() 151 { 152 return remove_reference< Target >::type::static_type(); 153 } 154 155 template< class Dummy > foundboost::statechart::detail::state_cast_impl_reference_target156 static bool found( const Dummy & ) 157 { 158 return true; 159 } 160 161 template< class Target > not_foundboost::statechart::detail::state_cast_impl_reference_target162 static Target not_found() 163 { 164 throw std::bad_cast(); 165 } 166 }; 167 168 template< class Target > 169 struct state_cast_impl : public mpl::if_< 170 is_pointer< Target >, 171 state_cast_impl_pointer_target, 172 state_cast_impl_reference_target 173 >::type {}; 174 175 176 ////////////////////////////////////////////////////////////////////////////// 177 template< class RttiPolicy > 178 class history_key 179 { 180 public: 181 ////////////////////////////////////////////////////////////////////////// 182 template< class HistorizedState > make_history_key()183 static history_key make_history_key() 184 { 185 return history_key( 186 HistorizedState::context_type::static_type(), 187 HistorizedState::orthogonal_position::value ); 188 } 189 history_context_type() const190 typename RttiPolicy::id_type history_context_type() const 191 { 192 return historyContextType_; 193 } 194 operator <(const history_key & left,const history_key & right)195 friend bool operator<( 196 const history_key & left, const history_key & right ) 197 { 198 return 199 std::less< typename RttiPolicy::id_type >()( 200 left.historyContextType_, right.historyContextType_ ) || 201 ( ( left.historyContextType_ == right.historyContextType_ ) && 202 ( left.historizedOrthogonalRegion_ < 203 right.historizedOrthogonalRegion_ ) ); 204 } 205 206 private: 207 ////////////////////////////////////////////////////////////////////////// history_key(typename RttiPolicy::id_type historyContextType,orthogonal_position_type historizedOrthogonalRegion)208 history_key( 209 typename RttiPolicy::id_type historyContextType, 210 orthogonal_position_type historizedOrthogonalRegion 211 ) : 212 historyContextType_( historyContextType ), 213 historizedOrthogonalRegion_( historizedOrthogonalRegion ) 214 { 215 } 216 217 // avoids C4512 (assignment operator could not be generated) 218 history_key & operator=( const history_key & ); 219 220 const typename RttiPolicy::id_type historyContextType_; 221 const orthogonal_position_type historizedOrthogonalRegion_; 222 }; 223 224 225 226 } // namespace detail 227 228 229 230 ////////////////////////////////////////////////////////////////////////////// 231 template< class MostDerived, 232 class InitialState, 233 class Allocator = std::allocator< none >, 234 class ExceptionTranslator = null_exception_translator > 235 class state_machine : noncopyable 236 { 237 public: 238 ////////////////////////////////////////////////////////////////////////// 239 typedef Allocator allocator_type; 240 typedef detail::rtti_policy rtti_policy_type; 241 typedef event_base event_base_type; 242 typedef intrusive_ptr< const event_base_type > event_base_ptr_type; 243 initiate()244 void initiate() 245 { 246 terminate(); 247 248 { 249 terminator guard( *this, 0 ); 250 detail::result_utility::get_result( translator_( 251 initial_construct_function( *this ), 252 exception_event_handler( *this ) ) ); 253 guard.dismiss(); 254 } 255 256 process_queued_events(); 257 } 258 terminate()259 void terminate() 260 { 261 terminator guard( *this, 0 ); 262 detail::result_utility::get_result( translator_( 263 terminate_function( *this ), 264 exception_event_handler( *this ) ) ); 265 guard.dismiss(); 266 } 267 terminated() const268 bool terminated() const 269 { 270 return pOutermostState_ == 0; 271 } 272 process_event(const event_base_type & evt)273 void process_event( const event_base_type & evt ) 274 { 275 if ( send_event( evt ) == detail::do_defer_event ) 276 { 277 deferredEventQueue_.push_back( evt.intrusive_from_this() ); 278 } 279 280 process_queued_events(); 281 } 282 283 template< class Target > state_cast() const284 Target state_cast() const 285 { 286 typedef detail::state_cast_impl< Target > impl; 287 288 for ( typename state_list_type::const_iterator pCurrentLeafState = 289 currentStates_.begin(); 290 pCurrentLeafState != currentStatesEnd_; 291 ++pCurrentLeafState ) 292 { 293 const state_base_type * pCurrentState( 294 get_pointer( *pCurrentLeafState ) ); 295 296 while ( pCurrentState != 0 ) 297 { 298 // The unnecessary try/catch overhead for pointer targets is 299 // typically small compared to the cycles dynamic_cast needs 300 #ifndef BOOST_NO_EXCEPTIONS 301 try 302 #endif 303 { 304 Target result = dynamic_cast< Target >( 305 impl::deref_if_necessary( pCurrentState ) ); 306 307 if ( impl::found( result ) ) 308 { 309 return result; 310 } 311 } 312 #ifndef BOOST_NO_EXCEPTIONS 313 // Intentionally swallow std::bad_cast exceptions. We'll throw one 314 // ourselves when we fail to find a state that can be cast to Target 315 catch ( const std::bad_cast & ) {} 316 #endif 317 318 pCurrentState = pCurrentState->outer_state_ptr(); 319 } 320 } 321 322 return impl::template not_found< Target >(); 323 } 324 325 template< class Target > state_downcast() const326 Target state_downcast() const 327 { 328 typedef detail::state_cast_impl< Target > impl; 329 330 typename rtti_policy_type::id_type targetType = 331 impl::template type_id< Target, rtti_policy_type::id_type >(); 332 333 for ( typename state_list_type::const_iterator pCurrentLeafState = 334 currentStates_.begin(); 335 pCurrentLeafState != currentStatesEnd_; 336 ++pCurrentLeafState ) 337 { 338 const state_base_type * pCurrentState( 339 get_pointer( *pCurrentLeafState ) ); 340 341 while ( pCurrentState != 0 ) 342 { 343 if ( pCurrentState->dynamic_type() == targetType ) 344 { 345 return static_cast< Target >( 346 impl::deref_if_necessary( pCurrentState ) ); 347 } 348 349 pCurrentState = pCurrentState->outer_state_ptr(); 350 } 351 } 352 353 return impl::template not_found< Target >(); 354 } 355 356 typedef detail::state_base< allocator_type, rtti_policy_type > 357 state_base_type; 358 359 class state_iterator : public std::iterator< 360 std::forward_iterator_tag, 361 state_base_type, std::ptrdiff_t 362 #ifndef BOOST_MSVC_STD_ITERATOR 363 , const state_base_type *, const state_base_type & 364 #endif 365 > 366 { 367 public: 368 ////////////////////////////////////////////////////////////////////// state_iterator(typename state_base_type::state_list_type::const_iterator baseIterator)369 explicit state_iterator( 370 typename state_base_type::state_list_type::const_iterator 371 baseIterator 372 ) : baseIterator_( baseIterator ) {} 373 operator *() const374 const state_base_type & operator*() const { return **baseIterator_; } operator ->() const375 const state_base_type * operator->() const 376 { 377 return &**baseIterator_; 378 } 379 operator ++()380 state_iterator & operator++() { ++baseIterator_; return *this; } operator ++(int)381 state_iterator operator++( int ) 382 { 383 return state_iterator( baseIterator_++ ); 384 } 385 operator ==(const state_iterator & right) const386 bool operator==( const state_iterator & right ) const 387 { 388 return baseIterator_ == right.baseIterator_; 389 } operator !=(const state_iterator & right) const390 bool operator!=( const state_iterator & right ) const 391 { 392 return !( *this == right ); 393 } 394 395 private: 396 typename state_base_type::state_list_type::const_iterator 397 baseIterator_; 398 }; 399 state_begin() const400 state_iterator state_begin() const 401 { 402 return state_iterator( currentStates_.begin() ); 403 } 404 state_end() const405 state_iterator state_end() const 406 { 407 return state_iterator( currentStatesEnd_ ); 408 } 409 unconsumed_event(const event_base &)410 void unconsumed_event( const event_base & ) {} 411 412 protected: 413 ////////////////////////////////////////////////////////////////////////// state_machine()414 state_machine() : 415 currentStatesEnd_( currentStates_.end() ), 416 pOutermostState_( 0 ), 417 isInnermostCommonOuter_( false ), 418 performFullExit_( true ), 419 pTriggeringEvent_( 0 ) 420 { 421 } 422 423 // This destructor was only made virtual so that that 424 // polymorphic_downcast can be used to cast to MostDerived. ~state_machine()425 virtual ~state_machine() 426 { 427 terminate_impl( false ); 428 } 429 post_event(const event_base_ptr_type & pEvent)430 void post_event( const event_base_ptr_type & pEvent ) 431 { 432 post_event_impl( pEvent ); 433 } 434 post_event(const event_base & evt)435 void post_event( const event_base & evt ) 436 { 437 post_event_impl( evt ); 438 } 439 440 public: 441 ////////////////////////////////////////////////////////////////////////// 442 // The following declarations should be protected. 443 // They are only public because many compilers lack template friends. 444 ////////////////////////////////////////////////////////////////////////// 445 template< 446 class HistoryContext, 447 detail::orthogonal_position_type orthogonalPosition > clear_shallow_history()448 void clear_shallow_history() 449 { 450 // If you receive a 451 // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or 452 // similar compiler error here then you tried to clear shallow history 453 // for a state that does not have shallow history. That is, the state 454 // does not pass either statechart::has_shallow_history or 455 // statechart::has_full_history to its base class template. 456 BOOST_STATIC_ASSERT( HistoryContext::shallow_history::value ); 457 458 typedef typename mpl::at_c< 459 typename HistoryContext::inner_initial_list, 460 orthogonalPosition >::type historized_state; 461 462 store_history_impl( 463 shallowHistoryMap_, 464 history_key_type::make_history_key< historized_state >(), 465 0 ); 466 } 467 468 template< 469 class HistoryContext, 470 detail::orthogonal_position_type orthogonalPosition > clear_deep_history()471 void clear_deep_history() 472 { 473 // If you receive a 474 // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or 475 // similar compiler error here then you tried to clear deep history for 476 // a state that does not have deep history. That is, the state does not 477 // pass either statechart::has_deep_history or 478 // statechart::has_full_history to its base class template 479 BOOST_STATIC_ASSERT( HistoryContext::deep_history::value ); 480 481 typedef typename mpl::at_c< 482 typename HistoryContext::inner_initial_list, 483 orthogonalPosition >::type historized_state; 484 485 store_history_impl( 486 deepHistoryMap_, 487 history_key_type::make_history_key< historized_state >(), 488 0 ); 489 } 490 triggering_event() const491 const event_base_type * triggering_event() const 492 { 493 return pTriggeringEvent_; 494 } 495 496 public: 497 ////////////////////////////////////////////////////////////////////////// 498 // The following declarations should be private. 499 // They are only public because many compilers lack template friends. 500 ////////////////////////////////////////////////////////////////////////// 501 typedef MostDerived inner_context_type; 502 typedef mpl::integral_c< detail::orthogonal_position_type, 0 > 503 inner_orthogonal_position; 504 typedef mpl::integral_c< detail::orthogonal_position_type, 1 > 505 no_of_orthogonal_regions; 506 507 typedef MostDerived outermost_context_type; 508 typedef state_machine outermost_context_base_type; 509 typedef state_machine * inner_context_ptr_type; 510 typedef typename state_base_type::node_state_base_ptr_type 511 node_state_base_ptr_type; 512 typedef typename state_base_type::leaf_state_ptr_type leaf_state_ptr_type; 513 typedef typename state_base_type::state_list_type state_list_type; 514 515 typedef mpl::clear< mpl::list<> >::type context_type_list; 516 517 typedef mpl::bool_< false > shallow_history; 518 typedef mpl::bool_< false > deep_history; 519 typedef mpl::bool_< false > inherited_deep_history; 520 post_event_impl(const event_base_ptr_type & pEvent)521 void post_event_impl( const event_base_ptr_type & pEvent ) 522 { 523 BOOST_ASSERT( get_pointer( pEvent ) != 0 ); 524 eventQueue_.push_back( pEvent ); 525 } 526 post_event_impl(const event_base & evt)527 void post_event_impl( const event_base & evt ) 528 { 529 post_event_impl( evt.intrusive_from_this() ); 530 } 531 react_impl(const event_base_type &,typename rtti_policy_type::id_type)532 detail::reaction_result react_impl( 533 const event_base_type &, 534 typename rtti_policy_type::id_type ) 535 { 536 return detail::do_forward_event; 537 } 538 exit_impl(inner_context_ptr_type &,typename state_base_type::node_state_base_ptr_type &,bool)539 void exit_impl( 540 inner_context_ptr_type &, 541 typename state_base_type::node_state_base_ptr_type &, 542 bool ) {} 543 set_outermost_unstable_state(typename state_base_type::node_state_base_ptr_type & pOutermostUnstableState)544 void set_outermost_unstable_state( 545 typename state_base_type::node_state_base_ptr_type & 546 pOutermostUnstableState ) 547 { 548 pOutermostUnstableState = 0; 549 } 550 551 // Returns a reference to the context identified by the template 552 // parameter. This can either be _this_ object or one of its direct or 553 // indirect contexts. 554 template< class Context > context()555 Context & context() 556 { 557 // As we are in the outermost context here, only this object can be 558 // returned. 559 return *polymorphic_downcast< MostDerived * >( this ); 560 } 561 562 template< class Context > context() const563 const Context & context() const 564 { 565 // As we are in the outermost context here, only this object can be 566 // returned. 567 return *polymorphic_downcast< const MostDerived * >( this ); 568 } 569 outermost_context()570 outermost_context_type & outermost_context() 571 { 572 return *polymorphic_downcast< MostDerived * >( this ); 573 } 574 outermost_context() const575 const outermost_context_type & outermost_context() const 576 { 577 return *polymorphic_downcast< const MostDerived * >( this ); 578 } 579 outermost_context_base()580 outermost_context_base_type & outermost_context_base() 581 { 582 return *this; 583 } 584 outermost_context_base() const585 const outermost_context_base_type & outermost_context_base() const 586 { 587 return *this; 588 } 589 terminate_as_reaction(state_base_type & theState)590 void terminate_as_reaction( state_base_type & theState ) 591 { 592 terminate_impl( theState, performFullExit_ ); 593 pOutermostUnstableState_ = 0; 594 } 595 terminate_as_part_of_transit(state_base_type & theState)596 void terminate_as_part_of_transit( state_base_type & theState ) 597 { 598 terminate_impl( theState, performFullExit_ ); 599 isInnermostCommonOuter_ = true; 600 } 601 terminate_as_part_of_transit(state_machine &)602 void terminate_as_part_of_transit( state_machine & ) 603 { 604 terminate_impl( *pOutermostState_, performFullExit_ ); 605 isInnermostCommonOuter_ = true; 606 } 607 608 609 template< class State > add(const intrusive_ptr<State> & pState)610 void add( const intrusive_ptr< State > & pState ) 611 { 612 // The second dummy argument is necessary because the call to the 613 // overloaded function add_impl would otherwise be ambiguous. 614 node_state_base_ptr_type pNewOutermostUnstableStateCandidate = 615 add_impl( pState, *pState ); 616 617 if ( isInnermostCommonOuter_ || 618 ( is_in_highest_orthogonal_region< State >() && 619 ( get_pointer( pOutermostUnstableState_ ) == 620 pState->State::outer_state_ptr() ) ) ) 621 { 622 isInnermostCommonOuter_ = false; 623 pOutermostUnstableState_ = pNewOutermostUnstableStateCandidate; 624 } 625 } 626 627 add_inner_state(detail::orthogonal_position_type position,state_base_type * pOutermostState)628 void add_inner_state( 629 detail::orthogonal_position_type position, 630 state_base_type * pOutermostState ) 631 { 632 BOOST_ASSERT( position == 0 ); 633 detail::avoid_unused_warning( position ); 634 pOutermostState_ = pOutermostState; 635 } 636 remove_inner_state(detail::orthogonal_position_type position)637 void remove_inner_state( detail::orthogonal_position_type position ) 638 { 639 BOOST_ASSERT( position == 0 ); 640 detail::avoid_unused_warning( position ); 641 pOutermostState_ = 0; 642 } 643 644 release_events()645 void release_events() 646 { 647 eventQueue_.splice( eventQueue_.begin(), deferredEventQueue_ ); 648 } 649 650 651 template< class HistorizedState > store_shallow_history()652 void store_shallow_history() 653 { 654 // 5.2.10.6 declares that reinterpret_casting a function pointer to a 655 // different function pointer and back must yield the same value. The 656 // following reinterpret_cast is the first half of such a sequence. 657 store_history_impl( 658 shallowHistoryMap_, 659 history_key_type::make_history_key< HistorizedState >(), 660 reinterpret_cast< void (*)() >( &HistorizedState::deep_construct ) ); 661 } 662 663 template< class DefaultState > construct_with_shallow_history(const typename DefaultState::context_ptr_type & pContext)664 void construct_with_shallow_history( 665 const typename DefaultState::context_ptr_type & pContext ) 666 { 667 construct_with_history_impl< DefaultState >( 668 shallowHistoryMap_, pContext ); 669 } 670 671 672 template< class HistorizedState, class LeafState > store_deep_history()673 void store_deep_history() 674 { 675 typedef typename detail::make_context_list< 676 typename HistorizedState::context_type, 677 LeafState >::type history_context_list; 678 typedef detail::constructor< 679 history_context_list, outermost_context_base_type > constructor_type; 680 // 5.2.10.6 declares that reinterpret_casting a function pointer to a 681 // different function pointer and back must yield the same value. The 682 // following reinterpret_cast is the first half of such a sequence. 683 store_history_impl( 684 deepHistoryMap_, 685 history_key_type::make_history_key< HistorizedState >(), 686 reinterpret_cast< void (*)() >( &constructor_type::construct ) ); 687 } 688 689 template< class DefaultState > construct_with_deep_history(const typename DefaultState::context_ptr_type & pContext)690 void construct_with_deep_history( 691 const typename DefaultState::context_ptr_type & pContext ) 692 { 693 construct_with_history_impl< DefaultState >( 694 deepHistoryMap_, pContext ); 695 } 696 697 private: // implementation 698 ////////////////////////////////////////////////////////////////////////// initial_construct()699 void initial_construct() 700 { 701 InitialState::initial_deep_construct( 702 *polymorphic_downcast< MostDerived * >( this ) ); 703 } 704 705 class initial_construct_function 706 { 707 public: 708 ////////////////////////////////////////////////////////////////////// initial_construct_function(state_machine & machine)709 initial_construct_function( state_machine & machine ) : 710 machine_( machine ) 711 { 712 } 713 operator ()()714 result operator()() 715 { 716 machine_.initial_construct(); 717 return detail::result_utility::make_result( 718 detail::do_discard_event ); // there is nothing to be consumed 719 } 720 721 private: 722 ////////////////////////////////////////////////////////////////////// 723 // avoids C4512 (assignment operator could not be generated) 724 initial_construct_function & operator=( 725 const initial_construct_function & ); 726 727 state_machine & machine_; 728 }; 729 friend class initial_construct_function; 730 731 class terminate_function 732 { 733 public: 734 ////////////////////////////////////////////////////////////////////// terminate_function(state_machine & machine)735 terminate_function( state_machine & machine ) : machine_( machine ) {} 736 operator ()()737 result operator()() 738 { 739 machine_.terminate_impl( true ); 740 return detail::result_utility::make_result( 741 detail::do_discard_event ); // there is nothing to be consumed 742 } 743 744 private: 745 ////////////////////////////////////////////////////////////////////// 746 // avoids C4512 (assignment operator could not be generated) 747 terminate_function & operator=( const terminate_function & ); 748 749 state_machine & machine_; 750 }; 751 friend class terminate_function; 752 753 template< class ExceptionEvent > handle_exception_event(const ExceptionEvent & exceptionEvent,state_base_type * pCurrentState)754 detail::reaction_result handle_exception_event( 755 const ExceptionEvent & exceptionEvent, 756 state_base_type * pCurrentState ) 757 { 758 if ( terminated() ) 759 { 760 // there is no state that could handle the exception -> bail out 761 throw; 762 } 763 764 // If we are stable, an event handler has thrown. 765 // Otherwise, either a state constructor, a transition action or an exit 766 // function has thrown and the state machine is now in an invalid state. 767 // This situation can be resolved by the exception event handler 768 // function by orderly transiting to another state or terminating. 769 // As a result of this, the machine must not be unstable when this 770 // function is left. 771 state_base_type * const pOutermostUnstableState = 772 get_pointer( pOutermostUnstableState_ ); 773 state_base_type * const pHandlingState = pOutermostUnstableState == 0 ? 774 pCurrentState : pOutermostUnstableState; 775 776 BOOST_ASSERT( pHandlingState != 0 ); 777 terminator guard( *this, &exceptionEvent ); 778 // There is another scope guard up the call stack, which will terminate 779 // the machine. So this guard only sets the triggering event. 780 guard.dismiss(); 781 782 // Setting a member variable to a special value for the duration of a 783 // call surely looks like a kludge (normally it should be a parameter of 784 // the call). However, in this case it is unavoidable because the call 785 // below could result in a call to user code where passing through an 786 // additional bool parameter is not acceptable. 787 performFullExit_ = false; 788 const detail::reaction_result reactionResult = pHandlingState->react_impl( 789 exceptionEvent, exceptionEvent.dynamic_type() ); 790 // If the above call throws then performFullExit_ will obviously not be 791 // set back to true. In this case the termination triggered by the 792 // scope guard further up in the call stack will take care of this. 793 performFullExit_ = true; 794 795 if ( ( reactionResult != detail::do_discard_event ) || 796 ( get_pointer( pOutermostUnstableState_ ) != 0 ) ) 797 { 798 throw; 799 } 800 801 return detail::do_discard_event; 802 } 803 804 class exception_event_handler 805 { 806 public: 807 ////////////////////////////////////////////////////////////////////// exception_event_handler(state_machine & machine,state_base_type * pCurrentState=0)808 exception_event_handler( 809 state_machine & machine, 810 state_base_type * pCurrentState = 0 811 ) : 812 machine_( machine ), 813 pCurrentState_( pCurrentState ) 814 { 815 } 816 817 template< class ExceptionEvent > operator ()(const ExceptionEvent & exceptionEvent)818 result operator()( 819 const ExceptionEvent & exceptionEvent ) 820 { 821 return detail::result_utility::make_result( 822 machine_.handle_exception_event( 823 exceptionEvent, pCurrentState_ ) ); 824 } 825 826 private: 827 ////////////////////////////////////////////////////////////////////// 828 // avoids C4512 (assignment operator could not be generated) 829 exception_event_handler & operator=( 830 const exception_event_handler & ); 831 832 state_machine & machine_; 833 state_base_type * pCurrentState_; 834 }; 835 friend class exception_event_handler; 836 837 class terminator 838 { 839 public: 840 ////////////////////////////////////////////////////////////////////// terminator(state_machine & machine,const event_base * pNewTriggeringEvent)841 terminator( 842 state_machine & machine, const event_base * pNewTriggeringEvent ) : 843 machine_( machine ), 844 pOldTriggeringEvent_(machine_.pTriggeringEvent_), 845 dismissed_( false ) 846 { 847 machine_.pTriggeringEvent_ = pNewTriggeringEvent; 848 } 849 ~terminator()850 ~terminator() 851 { 852 if ( !dismissed_ ) { machine_.terminate_impl( false ); } 853 machine_.pTriggeringEvent_ = pOldTriggeringEvent_; 854 } 855 dismiss()856 void dismiss() { dismissed_ = true; } 857 858 private: 859 ////////////////////////////////////////////////////////////////////// 860 // avoids C4512 (assignment operator could not be generated) 861 terminator & operator=( const terminator & ); 862 863 state_machine & machine_; 864 const event_base_type * const pOldTriggeringEvent_; 865 bool dismissed_; 866 }; 867 friend class terminator; 868 869 send_event(const event_base_type & evt)870 detail::reaction_result send_event( const event_base_type & evt ) 871 { 872 terminator guard( *this, &evt ); 873 BOOST_ASSERT( get_pointer( pOutermostUnstableState_ ) == 0 ); 874 const typename rtti_policy_type::id_type eventType = evt.dynamic_type(); 875 detail::reaction_result reactionResult = detail::do_forward_event; 876 877 for ( 878 typename state_list_type::iterator pState = currentStates_.begin(); 879 ( reactionResult == detail::do_forward_event ) && 880 ( pState != currentStatesEnd_ ); 881 ++pState ) 882 { 883 // CAUTION: The following statement could modify our state list! 884 // We must not continue iterating if the event was consumed 885 reactionResult = detail::result_utility::get_result( translator_( 886 detail::send_function< 887 state_base_type, event_base_type, rtti_policy_type::id_type >( 888 **pState, evt, eventType ), 889 exception_event_handler( *this, get_pointer( *pState ) ) ) ); 890 } 891 892 guard.dismiss(); 893 894 if ( reactionResult == detail::do_forward_event ) 895 { 896 polymorphic_downcast< MostDerived * >( this )->unconsumed_event( evt ); 897 } 898 899 return reactionResult; 900 } 901 902 process_queued_events()903 void process_queued_events() 904 { 905 while ( !eventQueue_.empty() ) 906 { 907 event_base_ptr_type pEvent = eventQueue_.front(); 908 eventQueue_.pop_front(); 909 910 if ( send_event( *pEvent ) == detail::do_defer_event ) 911 { 912 deferredEventQueue_.push_back( pEvent ); 913 } 914 } 915 } 916 917 terminate_impl(bool performFullExit)918 void terminate_impl( bool performFullExit ) 919 { 920 performFullExit_ = true; 921 922 if ( !terminated() ) 923 { 924 terminate_impl( *pOutermostState_, performFullExit ); 925 } 926 927 eventQueue_.clear(); 928 deferredEventQueue_.clear(); 929 shallowHistoryMap_.clear(); 930 deepHistoryMap_.clear(); 931 } 932 terminate_impl(state_base_type & theState,bool performFullExit)933 void terminate_impl( state_base_type & theState, bool performFullExit ) 934 { 935 isInnermostCommonOuter_ = false; 936 937 // If pOutermostUnstableState_ == 0, we know for sure that 938 // currentStates_.size() > 0, otherwise theState couldn't be alive any 939 // more 940 if ( get_pointer( pOutermostUnstableState_ ) != 0 ) 941 { 942 theState.remove_from_state_list( 943 currentStatesEnd_, pOutermostUnstableState_, performFullExit ); 944 } 945 // Optimization: We want to find out whether currentStates_ has size 1 946 // and if yes use the optimized implementation below. Since 947 // list<>::size() is implemented quite inefficiently in some std libs 948 // it is best to just decrement the currentStatesEnd_ here and 949 // increment it again, if the test failed. 950 else if ( currentStates_.begin() == --currentStatesEnd_ ) 951 { 952 // The machine is stable and there is exactly one innermost state. 953 // The following optimization is only correct for a stable machine 954 // without orthogonal regions. 955 leaf_state_ptr_type & pState = *currentStatesEnd_; 956 pState->exit_impl( 957 pState, pOutermostUnstableState_, performFullExit ); 958 } 959 else 960 { 961 BOOST_ASSERT( currentStates_.size() > 1 ); 962 // The machine is stable and there are multiple innermost states 963 theState.remove_from_state_list( 964 ++currentStatesEnd_, pOutermostUnstableState_, performFullExit ); 965 } 966 } 967 968 add_impl(const leaf_state_ptr_type & pState,detail::leaf_state<allocator_type,rtti_policy_type> &)969 node_state_base_ptr_type add_impl( 970 const leaf_state_ptr_type & pState, 971 detail::leaf_state< allocator_type, rtti_policy_type > & ) 972 { 973 if ( currentStatesEnd_ == currentStates_.end() ) 974 { 975 pState->set_list_position( 976 currentStates_.insert( currentStatesEnd_, pState ) ); 977 } 978 else 979 { 980 *currentStatesEnd_ = pState; 981 pState->set_list_position( currentStatesEnd_ ); 982 ++currentStatesEnd_; 983 } 984 985 return 0; 986 } 987 add_impl(const node_state_base_ptr_type & pState,state_base_type &)988 node_state_base_ptr_type add_impl( 989 const node_state_base_ptr_type & pState, 990 state_base_type & ) 991 { 992 return pState; 993 } 994 995 template< class State > is_in_highest_orthogonal_region()996 static bool is_in_highest_orthogonal_region() 997 { 998 return mpl::equal_to< 999 typename State::orthogonal_position, 1000 mpl::minus< 1001 typename State::context_type::no_of_orthogonal_regions, 1002 mpl::integral_c< detail::orthogonal_position_type, 1 > > 1003 >::value; 1004 } 1005 1006 1007 typedef detail::history_key< rtti_policy_type > history_key_type; 1008 1009 typedef std::map< 1010 history_key_type, void (*)(), 1011 std::less< history_key_type >, 1012 typename boost::detail::allocator::rebind_to< 1013 allocator_type, std::pair< const history_key_type, void (*)() > 1014 >::type 1015 > history_map_type; 1016 store_history_impl(history_map_type & historyMap,const history_key_type & historyId,void (* pConstructFunction)())1017 void store_history_impl( 1018 history_map_type & historyMap, 1019 const history_key_type & historyId, 1020 void (*pConstructFunction)() ) 1021 { 1022 historyMap[ historyId ] = pConstructFunction; 1023 } 1024 1025 template< class DefaultState > construct_with_history_impl(history_map_type & historyMap,const typename DefaultState::context_ptr_type & pContext)1026 void construct_with_history_impl( 1027 history_map_type & historyMap, 1028 const typename DefaultState::context_ptr_type & pContext ) 1029 { 1030 typename history_map_type::iterator pFoundSlot = historyMap.find( 1031 history_key_type::make_history_key< DefaultState >() ); 1032 1033 if ( ( pFoundSlot == historyMap.end() ) || ( pFoundSlot->second == 0 ) ) 1034 { 1035 // We have never entered this state before or history was cleared 1036 DefaultState::deep_construct( 1037 pContext, *polymorphic_downcast< MostDerived * >( this ) ); 1038 } 1039 else 1040 { 1041 typedef void construct_function( 1042 const typename DefaultState::context_ptr_type &, 1043 typename DefaultState::outermost_context_base_type & ); 1044 // 5.2.10.6 declares that reinterpret_casting a function pointer to a 1045 // different function pointer and back must yield the same value. The 1046 // following reinterpret_cast is the second half of such a sequence. 1047 construct_function * const pConstructFunction = 1048 reinterpret_cast< construct_function * >( pFoundSlot->second ); 1049 (*pConstructFunction)( 1050 pContext, *polymorphic_downcast< MostDerived * >( this ) ); 1051 } 1052 } 1053 1054 typedef std::list< 1055 event_base_ptr_type, 1056 typename boost::detail::allocator::rebind_to< 1057 allocator_type, event_base_ptr_type >::type 1058 > event_queue_type; 1059 1060 typedef std::map< 1061 const state_base_type *, event_queue_type, 1062 std::less< const state_base_type * >, 1063 typename boost::detail::allocator::rebind_to< 1064 allocator_type, 1065 std::pair< const state_base_type * const, event_queue_type > 1066 >::type 1067 > deferred_map_type; 1068 1069 1070 event_queue_type eventQueue_; 1071 event_queue_type deferredEventQueue_; 1072 state_list_type currentStates_; 1073 typename state_list_type::iterator currentStatesEnd_; 1074 state_base_type * pOutermostState_; 1075 bool isInnermostCommonOuter_; 1076 node_state_base_ptr_type pOutermostUnstableState_; 1077 ExceptionTranslator translator_; 1078 bool performFullExit_; 1079 history_map_type shallowHistoryMap_; 1080 history_map_type deepHistoryMap_; 1081 const event_base_type * pTriggeringEvent_; 1082 }; 1083 1084 1085 1086 } // namespace statechart 1087 } // namespace boost 1088 1089 1090 1091 #endif 1092