Chris@16: #ifndef BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED Chris@16: #define BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: // Copyright 2002-2010 Andreas Huber Doenni Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompany- Chris@16: // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include // boost::polymorphic_downcast Chris@16: // BOOST_NO_EXCEPTIONS, BOOST_MSVC, BOOST_MSVC_STD_ITERATOR Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: # pragma warning( push ) Chris@16: # pragma warning( disable: 4702 ) // unreachable code (in release mode only) Chris@16: #endif Chris@16: Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: # pragma warning( pop ) Chris@16: #endif Chris@16: Chris@16: #include // std::allocator Chris@16: #include // std::bad_cast Chris@16: #include // std::less Chris@16: #include Chris@16: Chris@16: Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: namespace statechart Chris@16: { Chris@16: namespace detail Chris@16: { Chris@16: Chris@16: Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: template< class StateBaseType, class EventBaseType, class IdType > Chris@16: class send_function Chris@16: { Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: send_function( Chris@16: StateBaseType & toState, Chris@16: const EventBaseType & evt, Chris@16: IdType eventType Chris@16: ) : Chris@16: toState_( toState ), evt_( evt ), eventType_( eventType ) Chris@16: { Chris@16: } Chris@16: Chris@16: result operator()() Chris@16: { Chris@16: return detail::result_utility::make_result( Chris@16: toState_.react_impl( evt_, eventType_ ) ); Chris@16: } Chris@16: Chris@16: private: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: // avoids C4512 (assignment operator could not be generated) Chris@16: send_function & operator=( const send_function & ); Chris@16: Chris@16: StateBaseType & toState_; Chris@16: const EventBaseType & evt_; Chris@16: IdType eventType_; Chris@16: }; Chris@16: Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: struct state_cast_impl_pointer_target Chris@16: { Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: template< class StateBaseType > Chris@16: static const StateBaseType * deref_if_necessary( Chris@16: const StateBaseType * pState ) Chris@16: { Chris@16: return pState; Chris@16: } Chris@16: Chris@16: template< class Target, class IdType > Chris@16: static IdType type_id() Chris@16: { Chris@16: Target p = 0; Chris@16: return type_id_impl< IdType >( p ); Chris@16: } Chris@16: Chris@16: static bool found( const void * pFound ) Chris@16: { Chris@16: return pFound != 0; Chris@16: } Chris@16: Chris@16: template< class Target > Chris@16: static Target not_found() Chris@16: { Chris@16: return 0; Chris@16: } Chris@16: Chris@16: private: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: template< class IdType, class Type > Chris@16: static IdType type_id_impl( const Type * ) Chris@16: { Chris@16: return Type::static_type(); Chris@16: } Chris@16: }; Chris@16: Chris@16: struct state_cast_impl_reference_target Chris@16: { Chris@16: template< class StateBaseType > Chris@16: static const StateBaseType & deref_if_necessary( Chris@16: const StateBaseType * pState ) Chris@16: { Chris@16: return *pState; Chris@16: } Chris@16: Chris@16: template< class Target, class IdType > Chris@16: static IdType type_id() Chris@16: { Chris@16: return remove_reference< Target >::type::static_type(); Chris@16: } Chris@16: Chris@16: template< class Dummy > Chris@16: static bool found( const Dummy & ) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: Chris@16: template< class Target > Chris@16: static Target not_found() Chris@16: { Chris@16: throw std::bad_cast(); Chris@16: } Chris@16: }; Chris@16: Chris@16: template< class Target > Chris@16: struct state_cast_impl : public mpl::if_< Chris@16: is_pointer< Target >, Chris@16: state_cast_impl_pointer_target, Chris@16: state_cast_impl_reference_target Chris@16: >::type {}; Chris@16: Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: template< class RttiPolicy > Chris@16: class history_key Chris@16: { Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: template< class HistorizedState > Chris@16: static history_key make_history_key() Chris@16: { Chris@16: return history_key( Chris@16: HistorizedState::context_type::static_type(), Chris@16: HistorizedState::orthogonal_position::value ); Chris@16: } Chris@16: Chris@16: typename RttiPolicy::id_type history_context_type() const Chris@16: { Chris@16: return historyContextType_; Chris@16: } Chris@16: Chris@16: friend bool operator<( Chris@16: const history_key & left, const history_key & right ) Chris@16: { Chris@16: return Chris@16: std::less< typename RttiPolicy::id_type >()( Chris@16: left.historyContextType_, right.historyContextType_ ) || Chris@16: ( ( left.historyContextType_ == right.historyContextType_ ) && Chris@16: ( left.historizedOrthogonalRegion_ < Chris@16: right.historizedOrthogonalRegion_ ) ); Chris@16: } Chris@16: Chris@16: private: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: history_key( Chris@16: typename RttiPolicy::id_type historyContextType, Chris@16: orthogonal_position_type historizedOrthogonalRegion Chris@16: ) : Chris@16: historyContextType_( historyContextType ), Chris@16: historizedOrthogonalRegion_( historizedOrthogonalRegion ) Chris@16: { Chris@16: } Chris@16: Chris@16: // avoids C4512 (assignment operator could not be generated) Chris@16: history_key & operator=( const history_key & ); Chris@16: Chris@16: const typename RttiPolicy::id_type historyContextType_; Chris@16: const orthogonal_position_type historizedOrthogonalRegion_; Chris@16: }; Chris@16: Chris@16: Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: Chris@16: Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: template< class MostDerived, Chris@16: class InitialState, Chris@16: class Allocator = std::allocator< void >, Chris@16: class ExceptionTranslator = null_exception_translator > Chris@16: class state_machine : noncopyable Chris@16: { Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: typedef Allocator allocator_type; Chris@16: typedef detail::rtti_policy rtti_policy_type; Chris@16: typedef event_base event_base_type; Chris@16: typedef intrusive_ptr< const event_base_type > event_base_ptr_type; Chris@16: Chris@16: void initiate() Chris@16: { Chris@16: terminate(); Chris@16: Chris@16: { Chris@16: terminator guard( *this, 0 ); Chris@16: detail::result_utility::get_result( translator_( Chris@16: initial_construct_function( *this ), Chris@16: exception_event_handler( *this ) ) ); Chris@16: guard.dismiss(); Chris@16: } Chris@16: Chris@16: process_queued_events(); Chris@16: } Chris@16: Chris@16: void terminate() Chris@16: { Chris@16: terminator guard( *this, 0 ); Chris@16: detail::result_utility::get_result( translator_( Chris@16: terminate_function( *this ), Chris@16: exception_event_handler( *this ) ) ); Chris@16: guard.dismiss(); Chris@16: } Chris@16: Chris@16: bool terminated() const Chris@16: { Chris@16: return pOutermostState_ == 0; Chris@16: } Chris@16: Chris@16: void process_event( const event_base_type & evt ) Chris@16: { Chris@16: if ( send_event( evt ) == detail::do_defer_event ) Chris@16: { Chris@16: deferredEventQueue_.push_back( evt.intrusive_from_this() ); Chris@16: } Chris@16: Chris@16: process_queued_events(); Chris@16: } Chris@16: Chris@16: template< class Target > Chris@16: Target state_cast() const Chris@16: { Chris@16: typedef detail::state_cast_impl< Target > impl; Chris@16: Chris@16: for ( typename state_list_type::const_iterator pCurrentLeafState = Chris@16: currentStates_.begin(); Chris@16: pCurrentLeafState != currentStatesEnd_; Chris@16: ++pCurrentLeafState ) Chris@16: { Chris@16: const state_base_type * pCurrentState( Chris@16: get_pointer( *pCurrentLeafState ) ); Chris@16: Chris@16: while ( pCurrentState != 0 ) Chris@16: { Chris@16: // The unnecessary try/catch overhead for pointer targets is Chris@16: // typically small compared to the cycles dynamic_cast needs Chris@16: #ifndef BOOST_NO_EXCEPTIONS Chris@16: try Chris@16: #endif Chris@16: { Chris@16: Target result = dynamic_cast< Target >( Chris@16: impl::deref_if_necessary( pCurrentState ) ); Chris@16: Chris@16: if ( impl::found( result ) ) Chris@16: { Chris@16: return result; Chris@16: } Chris@16: } Chris@16: #ifndef BOOST_NO_EXCEPTIONS Chris@16: // Intentionally swallow std::bad_cast exceptions. We'll throw one Chris@16: // ourselves when we fail to find a state that can be cast to Target Chris@16: catch ( const std::bad_cast & ) {} Chris@16: #endif Chris@16: Chris@16: pCurrentState = pCurrentState->outer_state_ptr(); Chris@16: } Chris@16: } Chris@16: Chris@16: return impl::template not_found< Target >(); Chris@16: } Chris@16: Chris@16: template< class Target > Chris@16: Target state_downcast() const Chris@16: { Chris@16: typedef detail::state_cast_impl< Target > impl; Chris@16: Chris@16: typename rtti_policy_type::id_type targetType = Chris@16: impl::template type_id< Target, rtti_policy_type::id_type >(); Chris@16: Chris@16: for ( typename state_list_type::const_iterator pCurrentLeafState = Chris@16: currentStates_.begin(); Chris@16: pCurrentLeafState != currentStatesEnd_; Chris@16: ++pCurrentLeafState ) Chris@16: { Chris@16: const state_base_type * pCurrentState( Chris@16: get_pointer( *pCurrentLeafState ) ); Chris@16: Chris@16: while ( pCurrentState != 0 ) Chris@16: { Chris@16: if ( pCurrentState->dynamic_type() == targetType ) Chris@16: { Chris@16: return static_cast< Target >( Chris@16: impl::deref_if_necessary( pCurrentState ) ); Chris@16: } Chris@16: Chris@16: pCurrentState = pCurrentState->outer_state_ptr(); Chris@16: } Chris@16: } Chris@16: Chris@16: return impl::template not_found< Target >(); Chris@16: } Chris@16: Chris@16: typedef detail::state_base< allocator_type, rtti_policy_type > Chris@16: state_base_type; Chris@16: Chris@16: class state_iterator : public std::iterator< Chris@16: std::forward_iterator_tag, Chris@16: state_base_type, std::ptrdiff_t Chris@16: #ifndef BOOST_MSVC_STD_ITERATOR Chris@16: , const state_base_type *, const state_base_type & Chris@16: #endif Chris@16: > Chris@16: { Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////// Chris@16: explicit state_iterator( Chris@16: typename state_base_type::state_list_type::const_iterator Chris@16: baseIterator Chris@16: ) : baseIterator_( baseIterator ) {} Chris@16: Chris@16: const state_base_type & operator*() const { return **baseIterator_; } Chris@16: const state_base_type * operator->() const Chris@16: { Chris@16: return &**baseIterator_; Chris@16: } Chris@16: Chris@16: state_iterator & operator++() { ++baseIterator_; return *this; } Chris@16: state_iterator operator++( int ) Chris@16: { Chris@16: return state_iterator( baseIterator_++ ); Chris@16: } Chris@16: Chris@16: bool operator==( const state_iterator & right ) const Chris@16: { Chris@16: return baseIterator_ == right.baseIterator_; Chris@16: } Chris@16: bool operator!=( const state_iterator & right ) const Chris@16: { Chris@16: return !( *this == right ); Chris@16: } Chris@16: Chris@16: private: Chris@16: typename state_base_type::state_list_type::const_iterator Chris@16: baseIterator_; Chris@16: }; Chris@16: Chris@16: state_iterator state_begin() const Chris@16: { Chris@16: return state_iterator( currentStates_.begin() ); Chris@16: } Chris@16: Chris@16: state_iterator state_end() const Chris@16: { Chris@16: return state_iterator( currentStatesEnd_ ); Chris@16: } Chris@16: Chris@16: void unconsumed_event( const event_base & ) {} Chris@16: Chris@16: protected: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: state_machine() : Chris@16: currentStatesEnd_( currentStates_.end() ), Chris@16: pOutermostState_( 0 ), Chris@16: isInnermostCommonOuter_( false ), Chris@16: performFullExit_( true ), Chris@16: pTriggeringEvent_( 0 ) Chris@16: { Chris@16: } Chris@16: Chris@16: // This destructor was only made virtual so that that Chris@16: // polymorphic_downcast can be used to cast to MostDerived. Chris@16: virtual ~state_machine() Chris@16: { Chris@16: terminate_impl( false ); Chris@16: } Chris@16: Chris@16: void post_event( const event_base_ptr_type & pEvent ) Chris@16: { Chris@16: post_event_impl( pEvent ); Chris@16: } Chris@16: Chris@16: void post_event( const event_base & evt ) Chris@16: { Chris@16: post_event_impl( evt ); Chris@16: } Chris@16: Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: // The following declarations should be protected. Chris@16: // They are only public because many compilers lack template friends. Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: template< Chris@16: class HistoryContext, Chris@16: detail::orthogonal_position_type orthogonalPosition > Chris@16: void clear_shallow_history() Chris@16: { Chris@16: // If you receive a Chris@16: // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE'" or Chris@16: // similar compiler error here then you tried to clear shallow history Chris@16: // for a state that does not have shallow history. That is, the state Chris@16: // does not pass either statechart::has_shallow_history or Chris@16: // statechart::has_full_history to its base class template. Chris@16: BOOST_STATIC_ASSERT( HistoryContext::shallow_history::value ); Chris@16: Chris@16: typedef typename mpl::at_c< Chris@16: typename HistoryContext::inner_initial_list, Chris@16: orthogonalPosition >::type historized_state; Chris@16: Chris@16: store_history_impl( Chris@16: shallowHistoryMap_, Chris@16: history_key_type::make_history_key< historized_state >(), Chris@16: 0 ); Chris@16: } Chris@16: Chris@16: template< Chris@16: class HistoryContext, Chris@16: detail::orthogonal_position_type orthogonalPosition > Chris@16: void clear_deep_history() Chris@16: { Chris@16: // If you receive a Chris@16: // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE'" or Chris@16: // similar compiler error here then you tried to clear deep history for Chris@16: // a state that does not have deep history. That is, the state does not Chris@16: // pass either statechart::has_deep_history or Chris@16: // statechart::has_full_history to its base class template Chris@16: BOOST_STATIC_ASSERT( HistoryContext::deep_history::value ); Chris@16: Chris@16: typedef typename mpl::at_c< Chris@16: typename HistoryContext::inner_initial_list, Chris@16: orthogonalPosition >::type historized_state; Chris@16: Chris@16: store_history_impl( Chris@16: deepHistoryMap_, Chris@16: history_key_type::make_history_key< historized_state >(), Chris@16: 0 ); Chris@16: } Chris@16: Chris@16: const event_base_type * triggering_event() const Chris@16: { Chris@16: return pTriggeringEvent_; Chris@16: } Chris@16: Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: // The following declarations should be private. Chris@16: // They are only public because many compilers lack template friends. Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: typedef MostDerived inner_context_type; Chris@16: typedef mpl::integral_c< detail::orthogonal_position_type, 0 > Chris@16: inner_orthogonal_position; Chris@16: typedef mpl::integral_c< detail::orthogonal_position_type, 1 > Chris@16: no_of_orthogonal_regions; Chris@16: Chris@16: typedef MostDerived outermost_context_type; Chris@16: typedef state_machine outermost_context_base_type; Chris@16: typedef state_machine * inner_context_ptr_type; Chris@16: typedef typename state_base_type::node_state_base_ptr_type Chris@16: node_state_base_ptr_type; Chris@16: typedef typename state_base_type::leaf_state_ptr_type leaf_state_ptr_type; Chris@16: typedef typename state_base_type::state_list_type state_list_type; Chris@16: Chris@16: typedef mpl::clear< mpl::list<> >::type context_type_list; Chris@16: Chris@16: typedef mpl::bool_< false > shallow_history; Chris@16: typedef mpl::bool_< false > deep_history; Chris@16: typedef mpl::bool_< false > inherited_deep_history; Chris@16: Chris@16: void post_event_impl( const event_base_ptr_type & pEvent ) Chris@16: { Chris@16: BOOST_ASSERT( get_pointer( pEvent ) != 0 ); Chris@16: eventQueue_.push_back( pEvent ); Chris@16: } Chris@16: Chris@16: void post_event_impl( const event_base & evt ) Chris@16: { Chris@16: post_event_impl( evt.intrusive_from_this() ); Chris@16: } Chris@16: Chris@16: detail::reaction_result react_impl( Chris@16: const event_base_type &, Chris@16: typename rtti_policy_type::id_type ) Chris@16: { Chris@16: return detail::do_forward_event; Chris@16: } Chris@16: Chris@16: void exit_impl( Chris@16: inner_context_ptr_type &, Chris@16: typename state_base_type::node_state_base_ptr_type &, Chris@16: bool ) {} Chris@16: Chris@16: void set_outermost_unstable_state( Chris@16: typename state_base_type::node_state_base_ptr_type & Chris@16: pOutermostUnstableState ) Chris@16: { Chris@16: pOutermostUnstableState = 0; Chris@16: } Chris@16: Chris@16: // Returns a reference to the context identified by the template Chris@16: // parameter. This can either be _this_ object or one of its direct or Chris@16: // indirect contexts. Chris@16: template< class Context > Chris@16: Context & context() Chris@16: { Chris@16: // As we are in the outermost context here, only this object can be Chris@16: // returned. Chris@16: return *polymorphic_downcast< MostDerived * >( this ); Chris@16: } Chris@16: Chris@16: template< class Context > Chris@16: const Context & context() const Chris@16: { Chris@16: // As we are in the outermost context here, only this object can be Chris@16: // returned. Chris@16: return *polymorphic_downcast< const MostDerived * >( this ); Chris@16: } Chris@16: Chris@16: outermost_context_type & outermost_context() Chris@16: { Chris@16: return *polymorphic_downcast< MostDerived * >( this ); Chris@16: } Chris@16: Chris@16: const outermost_context_type & outermost_context() const Chris@16: { Chris@16: return *polymorphic_downcast< const MostDerived * >( this ); Chris@16: } Chris@16: Chris@16: outermost_context_base_type & outermost_context_base() Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: Chris@16: const outermost_context_base_type & outermost_context_base() const Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: Chris@16: void terminate_as_reaction( state_base_type & theState ) Chris@16: { Chris@16: terminate_impl( theState, performFullExit_ ); Chris@16: pOutermostUnstableState_ = 0; Chris@16: } Chris@16: Chris@16: void terminate_as_part_of_transit( state_base_type & theState ) Chris@16: { Chris@16: terminate_impl( theState, performFullExit_ ); Chris@16: isInnermostCommonOuter_ = true; Chris@16: } Chris@16: Chris@16: void terminate_as_part_of_transit( state_machine & ) Chris@16: { Chris@16: terminate_impl( *pOutermostState_, performFullExit_ ); Chris@16: isInnermostCommonOuter_ = true; Chris@16: } Chris@16: Chris@16: Chris@16: template< class State > Chris@16: void add( const intrusive_ptr< State > & pState ) Chris@16: { Chris@16: // The second dummy argument is necessary because the call to the Chris@16: // overloaded function add_impl would otherwise be ambiguous. Chris@16: node_state_base_ptr_type pNewOutermostUnstableStateCandidate = Chris@16: add_impl( pState, *pState ); Chris@16: Chris@16: if ( isInnermostCommonOuter_ || Chris@16: ( is_in_highest_orthogonal_region< State >() && Chris@16: ( get_pointer( pOutermostUnstableState_ ) == Chris@16: pState->State::outer_state_ptr() ) ) ) Chris@16: { Chris@16: isInnermostCommonOuter_ = false; Chris@16: pOutermostUnstableState_ = pNewOutermostUnstableStateCandidate; Chris@16: } Chris@16: } Chris@16: Chris@16: Chris@16: void add_inner_state( Chris@16: detail::orthogonal_position_type position, Chris@16: state_base_type * pOutermostState ) Chris@16: { Chris@16: BOOST_ASSERT( position == 0 ); Chris@16: detail::avoid_unused_warning( position ); Chris@16: pOutermostState_ = pOutermostState; Chris@16: } Chris@16: Chris@16: void remove_inner_state( detail::orthogonal_position_type position ) Chris@16: { Chris@16: BOOST_ASSERT( position == 0 ); Chris@16: detail::avoid_unused_warning( position ); Chris@16: pOutermostState_ = 0; Chris@16: } Chris@16: Chris@16: Chris@16: void release_events() Chris@16: { Chris@16: eventQueue_.splice( eventQueue_.begin(), deferredEventQueue_ ); Chris@16: } Chris@16: Chris@16: Chris@16: template< class HistorizedState > Chris@16: void store_shallow_history() Chris@16: { Chris@16: // 5.2.10.6 declares that reinterpret_casting a function pointer to a Chris@16: // different function pointer and back must yield the same value. The Chris@16: // following reinterpret_cast is the first half of such a sequence. Chris@16: store_history_impl( Chris@16: shallowHistoryMap_, Chris@16: history_key_type::make_history_key< HistorizedState >(), Chris@16: reinterpret_cast< void (*)() >( &HistorizedState::deep_construct ) ); Chris@16: } Chris@16: Chris@16: template< class DefaultState > Chris@16: void construct_with_shallow_history( Chris@16: const typename DefaultState::context_ptr_type & pContext ) Chris@16: { Chris@16: construct_with_history_impl< DefaultState >( Chris@16: shallowHistoryMap_, pContext ); Chris@16: } Chris@16: Chris@16: Chris@16: template< class HistorizedState, class LeafState > Chris@16: void store_deep_history() Chris@16: { Chris@16: typedef typename detail::make_context_list< Chris@16: typename HistorizedState::context_type, Chris@16: LeafState >::type history_context_list; Chris@16: typedef detail::constructor< Chris@16: history_context_list, outermost_context_base_type > constructor_type; Chris@16: // 5.2.10.6 declares that reinterpret_casting a function pointer to a Chris@16: // different function pointer and back must yield the same value. The Chris@16: // following reinterpret_cast is the first half of such a sequence. Chris@16: store_history_impl( Chris@16: deepHistoryMap_, Chris@16: history_key_type::make_history_key< HistorizedState >(), Chris@16: reinterpret_cast< void (*)() >( &constructor_type::construct ) ); Chris@16: } Chris@16: Chris@16: template< class DefaultState > Chris@16: void construct_with_deep_history( Chris@16: const typename DefaultState::context_ptr_type & pContext ) Chris@16: { Chris@16: construct_with_history_impl< DefaultState >( Chris@16: deepHistoryMap_, pContext ); Chris@16: } Chris@16: Chris@16: private: // implementation Chris@16: ////////////////////////////////////////////////////////////////////////// Chris@16: void initial_construct() Chris@16: { Chris@16: InitialState::initial_deep_construct( Chris@16: *polymorphic_downcast< MostDerived * >( this ) ); Chris@16: } Chris@16: Chris@16: class initial_construct_function Chris@16: { Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////// Chris@16: initial_construct_function( state_machine & machine ) : Chris@16: machine_( machine ) Chris@16: { Chris@16: } Chris@16: Chris@16: result operator()() Chris@16: { Chris@16: machine_.initial_construct(); Chris@16: return detail::result_utility::make_result( Chris@16: detail::do_discard_event ); // there is nothing to be consumed Chris@16: } Chris@16: Chris@16: private: Chris@16: ////////////////////////////////////////////////////////////////////// Chris@16: // avoids C4512 (assignment operator could not be generated) Chris@16: initial_construct_function & operator=( Chris@16: const initial_construct_function & ); Chris@16: Chris@16: state_machine & machine_; Chris@16: }; Chris@16: friend class initial_construct_function; Chris@16: Chris@16: class terminate_function Chris@16: { Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////// Chris@16: terminate_function( state_machine & machine ) : machine_( machine ) {} Chris@16: Chris@16: result operator()() Chris@16: { Chris@16: machine_.terminate_impl( true ); Chris@16: return detail::result_utility::make_result( Chris@16: detail::do_discard_event ); // there is nothing to be consumed Chris@16: } Chris@16: Chris@16: private: Chris@16: ////////////////////////////////////////////////////////////////////// Chris@16: // avoids C4512 (assignment operator could not be generated) Chris@16: terminate_function & operator=( const terminate_function & ); Chris@16: Chris@16: state_machine & machine_; Chris@16: }; Chris@16: friend class terminate_function; Chris@16: Chris@16: template< class ExceptionEvent > Chris@16: detail::reaction_result handle_exception_event( Chris@16: const ExceptionEvent & exceptionEvent, Chris@16: state_base_type * pCurrentState ) Chris@16: { Chris@16: if ( terminated() ) Chris@16: { Chris@16: // there is no state that could handle the exception -> bail out Chris@16: throw; Chris@16: } Chris@16: Chris@16: // If we are stable, an event handler has thrown. Chris@16: // Otherwise, either a state constructor, a transition action or an exit Chris@16: // function has thrown and the state machine is now in an invalid state. Chris@16: // This situation can be resolved by the exception event handler Chris@16: // function by orderly transiting to another state or terminating. Chris@16: // As a result of this, the machine must not be unstable when this Chris@16: // function is left. Chris@16: state_base_type * const pOutermostUnstableState = Chris@16: get_pointer( pOutermostUnstableState_ ); Chris@16: state_base_type * const pHandlingState = pOutermostUnstableState == 0 ? Chris@16: pCurrentState : pOutermostUnstableState; Chris@16: Chris@16: BOOST_ASSERT( pHandlingState != 0 ); Chris@16: terminator guard( *this, &exceptionEvent ); Chris@16: // There is another scope guard up the call stack, which will terminate Chris@16: // the machine. So this guard only sets the triggering event. Chris@16: guard.dismiss(); Chris@16: Chris@16: // Setting a member variable to a special value for the duration of a Chris@16: // call surely looks like a kludge (normally it should be a parameter of Chris@16: // the call). However, in this case it is unavoidable because the call Chris@16: // below could result in a call to user code where passing through an Chris@16: // additional bool parameter is not acceptable. Chris@16: performFullExit_ = false; Chris@16: const detail::reaction_result reactionResult = pHandlingState->react_impl( Chris@16: exceptionEvent, exceptionEvent.dynamic_type() ); Chris@16: // If the above call throws then performFullExit_ will obviously not be Chris@16: // set back to true. In this case the termination triggered by the Chris@16: // scope guard further up in the call stack will take care of this. Chris@16: performFullExit_ = true; Chris@16: Chris@16: if ( ( reactionResult != detail::do_discard_event ) || Chris@16: ( get_pointer( pOutermostUnstableState_ ) != 0 ) ) Chris@16: { Chris@16: throw; Chris@16: } Chris@16: Chris@16: return detail::do_discard_event; Chris@16: } Chris@16: Chris@16: class exception_event_handler Chris@16: { Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////// Chris@16: exception_event_handler( Chris@16: state_machine & machine, Chris@16: state_base_type * pCurrentState = 0 Chris@16: ) : Chris@16: machine_( machine ), Chris@16: pCurrentState_( pCurrentState ) Chris@16: { Chris@16: } Chris@16: Chris@16: template< class ExceptionEvent > Chris@16: result operator()( Chris@16: const ExceptionEvent & exceptionEvent ) Chris@16: { Chris@16: return detail::result_utility::make_result( Chris@16: machine_.handle_exception_event( Chris@16: exceptionEvent, pCurrentState_ ) ); Chris@16: } Chris@16: Chris@16: private: Chris@16: ////////////////////////////////////////////////////////////////////// Chris@16: // avoids C4512 (assignment operator could not be generated) Chris@16: exception_event_handler & operator=( Chris@16: const exception_event_handler & ); Chris@16: Chris@16: state_machine & machine_; Chris@16: state_base_type * pCurrentState_; Chris@16: }; Chris@16: friend class exception_event_handler; Chris@16: Chris@16: class terminator Chris@16: { Chris@16: public: Chris@16: ////////////////////////////////////////////////////////////////////// Chris@16: terminator( Chris@16: state_machine & machine, const event_base * pNewTriggeringEvent ) : Chris@16: machine_( machine ), Chris@16: pOldTriggeringEvent_(machine_.pTriggeringEvent_), Chris@16: dismissed_( false ) Chris@16: { Chris@16: machine_.pTriggeringEvent_ = pNewTriggeringEvent; Chris@16: } Chris@16: Chris@16: ~terminator() Chris@16: { Chris@16: if ( !dismissed_ ) { machine_.terminate_impl( false ); } Chris@16: machine_.pTriggeringEvent_ = pOldTriggeringEvent_; Chris@16: } Chris@16: Chris@16: void dismiss() { dismissed_ = true; } Chris@16: Chris@16: private: Chris@16: ////////////////////////////////////////////////////////////////////// Chris@16: // avoids C4512 (assignment operator could not be generated) Chris@16: terminator & operator=( const terminator & ); Chris@16: Chris@16: state_machine & machine_; Chris@16: const event_base_type * const pOldTriggeringEvent_; Chris@16: bool dismissed_; Chris@16: }; Chris@16: friend class terminator; Chris@16: Chris@16: Chris@16: detail::reaction_result send_event( const event_base_type & evt ) Chris@16: { Chris@16: terminator guard( *this, &evt ); Chris@16: BOOST_ASSERT( get_pointer( pOutermostUnstableState_ ) == 0 ); Chris@16: const typename rtti_policy_type::id_type eventType = evt.dynamic_type(); Chris@16: detail::reaction_result reactionResult = detail::do_forward_event; Chris@16: Chris@16: for ( Chris@16: typename state_list_type::iterator pState = currentStates_.begin(); Chris@16: ( reactionResult == detail::do_forward_event ) && Chris@16: ( pState != currentStatesEnd_ ); Chris@16: ++pState ) Chris@16: { Chris@16: // CAUTION: The following statement could modify our state list! Chris@16: // We must not continue iterating if the event was consumed Chris@16: reactionResult = detail::result_utility::get_result( translator_( Chris@16: detail::send_function< Chris@16: state_base_type, event_base_type, rtti_policy_type::id_type >( Chris@16: **pState, evt, eventType ), Chris@16: exception_event_handler( *this, get_pointer( *pState ) ) ) ); Chris@16: } Chris@16: Chris@16: guard.dismiss(); Chris@16: Chris@16: if ( reactionResult == detail::do_forward_event ) Chris@16: { Chris@16: polymorphic_downcast< MostDerived * >( this )->unconsumed_event( evt ); Chris@16: } Chris@16: Chris@16: return reactionResult; Chris@16: } Chris@16: Chris@16: Chris@16: void process_queued_events() Chris@16: { Chris@16: while ( !eventQueue_.empty() ) Chris@16: { Chris@16: event_base_ptr_type pEvent = eventQueue_.front(); Chris@16: eventQueue_.pop_front(); Chris@16: Chris@16: if ( send_event( *pEvent ) == detail::do_defer_event ) Chris@16: { Chris@16: deferredEventQueue_.push_back( pEvent ); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: Chris@16: void terminate_impl( bool performFullExit ) Chris@16: { Chris@16: performFullExit_ = true; Chris@16: Chris@16: if ( !terminated() ) Chris@16: { Chris@16: terminate_impl( *pOutermostState_, performFullExit ); Chris@16: } Chris@16: Chris@16: eventQueue_.clear(); Chris@16: deferredEventQueue_.clear(); Chris@16: shallowHistoryMap_.clear(); Chris@16: deepHistoryMap_.clear(); Chris@16: } Chris@16: Chris@16: void terminate_impl( state_base_type & theState, bool performFullExit ) Chris@16: { Chris@16: isInnermostCommonOuter_ = false; Chris@16: Chris@16: // If pOutermostUnstableState_ == 0, we know for sure that Chris@16: // currentStates_.size() > 0, otherwise theState couldn't be alive any Chris@16: // more Chris@16: if ( get_pointer( pOutermostUnstableState_ ) != 0 ) Chris@16: { Chris@16: theState.remove_from_state_list( Chris@16: currentStatesEnd_, pOutermostUnstableState_, performFullExit ); Chris@16: } Chris@16: // Optimization: We want to find out whether currentStates_ has size 1 Chris@16: // and if yes use the optimized implementation below. Since Chris@16: // list<>::size() is implemented quite inefficiently in some std libs Chris@16: // it is best to just decrement the currentStatesEnd_ here and Chris@16: // increment it again, if the test failed. Chris@16: else if ( currentStates_.begin() == --currentStatesEnd_ ) Chris@16: { Chris@16: // The machine is stable and there is exactly one innermost state. Chris@16: // The following optimization is only correct for a stable machine Chris@16: // without orthogonal regions. Chris@16: leaf_state_ptr_type & pState = *currentStatesEnd_; Chris@16: pState->exit_impl( Chris@16: pState, pOutermostUnstableState_, performFullExit ); Chris@16: } Chris@16: else Chris@16: { Chris@16: BOOST_ASSERT( currentStates_.size() > 1 ); Chris@16: // The machine is stable and there are multiple innermost states Chris@16: theState.remove_from_state_list( Chris@16: ++currentStatesEnd_, pOutermostUnstableState_, performFullExit ); Chris@16: } Chris@16: } Chris@16: Chris@16: Chris@16: node_state_base_ptr_type add_impl( Chris@16: const leaf_state_ptr_type & pState, Chris@16: detail::leaf_state< allocator_type, rtti_policy_type > & ) Chris@16: { Chris@16: if ( currentStatesEnd_ == currentStates_.end() ) Chris@16: { Chris@16: pState->set_list_position( Chris@16: currentStates_.insert( currentStatesEnd_, pState ) ); Chris@16: } Chris@16: else Chris@16: { Chris@16: *currentStatesEnd_ = pState; Chris@16: pState->set_list_position( currentStatesEnd_ ); Chris@16: ++currentStatesEnd_; Chris@16: } Chris@16: Chris@16: return 0; Chris@16: } Chris@16: Chris@16: node_state_base_ptr_type add_impl( Chris@16: const node_state_base_ptr_type & pState, Chris@16: state_base_type & ) Chris@16: { Chris@16: return pState; Chris@16: } Chris@16: Chris@16: template< class State > Chris@16: static bool is_in_highest_orthogonal_region() Chris@16: { Chris@16: return mpl::equal_to< Chris@16: typename State::orthogonal_position, Chris@16: mpl::minus< Chris@16: typename State::context_type::no_of_orthogonal_regions, Chris@16: mpl::integral_c< detail::orthogonal_position_type, 1 > > Chris@16: >::value; Chris@16: } Chris@16: Chris@16: Chris@16: typedef detail::history_key< rtti_policy_type > history_key_type; Chris@16: Chris@16: typedef std::map< Chris@16: history_key_type, void (*)(), Chris@16: std::less< history_key_type >, Chris@16: typename boost::detail::allocator::rebind_to< Chris@16: allocator_type, std::pair< const history_key_type, void (*)() > Chris@16: >::type Chris@16: > history_map_type; Chris@16: Chris@16: void store_history_impl( Chris@16: history_map_type & historyMap, Chris@16: const history_key_type & historyId, Chris@16: void (*pConstructFunction)() ) Chris@16: { Chris@16: historyMap[ historyId ] = pConstructFunction; Chris@16: } Chris@16: Chris@16: template< class DefaultState > Chris@16: void construct_with_history_impl( Chris@16: history_map_type & historyMap, Chris@16: const typename DefaultState::context_ptr_type & pContext ) Chris@16: { Chris@16: typename history_map_type::iterator pFoundSlot = historyMap.find( Chris@16: history_key_type::make_history_key< DefaultState >() ); Chris@16: Chris@16: if ( ( pFoundSlot == historyMap.end() ) || ( pFoundSlot->second == 0 ) ) Chris@16: { Chris@16: // We have never entered this state before or history was cleared Chris@16: DefaultState::deep_construct( Chris@16: pContext, *polymorphic_downcast< MostDerived * >( this ) ); Chris@16: } Chris@16: else Chris@16: { Chris@16: typedef void construct_function( Chris@16: const typename DefaultState::context_ptr_type &, Chris@16: typename DefaultState::outermost_context_base_type & ); Chris@16: // 5.2.10.6 declares that reinterpret_casting a function pointer to a Chris@16: // different function pointer and back must yield the same value. The Chris@16: // following reinterpret_cast is the second half of such a sequence. Chris@16: construct_function * const pConstructFunction = Chris@16: reinterpret_cast< construct_function * >( pFoundSlot->second ); Chris@16: (*pConstructFunction)( Chris@16: pContext, *polymorphic_downcast< MostDerived * >( this ) ); Chris@16: } Chris@16: } Chris@16: Chris@16: typedef std::list< Chris@16: event_base_ptr_type, Chris@16: typename boost::detail::allocator::rebind_to< Chris@16: allocator_type, event_base_ptr_type >::type Chris@16: > event_queue_type; Chris@16: Chris@16: typedef std::map< Chris@16: const state_base_type *, event_queue_type, Chris@16: std::less< const state_base_type * >, Chris@16: typename boost::detail::allocator::rebind_to< Chris@16: allocator_type, Chris@16: std::pair< const state_base_type * const, event_queue_type > Chris@16: >::type Chris@16: > deferred_map_type; Chris@16: Chris@16: Chris@16: event_queue_type eventQueue_; Chris@16: event_queue_type deferredEventQueue_; Chris@16: state_list_type currentStates_; Chris@16: typename state_list_type::iterator currentStatesEnd_; Chris@16: state_base_type * pOutermostState_; Chris@16: bool isInnermostCommonOuter_; Chris@16: node_state_base_ptr_type pOutermostUnstableState_; Chris@16: ExceptionTranslator translator_; Chris@16: bool performFullExit_; Chris@16: history_map_type shallowHistoryMap_; Chris@16: history_map_type deepHistoryMap_; Chris@16: const event_base_type * pTriggeringEvent_; Chris@16: }; Chris@16: Chris@16: Chris@16: Chris@16: } // namespace statechart Chris@16: } // namespace boost Chris@16: Chris@16: Chris@16: Chris@16: #endif