liuxiaolong
2021-07-20 58d904a328c0d849769b483e901a0be9426b8209
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#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