📄 state_machine.hpp
字号:
class initial_construct_function
{
public:
//////////////////////////////////////////////////////////////////////
initial_construct_function( state_machine & machine ) :
machine_( machine )
{
}
result operator()()
{
machine_.initial_construct();
return detail::result_utility::make_result(
detail::do_discard_event ); // there is nothing to be consumed
}
private:
//////////////////////////////////////////////////////////////////////
state_machine & machine_;
};
friend class initial_construct_function;
class terminate_function
{
public:
//////////////////////////////////////////////////////////////////////
terminate_function( state_machine & machine ) : machine_( machine ) {}
result operator()()
{
machine_.terminate_impl( true );
return detail::result_utility::make_result(
detail::do_discard_event ); // there is nothing to be consumed
}
private:
//////////////////////////////////////////////////////////////////////
state_machine & machine_;
};
friend class terminate_function;
template< class ExceptionEvent >
detail::reaction_result handle_exception_event(
const ExceptionEvent & exceptionEvent,
state_base_type * pCurrentState )
{
if ( terminated() )
{
// there is no state that could handle the exception -> bail out
throw;
}
// If we are stable, an event handler has thrown.
// Otherwise, either a state constructor, a transition action or an exit
// function has thrown and the state machine is now in an invalid state.
// This situation can be resolved by the exception event handler
// function by orderly transiting to another state or terminating.
// As a result of this, the machine must not be unstable when this
// function is left.
state_base_type * const pOutermostUnstableState =
get_pointer( pOutermostUnstableState_ );
state_base_type * const pHandlingState = pOutermostUnstableState == 0 ?
pCurrentState : pOutermostUnstableState;
BOOST_ASSERT( pHandlingState != 0 );
// Setting a member variable to a special value for the duration of a
// call surely looks like a kludge (normally it should be a parameter of
// the call). However, in this case it is unavoidable because the call
// below could result in a call to user code where passing through an
// additional bool parameter is not acceptable.
performFullExit_ = false;
const detail::reaction_result reactionResult = pHandlingState->react_impl(
exceptionEvent, exceptionEvent.dynamic_type() );
// If the above call throws then performFullExit_ will obviously not be
// set back to true. In this case the termination triggered by the
// scope guard further up in the call stack will take care of this.
performFullExit_ = true;
if ( ( reactionResult != detail::do_discard_event ) ||
( get_pointer( pOutermostUnstableState_ ) != 0 ) )
{
throw;
}
return detail::do_discard_event;
}
class exception_event_handler
{
public:
//////////////////////////////////////////////////////////////////////
exception_event_handler(
state_machine & machine,
state_base_type * pCurrentState = 0
) :
machine_( machine ),
pCurrentState_( pCurrentState )
{
}
template< class ExceptionEvent >
result operator()(
const ExceptionEvent & exceptionEvent )
{
return detail::result_utility::make_result(
machine_.handle_exception_event(
exceptionEvent, pCurrentState_ ) );
}
private:
//////////////////////////////////////////////////////////////////////
state_machine & machine_;
state_base_type * pCurrentState_;
};
friend class exception_event_handler;
class terminator
{
public:
terminator( state_machine & machine ) :
machine_( machine ), dismissed_( false ) {}
~terminator()
{
if ( !dismissed_ ) { machine_.terminate_impl( false ); }
}
void dismiss() { dismissed_ = true; }
private:
state_machine & machine_;
bool dismissed_;
};
friend class terminator;
void send_event( const event_base_type & evt )
{
terminator guard( *this );
BOOST_ASSERT( get_pointer( pOutermostUnstableState_ ) == 0 );
const typename rtti_policy_type::id_type eventType = evt.dynamic_type();
detail::reaction_result reactionResult = detail::do_forward_event;
for (
typename state_list_type::iterator pState = currentStates_.begin();
( reactionResult == detail::do_forward_event ) &&
( pState != currentStatesEnd_ );
++pState )
{
// CAUTION: The following statement could modify our state list!
// We must not continue iterating if the event was consumed
reactionResult = detail::result_utility::get_result( translator_(
detail::send_function<
state_base_type, event_base_type, rtti_policy_type::id_type >(
**pState, evt, eventType ),
exception_event_handler( *this, get_pointer( *pState ) ) ) );
}
guard.dismiss();
if ( reactionResult == detail::do_forward_event )
{
polymorphic_downcast< MostDerived * >( this )->unconsumed_event( evt );
}
}
void process_queued_events()
{
while ( !eventQueue_.empty() )
{
const event_base_ptr_type pCurrentEvent( eventQueue_.front() );
eventQueue_.pop_front();
send_event( *pCurrentEvent );
}
}
void terminate_impl( bool performFullExit )
{
performFullExit_ = true;
if ( !terminated() )
{
// this also empties deferredMap_
terminate_impl( *pOutermostState_, performFullExit );
}
eventQueue_.clear();
shallowHistoryMap_.clear();
deepHistoryMap_.clear();
}
void terminate_impl( state_base_type & theState, bool performFullExit )
{
isInnermostCommonOuter_ = false;
// If pOutermostUnstableState_ == 0, we know for sure that
// currentStates_.size() > 0, otherwise theState couldn't be alive any
// more
if ( get_pointer( pOutermostUnstableState_ ) != 0 )
{
theState.remove_from_state_list(
currentStatesEnd_, pOutermostUnstableState_, performFullExit );
}
// Optimization: We want to find out whether currentStates_ has size 1
// and if yes use the optimized implementation below. Since
// list<>::size() is implemented quite inefficiently in some std libs
// it is best to just decrement the currentStatesEnd_ here and
// increment it again, if the test failed.
else if ( currentStates_.begin() == --currentStatesEnd_ )
{
// The machine is stable and there is exactly one innermost state.
// The following optimization is only correct for a stable machine
// without orthogonal regions.
leaf_state_ptr_type & pState = *currentStatesEnd_;
pState->exit_impl(
pState, pOutermostUnstableState_, performFullExit );
}
else
{
BOOST_ASSERT( currentStates_.size() > 1 );
// The machine is stable and there are multiple innermost states
theState.remove_from_state_list(
++currentStatesEnd_, pOutermostUnstableState_, performFullExit );
}
}
node_state_base_ptr_type add_impl(
const leaf_state_ptr_type & pState,
detail::leaf_state< allocator_type, rtti_policy_type > & )
{
if ( currentStatesEnd_ == currentStates_.end() )
{
pState->set_list_position(
currentStates_.insert( currentStatesEnd_, pState ) );
}
else
{
*currentStatesEnd_ = pState;
pState->set_list_position( currentStatesEnd_ );
++currentStatesEnd_;
}
return 0;
}
node_state_base_ptr_type add_impl(
const node_state_base_ptr_type & pState,
state_base_type & )
{
return pState;
}
template< class State >
static bool is_in_highest_orthogonal_region()
{
return mpl::equal_to<
typename State::orthogonal_position,
mpl::minus<
typename State::context_type::no_of_orthogonal_regions,
mpl::integral_c< detail::orthogonal_position_type, 1 > >
>::value;
}
typedef detail::history_key< rtti_policy_type > history_key_type;
typedef std::map<
history_key_type, void (*)(),
std::less< history_key_type >,
typename boost::detail::allocator::rebind_to<
allocator_type, std::pair< const history_key_type, void (*)() >
>::type
> history_map_type;
void store_history_impl(
history_map_type & historyMap,
const history_key_type & historyId,
void (*pConstructFunction)() )
{
historyMap[ historyId ] = pConstructFunction;
}
template< class DefaultState >
void construct_with_history_impl(
history_map_type & historyMap,
const typename DefaultState::context_ptr_type & pContext )
{
typename history_map_type::iterator pFoundSlot = historyMap.find(
history_key_type::make_history_key< DefaultState >() );
if ( ( pFoundSlot == historyMap.end() ) || ( pFoundSlot->second == 0 ) )
{
// We have never entered this state before or history was cleared
DefaultState::deep_construct(
pContext, *polymorphic_downcast< MostDerived * >( this ) );
}
else
{
typedef void construct_function(
const typename DefaultState::context_ptr_type &,
typename DefaultState::outermost_context_base_type & );
// 5.2.10.6 declares that reinterpret_casting a function pointer to a
// different function pointer and back must yield the same value. The
// following reinterpret_cast is the second half of such a sequence.
construct_function * const pConstructFunction =
reinterpret_cast< construct_function * >( pFoundSlot->second );
(*pConstructFunction)(
pContext, *polymorphic_downcast< MostDerived * >( this ) );
}
}
typedef std::list<
event_base_ptr_type,
typename boost::detail::allocator::rebind_to<
allocator_type, event_base_ptr_type >::type
> event_queue_type;
typedef std::map<
const state_base_type *, event_queue_type,
std::less< const state_base_type * >,
typename boost::detail::allocator::rebind_to<
allocator_type,
std::pair< const state_base_type * const, event_queue_type >
>::type
> deferred_map_type;
event_queue_type eventQueue_;
deferred_map_type deferredMap_;
state_list_type currentStates_;
typename state_list_type::iterator currentStatesEnd_;
state_base_type * pOutermostState_;
bool isInnermostCommonOuter_;
node_state_base_ptr_type pOutermostUnstableState_;
ExceptionTranslator translator_;
bool performFullExit_;
history_map_type shallowHistoryMap_;
history_map_type deepHistoryMap_;
};
} // namespace statechart
} // namespace boost
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -