You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
156 lines
5.1 KiB
156 lines
5.1 KiB
#ifndef BOOST_STATECHART_DETAIL_NODE_STATE_HPP_INCLUDED |
|
#define BOOST_STATECHART_DETAIL_NODE_STATE_HPP_INCLUDED |
|
////////////////////////////////////////////////////////////////////////////// |
|
// Copyright 2002-2006 Andreas Huber Doenni |
|
// Distributed under the Boost Software License, Version 1.0. (See accompany- |
|
// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
|
////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
|
|
#include <boost/statechart/detail/state_base.hpp> |
|
|
|
#include <boost/intrusive_ptr.hpp> |
|
#include <boost/assert.hpp> // BOOST_ASSERT |
|
|
|
#include <algorithm> // std::find_if |
|
|
|
|
|
|
|
namespace boost |
|
{ |
|
namespace statechart |
|
{ |
|
namespace detail |
|
{ |
|
|
|
|
|
|
|
template< class Allocator, class RttiPolicy > |
|
class node_state_base : public state_base< Allocator, RttiPolicy > |
|
{ |
|
typedef state_base< Allocator, RttiPolicy > base_type; |
|
protected: |
|
////////////////////////////////////////////////////////////////////////// |
|
node_state_base( typename RttiPolicy::id_provider_type idProvider ) : |
|
base_type( idProvider ) |
|
{ |
|
} |
|
|
|
~node_state_base() {} |
|
|
|
public: |
|
////////////////////////////////////////////////////////////////////////// |
|
// The following declarations should be private. |
|
// They are only public because many compilers lack template friends. |
|
////////////////////////////////////////////////////////////////////////// |
|
typedef base_type state_base_type; |
|
typedef intrusive_ptr< node_state_base > direct_state_base_ptr_type; |
|
virtual void exit_impl( |
|
direct_state_base_ptr_type & pSelf, |
|
typename base_type::node_state_base_ptr_type & pOutermostUnstableState, |
|
bool performFullExit ) = 0; |
|
}; |
|
|
|
////////////////////////////////////////////////////////////////////////////// |
|
template< class OrthogonalRegionCount, class Allocator, class RttiPolicy > |
|
class node_state : public node_state_base< Allocator, RttiPolicy > |
|
{ |
|
typedef node_state_base< Allocator, RttiPolicy > base_type; |
|
protected: |
|
////////////////////////////////////////////////////////////////////////// |
|
node_state( typename RttiPolicy::id_provider_type idProvider ) : |
|
base_type( idProvider ) |
|
{ |
|
for ( orthogonal_position_type pos = 0; |
|
pos < OrthogonalRegionCount::value; ++pos ) |
|
{ |
|
pInnerStates[ pos ] = 0; |
|
} |
|
} |
|
|
|
~node_state() {} |
|
|
|
public: |
|
////////////////////////////////////////////////////////////////////////// |
|
// The following declarations should be private. |
|
// They are only public because many compilers lack template friends. |
|
////////////////////////////////////////////////////////////////////////// |
|
typedef typename base_type::state_base_type state_base_type; |
|
|
|
void add_inner_state( orthogonal_position_type position, |
|
state_base_type * pInnerState ) |
|
{ |
|
BOOST_ASSERT( ( position < OrthogonalRegionCount::value ) && |
|
( pInnerStates[ position ] == 0 ) ); |
|
pInnerStates[ position ] = pInnerState; |
|
} |
|
|
|
void remove_inner_state( orthogonal_position_type position ) |
|
{ |
|
BOOST_ASSERT( position < OrthogonalRegionCount::value ); |
|
pInnerStates[ position ] = 0; |
|
} |
|
|
|
virtual void remove_from_state_list( |
|
typename state_base_type::state_list_type::iterator & statesEnd, |
|
typename state_base_type::node_state_base_ptr_type & |
|
pOutermostUnstableState, |
|
bool performFullExit ) |
|
{ |
|
state_base_type ** const pPastEnd = |
|
&pInnerStates[ OrthogonalRegionCount::value ]; |
|
// We must not iterate past the last inner state because *this* state |
|
// will no longer exist when the last inner state has been removed |
|
state_base_type ** const pFirstNonNull = std::find_if( |
|
&pInnerStates[ 0 ], pPastEnd, &node_state::is_not_null ); |
|
|
|
if ( pFirstNonNull == pPastEnd ) |
|
{ |
|
// The state does not have inner states but is still alive, this must |
|
// be the outermost unstable state then. |
|
BOOST_ASSERT( get_pointer( pOutermostUnstableState ) == this ); |
|
typename state_base_type::node_state_base_ptr_type pSelf = |
|
pOutermostUnstableState; |
|
pSelf->exit_impl( pSelf, pOutermostUnstableState, performFullExit ); |
|
} |
|
else |
|
{ |
|
// Destroy inner states in the reverse order of construction |
|
for ( state_base_type ** pState = pPastEnd; pState != pFirstNonNull; ) |
|
{ |
|
--pState; |
|
|
|
// An inner orthogonal state might have been terminated long before, |
|
// that's why we have to check for 0 pointers |
|
if ( *pState != 0 ) |
|
{ |
|
( *pState )->remove_from_state_list( |
|
statesEnd, pOutermostUnstableState, performFullExit ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
typedef typename base_type::direct_state_base_ptr_type |
|
direct_state_base_ptr_type; |
|
|
|
private: |
|
////////////////////////////////////////////////////////////////////////// |
|
static bool is_not_null( const state_base_type * pInner ) |
|
{ |
|
return pInner != 0; |
|
} |
|
|
|
state_base_type * pInnerStates[ OrthogonalRegionCount::value ]; |
|
}; |
|
|
|
|
|
|
|
} // namespace detail |
|
} // namespace statechart |
|
} // namespace boost |
|
|
|
|
|
|
|
#endif
|
|
|