#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 |