Chris@16
|
1 #ifndef BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED
|
Chris@16
|
2 #define BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED
|
Chris@16
|
3 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
4 // Copyright 2002-2010 Andreas Huber Doenni
|
Chris@16
|
5 // Distributed under the Boost Software License, Version 1.0. (See accompany-
|
Chris@16
|
6 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
7 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
8
|
Chris@16
|
9
|
Chris@16
|
10
|
Chris@16
|
11 #include <boost/statechart/event.hpp>
|
Chris@16
|
12 #include <boost/statechart/null_exception_translator.hpp>
|
Chris@16
|
13 #include <boost/statechart/result.hpp>
|
Chris@16
|
14
|
Chris@16
|
15 #include <boost/statechart/detail/rtti_policy.hpp>
|
Chris@16
|
16 #include <boost/statechart/detail/state_base.hpp>
|
Chris@16
|
17 #include <boost/statechart/detail/leaf_state.hpp>
|
Chris@16
|
18 #include <boost/statechart/detail/node_state.hpp>
|
Chris@16
|
19 #include <boost/statechart/detail/constructor.hpp>
|
Chris@16
|
20 #include <boost/statechart/detail/avoid_unused_warning.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 #include <boost/mpl/list.hpp>
|
Chris@16
|
23 #include <boost/mpl/clear.hpp>
|
Chris@16
|
24 #include <boost/mpl/if.hpp>
|
Chris@16
|
25 #include <boost/mpl/at.hpp>
|
Chris@16
|
26 #include <boost/mpl/integral_c.hpp>
|
Chris@16
|
27 #include <boost/mpl/minus.hpp>
|
Chris@16
|
28 #include <boost/mpl/equal_to.hpp>
|
Chris@16
|
29
|
Chris@16
|
30 #include <boost/intrusive_ptr.hpp>
|
Chris@16
|
31 #include <boost/type_traits/is_pointer.hpp>
|
Chris@16
|
32 #include <boost/type_traits/remove_reference.hpp>
|
Chris@16
|
33 #include <boost/noncopyable.hpp>
|
Chris@16
|
34 #include <boost/assert.hpp>
|
Chris@16
|
35 #include <boost/static_assert.hpp>
|
Chris@101
|
36 #include <boost/polymorphic_cast.hpp> // boost::polymorphic_downcast
|
Chris@16
|
37 // BOOST_NO_EXCEPTIONS, BOOST_MSVC, BOOST_MSVC_STD_ITERATOR
|
Chris@16
|
38 #include <boost/config.hpp>
|
Chris@16
|
39
|
Chris@16
|
40 #include <boost/detail/allocator_utilities.hpp>
|
Chris@16
|
41
|
Chris@16
|
42 #ifdef BOOST_MSVC
|
Chris@16
|
43 # pragma warning( push )
|
Chris@16
|
44 # pragma warning( disable: 4702 ) // unreachable code (in release mode only)
|
Chris@16
|
45 #endif
|
Chris@16
|
46
|
Chris@16
|
47 #include <map>
|
Chris@16
|
48
|
Chris@16
|
49 #ifdef BOOST_MSVC
|
Chris@16
|
50 # pragma warning( pop )
|
Chris@16
|
51 #endif
|
Chris@16
|
52
|
Chris@16
|
53 #include <memory> // std::allocator
|
Chris@16
|
54 #include <typeinfo> // std::bad_cast
|
Chris@16
|
55 #include <functional> // std::less
|
Chris@16
|
56 #include <iterator>
|
Chris@16
|
57
|
Chris@16
|
58
|
Chris@16
|
59
|
Chris@16
|
60 namespace boost
|
Chris@16
|
61 {
|
Chris@16
|
62 namespace statechart
|
Chris@16
|
63 {
|
Chris@16
|
64 namespace detail
|
Chris@16
|
65 {
|
Chris@16
|
66
|
Chris@16
|
67
|
Chris@16
|
68
|
Chris@16
|
69 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
70 template< class StateBaseType, class EventBaseType, class IdType >
|
Chris@16
|
71 class send_function
|
Chris@16
|
72 {
|
Chris@16
|
73 public:
|
Chris@16
|
74 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
75 send_function(
|
Chris@16
|
76 StateBaseType & toState,
|
Chris@16
|
77 const EventBaseType & evt,
|
Chris@16
|
78 IdType eventType
|
Chris@16
|
79 ) :
|
Chris@16
|
80 toState_( toState ), evt_( evt ), eventType_( eventType )
|
Chris@16
|
81 {
|
Chris@16
|
82 }
|
Chris@16
|
83
|
Chris@16
|
84 result operator()()
|
Chris@16
|
85 {
|
Chris@16
|
86 return detail::result_utility::make_result(
|
Chris@16
|
87 toState_.react_impl( evt_, eventType_ ) );
|
Chris@16
|
88 }
|
Chris@16
|
89
|
Chris@16
|
90 private:
|
Chris@16
|
91 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
92 // avoids C4512 (assignment operator could not be generated)
|
Chris@16
|
93 send_function & operator=( const send_function & );
|
Chris@16
|
94
|
Chris@16
|
95 StateBaseType & toState_;
|
Chris@16
|
96 const EventBaseType & evt_;
|
Chris@16
|
97 IdType eventType_;
|
Chris@16
|
98 };
|
Chris@16
|
99
|
Chris@16
|
100
|
Chris@16
|
101 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
102 struct state_cast_impl_pointer_target
|
Chris@16
|
103 {
|
Chris@16
|
104 public:
|
Chris@16
|
105 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
106 template< class StateBaseType >
|
Chris@16
|
107 static const StateBaseType * deref_if_necessary(
|
Chris@16
|
108 const StateBaseType * pState )
|
Chris@16
|
109 {
|
Chris@16
|
110 return pState;
|
Chris@16
|
111 }
|
Chris@16
|
112
|
Chris@16
|
113 template< class Target, class IdType >
|
Chris@16
|
114 static IdType type_id()
|
Chris@16
|
115 {
|
Chris@16
|
116 Target p = 0;
|
Chris@16
|
117 return type_id_impl< IdType >( p );
|
Chris@16
|
118 }
|
Chris@16
|
119
|
Chris@16
|
120 static bool found( const void * pFound )
|
Chris@16
|
121 {
|
Chris@16
|
122 return pFound != 0;
|
Chris@16
|
123 }
|
Chris@16
|
124
|
Chris@16
|
125 template< class Target >
|
Chris@16
|
126 static Target not_found()
|
Chris@16
|
127 {
|
Chris@16
|
128 return 0;
|
Chris@16
|
129 }
|
Chris@16
|
130
|
Chris@16
|
131 private:
|
Chris@16
|
132 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
133 template< class IdType, class Type >
|
Chris@16
|
134 static IdType type_id_impl( const Type * )
|
Chris@16
|
135 {
|
Chris@16
|
136 return Type::static_type();
|
Chris@16
|
137 }
|
Chris@16
|
138 };
|
Chris@16
|
139
|
Chris@16
|
140 struct state_cast_impl_reference_target
|
Chris@16
|
141 {
|
Chris@16
|
142 template< class StateBaseType >
|
Chris@16
|
143 static const StateBaseType & deref_if_necessary(
|
Chris@16
|
144 const StateBaseType * pState )
|
Chris@16
|
145 {
|
Chris@16
|
146 return *pState;
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@16
|
149 template< class Target, class IdType >
|
Chris@16
|
150 static IdType type_id()
|
Chris@16
|
151 {
|
Chris@16
|
152 return remove_reference< Target >::type::static_type();
|
Chris@16
|
153 }
|
Chris@16
|
154
|
Chris@16
|
155 template< class Dummy >
|
Chris@16
|
156 static bool found( const Dummy & )
|
Chris@16
|
157 {
|
Chris@16
|
158 return true;
|
Chris@16
|
159 }
|
Chris@16
|
160
|
Chris@16
|
161 template< class Target >
|
Chris@16
|
162 static Target not_found()
|
Chris@16
|
163 {
|
Chris@16
|
164 throw std::bad_cast();
|
Chris@16
|
165 }
|
Chris@16
|
166 };
|
Chris@16
|
167
|
Chris@16
|
168 template< class Target >
|
Chris@16
|
169 struct state_cast_impl : public mpl::if_<
|
Chris@16
|
170 is_pointer< Target >,
|
Chris@16
|
171 state_cast_impl_pointer_target,
|
Chris@16
|
172 state_cast_impl_reference_target
|
Chris@16
|
173 >::type {};
|
Chris@16
|
174
|
Chris@16
|
175
|
Chris@16
|
176 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
177 template< class RttiPolicy >
|
Chris@16
|
178 class history_key
|
Chris@16
|
179 {
|
Chris@16
|
180 public:
|
Chris@16
|
181 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
182 template< class HistorizedState >
|
Chris@16
|
183 static history_key make_history_key()
|
Chris@16
|
184 {
|
Chris@16
|
185 return history_key(
|
Chris@16
|
186 HistorizedState::context_type::static_type(),
|
Chris@16
|
187 HistorizedState::orthogonal_position::value );
|
Chris@16
|
188 }
|
Chris@16
|
189
|
Chris@16
|
190 typename RttiPolicy::id_type history_context_type() const
|
Chris@16
|
191 {
|
Chris@16
|
192 return historyContextType_;
|
Chris@16
|
193 }
|
Chris@16
|
194
|
Chris@16
|
195 friend bool operator<(
|
Chris@16
|
196 const history_key & left, const history_key & right )
|
Chris@16
|
197 {
|
Chris@16
|
198 return
|
Chris@16
|
199 std::less< typename RttiPolicy::id_type >()(
|
Chris@16
|
200 left.historyContextType_, right.historyContextType_ ) ||
|
Chris@16
|
201 ( ( left.historyContextType_ == right.historyContextType_ ) &&
|
Chris@16
|
202 ( left.historizedOrthogonalRegion_ <
|
Chris@16
|
203 right.historizedOrthogonalRegion_ ) );
|
Chris@16
|
204 }
|
Chris@16
|
205
|
Chris@16
|
206 private:
|
Chris@16
|
207 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
208 history_key(
|
Chris@16
|
209 typename RttiPolicy::id_type historyContextType,
|
Chris@16
|
210 orthogonal_position_type historizedOrthogonalRegion
|
Chris@16
|
211 ) :
|
Chris@16
|
212 historyContextType_( historyContextType ),
|
Chris@16
|
213 historizedOrthogonalRegion_( historizedOrthogonalRegion )
|
Chris@16
|
214 {
|
Chris@16
|
215 }
|
Chris@16
|
216
|
Chris@16
|
217 // avoids C4512 (assignment operator could not be generated)
|
Chris@16
|
218 history_key & operator=( const history_key & );
|
Chris@16
|
219
|
Chris@16
|
220 const typename RttiPolicy::id_type historyContextType_;
|
Chris@16
|
221 const orthogonal_position_type historizedOrthogonalRegion_;
|
Chris@16
|
222 };
|
Chris@16
|
223
|
Chris@16
|
224
|
Chris@16
|
225
|
Chris@16
|
226 } // namespace detail
|
Chris@16
|
227
|
Chris@16
|
228
|
Chris@16
|
229
|
Chris@16
|
230 //////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
231 template< class MostDerived,
|
Chris@16
|
232 class InitialState,
|
Chris@16
|
233 class Allocator = std::allocator< void >,
|
Chris@16
|
234 class ExceptionTranslator = null_exception_translator >
|
Chris@16
|
235 class state_machine : noncopyable
|
Chris@16
|
236 {
|
Chris@16
|
237 public:
|
Chris@16
|
238 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
239 typedef Allocator allocator_type;
|
Chris@16
|
240 typedef detail::rtti_policy rtti_policy_type;
|
Chris@16
|
241 typedef event_base event_base_type;
|
Chris@16
|
242 typedef intrusive_ptr< const event_base_type > event_base_ptr_type;
|
Chris@16
|
243
|
Chris@16
|
244 void initiate()
|
Chris@16
|
245 {
|
Chris@16
|
246 terminate();
|
Chris@16
|
247
|
Chris@16
|
248 {
|
Chris@16
|
249 terminator guard( *this, 0 );
|
Chris@16
|
250 detail::result_utility::get_result( translator_(
|
Chris@16
|
251 initial_construct_function( *this ),
|
Chris@16
|
252 exception_event_handler( *this ) ) );
|
Chris@16
|
253 guard.dismiss();
|
Chris@16
|
254 }
|
Chris@16
|
255
|
Chris@16
|
256 process_queued_events();
|
Chris@16
|
257 }
|
Chris@16
|
258
|
Chris@16
|
259 void terminate()
|
Chris@16
|
260 {
|
Chris@16
|
261 terminator guard( *this, 0 );
|
Chris@16
|
262 detail::result_utility::get_result( translator_(
|
Chris@16
|
263 terminate_function( *this ),
|
Chris@16
|
264 exception_event_handler( *this ) ) );
|
Chris@16
|
265 guard.dismiss();
|
Chris@16
|
266 }
|
Chris@16
|
267
|
Chris@16
|
268 bool terminated() const
|
Chris@16
|
269 {
|
Chris@16
|
270 return pOutermostState_ == 0;
|
Chris@16
|
271 }
|
Chris@16
|
272
|
Chris@16
|
273 void process_event( const event_base_type & evt )
|
Chris@16
|
274 {
|
Chris@16
|
275 if ( send_event( evt ) == detail::do_defer_event )
|
Chris@16
|
276 {
|
Chris@16
|
277 deferredEventQueue_.push_back( evt.intrusive_from_this() );
|
Chris@16
|
278 }
|
Chris@16
|
279
|
Chris@16
|
280 process_queued_events();
|
Chris@16
|
281 }
|
Chris@16
|
282
|
Chris@16
|
283 template< class Target >
|
Chris@16
|
284 Target state_cast() const
|
Chris@16
|
285 {
|
Chris@16
|
286 typedef detail::state_cast_impl< Target > impl;
|
Chris@16
|
287
|
Chris@16
|
288 for ( typename state_list_type::const_iterator pCurrentLeafState =
|
Chris@16
|
289 currentStates_.begin();
|
Chris@16
|
290 pCurrentLeafState != currentStatesEnd_;
|
Chris@16
|
291 ++pCurrentLeafState )
|
Chris@16
|
292 {
|
Chris@16
|
293 const state_base_type * pCurrentState(
|
Chris@16
|
294 get_pointer( *pCurrentLeafState ) );
|
Chris@16
|
295
|
Chris@16
|
296 while ( pCurrentState != 0 )
|
Chris@16
|
297 {
|
Chris@16
|
298 // The unnecessary try/catch overhead for pointer targets is
|
Chris@16
|
299 // typically small compared to the cycles dynamic_cast needs
|
Chris@16
|
300 #ifndef BOOST_NO_EXCEPTIONS
|
Chris@16
|
301 try
|
Chris@16
|
302 #endif
|
Chris@16
|
303 {
|
Chris@16
|
304 Target result = dynamic_cast< Target >(
|
Chris@16
|
305 impl::deref_if_necessary( pCurrentState ) );
|
Chris@16
|
306
|
Chris@16
|
307 if ( impl::found( result ) )
|
Chris@16
|
308 {
|
Chris@16
|
309 return result;
|
Chris@16
|
310 }
|
Chris@16
|
311 }
|
Chris@16
|
312 #ifndef BOOST_NO_EXCEPTIONS
|
Chris@16
|
313 // Intentionally swallow std::bad_cast exceptions. We'll throw one
|
Chris@16
|
314 // ourselves when we fail to find a state that can be cast to Target
|
Chris@16
|
315 catch ( const std::bad_cast & ) {}
|
Chris@16
|
316 #endif
|
Chris@16
|
317
|
Chris@16
|
318 pCurrentState = pCurrentState->outer_state_ptr();
|
Chris@16
|
319 }
|
Chris@16
|
320 }
|
Chris@16
|
321
|
Chris@16
|
322 return impl::template not_found< Target >();
|
Chris@16
|
323 }
|
Chris@16
|
324
|
Chris@16
|
325 template< class Target >
|
Chris@16
|
326 Target state_downcast() const
|
Chris@16
|
327 {
|
Chris@16
|
328 typedef detail::state_cast_impl< Target > impl;
|
Chris@16
|
329
|
Chris@16
|
330 typename rtti_policy_type::id_type targetType =
|
Chris@16
|
331 impl::template type_id< Target, rtti_policy_type::id_type >();
|
Chris@16
|
332
|
Chris@16
|
333 for ( typename state_list_type::const_iterator pCurrentLeafState =
|
Chris@16
|
334 currentStates_.begin();
|
Chris@16
|
335 pCurrentLeafState != currentStatesEnd_;
|
Chris@16
|
336 ++pCurrentLeafState )
|
Chris@16
|
337 {
|
Chris@16
|
338 const state_base_type * pCurrentState(
|
Chris@16
|
339 get_pointer( *pCurrentLeafState ) );
|
Chris@16
|
340
|
Chris@16
|
341 while ( pCurrentState != 0 )
|
Chris@16
|
342 {
|
Chris@16
|
343 if ( pCurrentState->dynamic_type() == targetType )
|
Chris@16
|
344 {
|
Chris@16
|
345 return static_cast< Target >(
|
Chris@16
|
346 impl::deref_if_necessary( pCurrentState ) );
|
Chris@16
|
347 }
|
Chris@16
|
348
|
Chris@16
|
349 pCurrentState = pCurrentState->outer_state_ptr();
|
Chris@16
|
350 }
|
Chris@16
|
351 }
|
Chris@16
|
352
|
Chris@16
|
353 return impl::template not_found< Target >();
|
Chris@16
|
354 }
|
Chris@16
|
355
|
Chris@16
|
356 typedef detail::state_base< allocator_type, rtti_policy_type >
|
Chris@16
|
357 state_base_type;
|
Chris@16
|
358
|
Chris@16
|
359 class state_iterator : public std::iterator<
|
Chris@16
|
360 std::forward_iterator_tag,
|
Chris@16
|
361 state_base_type, std::ptrdiff_t
|
Chris@16
|
362 #ifndef BOOST_MSVC_STD_ITERATOR
|
Chris@16
|
363 , const state_base_type *, const state_base_type &
|
Chris@16
|
364 #endif
|
Chris@16
|
365 >
|
Chris@16
|
366 {
|
Chris@16
|
367 public:
|
Chris@16
|
368 //////////////////////////////////////////////////////////////////////
|
Chris@16
|
369 explicit state_iterator(
|
Chris@16
|
370 typename state_base_type::state_list_type::const_iterator
|
Chris@16
|
371 baseIterator
|
Chris@16
|
372 ) : baseIterator_( baseIterator ) {}
|
Chris@16
|
373
|
Chris@16
|
374 const state_base_type & operator*() const { return **baseIterator_; }
|
Chris@16
|
375 const state_base_type * operator->() const
|
Chris@16
|
376 {
|
Chris@16
|
377 return &**baseIterator_;
|
Chris@16
|
378 }
|
Chris@16
|
379
|
Chris@16
|
380 state_iterator & operator++() { ++baseIterator_; return *this; }
|
Chris@16
|
381 state_iterator operator++( int )
|
Chris@16
|
382 {
|
Chris@16
|
383 return state_iterator( baseIterator_++ );
|
Chris@16
|
384 }
|
Chris@16
|
385
|
Chris@16
|
386 bool operator==( const state_iterator & right ) const
|
Chris@16
|
387 {
|
Chris@16
|
388 return baseIterator_ == right.baseIterator_;
|
Chris@16
|
389 }
|
Chris@16
|
390 bool operator!=( const state_iterator & right ) const
|
Chris@16
|
391 {
|
Chris@16
|
392 return !( *this == right );
|
Chris@16
|
393 }
|
Chris@16
|
394
|
Chris@16
|
395 private:
|
Chris@16
|
396 typename state_base_type::state_list_type::const_iterator
|
Chris@16
|
397 baseIterator_;
|
Chris@16
|
398 };
|
Chris@16
|
399
|
Chris@16
|
400 state_iterator state_begin() const
|
Chris@16
|
401 {
|
Chris@16
|
402 return state_iterator( currentStates_.begin() );
|
Chris@16
|
403 }
|
Chris@16
|
404
|
Chris@16
|
405 state_iterator state_end() const
|
Chris@16
|
406 {
|
Chris@16
|
407 return state_iterator( currentStatesEnd_ );
|
Chris@16
|
408 }
|
Chris@16
|
409
|
Chris@16
|
410 void unconsumed_event( const event_base & ) {}
|
Chris@16
|
411
|
Chris@16
|
412 protected:
|
Chris@16
|
413 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
414 state_machine() :
|
Chris@16
|
415 currentStatesEnd_( currentStates_.end() ),
|
Chris@16
|
416 pOutermostState_( 0 ),
|
Chris@16
|
417 isInnermostCommonOuter_( false ),
|
Chris@16
|
418 performFullExit_( true ),
|
Chris@16
|
419 pTriggeringEvent_( 0 )
|
Chris@16
|
420 {
|
Chris@16
|
421 }
|
Chris@16
|
422
|
Chris@16
|
423 // This destructor was only made virtual so that that
|
Chris@16
|
424 // polymorphic_downcast can be used to cast to MostDerived.
|
Chris@16
|
425 virtual ~state_machine()
|
Chris@16
|
426 {
|
Chris@16
|
427 terminate_impl( false );
|
Chris@16
|
428 }
|
Chris@16
|
429
|
Chris@16
|
430 void post_event( const event_base_ptr_type & pEvent )
|
Chris@16
|
431 {
|
Chris@16
|
432 post_event_impl( pEvent );
|
Chris@16
|
433 }
|
Chris@16
|
434
|
Chris@16
|
435 void post_event( const event_base & evt )
|
Chris@16
|
436 {
|
Chris@16
|
437 post_event_impl( evt );
|
Chris@16
|
438 }
|
Chris@16
|
439
|
Chris@16
|
440 public:
|
Chris@16
|
441 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
442 // The following declarations should be protected.
|
Chris@16
|
443 // They are only public because many compilers lack template friends.
|
Chris@16
|
444 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
445 template<
|
Chris@16
|
446 class HistoryContext,
|
Chris@16
|
447 detail::orthogonal_position_type orthogonalPosition >
|
Chris@16
|
448 void clear_shallow_history()
|
Chris@16
|
449 {
|
Chris@16
|
450 // If you receive a
|
Chris@16
|
451 // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or
|
Chris@16
|
452 // similar compiler error here then you tried to clear shallow history
|
Chris@16
|
453 // for a state that does not have shallow history. That is, the state
|
Chris@16
|
454 // does not pass either statechart::has_shallow_history or
|
Chris@16
|
455 // statechart::has_full_history to its base class template.
|
Chris@16
|
456 BOOST_STATIC_ASSERT( HistoryContext::shallow_history::value );
|
Chris@16
|
457
|
Chris@16
|
458 typedef typename mpl::at_c<
|
Chris@16
|
459 typename HistoryContext::inner_initial_list,
|
Chris@16
|
460 orthogonalPosition >::type historized_state;
|
Chris@16
|
461
|
Chris@16
|
462 store_history_impl(
|
Chris@16
|
463 shallowHistoryMap_,
|
Chris@16
|
464 history_key_type::make_history_key< historized_state >(),
|
Chris@16
|
465 0 );
|
Chris@16
|
466 }
|
Chris@16
|
467
|
Chris@16
|
468 template<
|
Chris@16
|
469 class HistoryContext,
|
Chris@16
|
470 detail::orthogonal_position_type orthogonalPosition >
|
Chris@16
|
471 void clear_deep_history()
|
Chris@16
|
472 {
|
Chris@16
|
473 // If you receive a
|
Chris@16
|
474 // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or
|
Chris@16
|
475 // similar compiler error here then you tried to clear deep history for
|
Chris@16
|
476 // a state that does not have deep history. That is, the state does not
|
Chris@16
|
477 // pass either statechart::has_deep_history or
|
Chris@16
|
478 // statechart::has_full_history to its base class template
|
Chris@16
|
479 BOOST_STATIC_ASSERT( HistoryContext::deep_history::value );
|
Chris@16
|
480
|
Chris@16
|
481 typedef typename mpl::at_c<
|
Chris@16
|
482 typename HistoryContext::inner_initial_list,
|
Chris@16
|
483 orthogonalPosition >::type historized_state;
|
Chris@16
|
484
|
Chris@16
|
485 store_history_impl(
|
Chris@16
|
486 deepHistoryMap_,
|
Chris@16
|
487 history_key_type::make_history_key< historized_state >(),
|
Chris@16
|
488 0 );
|
Chris@16
|
489 }
|
Chris@16
|
490
|
Chris@16
|
491 const event_base_type * triggering_event() const
|
Chris@16
|
492 {
|
Chris@16
|
493 return pTriggeringEvent_;
|
Chris@16
|
494 }
|
Chris@16
|
495
|
Chris@16
|
496 public:
|
Chris@16
|
497 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
498 // The following declarations should be private.
|
Chris@16
|
499 // They are only public because many compilers lack template friends.
|
Chris@16
|
500 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
501 typedef MostDerived inner_context_type;
|
Chris@16
|
502 typedef mpl::integral_c< detail::orthogonal_position_type, 0 >
|
Chris@16
|
503 inner_orthogonal_position;
|
Chris@16
|
504 typedef mpl::integral_c< detail::orthogonal_position_type, 1 >
|
Chris@16
|
505 no_of_orthogonal_regions;
|
Chris@16
|
506
|
Chris@16
|
507 typedef MostDerived outermost_context_type;
|
Chris@16
|
508 typedef state_machine outermost_context_base_type;
|
Chris@16
|
509 typedef state_machine * inner_context_ptr_type;
|
Chris@16
|
510 typedef typename state_base_type::node_state_base_ptr_type
|
Chris@16
|
511 node_state_base_ptr_type;
|
Chris@16
|
512 typedef typename state_base_type::leaf_state_ptr_type leaf_state_ptr_type;
|
Chris@16
|
513 typedef typename state_base_type::state_list_type state_list_type;
|
Chris@16
|
514
|
Chris@16
|
515 typedef mpl::clear< mpl::list<> >::type context_type_list;
|
Chris@16
|
516
|
Chris@16
|
517 typedef mpl::bool_< false > shallow_history;
|
Chris@16
|
518 typedef mpl::bool_< false > deep_history;
|
Chris@16
|
519 typedef mpl::bool_< false > inherited_deep_history;
|
Chris@16
|
520
|
Chris@16
|
521 void post_event_impl( const event_base_ptr_type & pEvent )
|
Chris@16
|
522 {
|
Chris@16
|
523 BOOST_ASSERT( get_pointer( pEvent ) != 0 );
|
Chris@16
|
524 eventQueue_.push_back( pEvent );
|
Chris@16
|
525 }
|
Chris@16
|
526
|
Chris@16
|
527 void post_event_impl( const event_base & evt )
|
Chris@16
|
528 {
|
Chris@16
|
529 post_event_impl( evt.intrusive_from_this() );
|
Chris@16
|
530 }
|
Chris@16
|
531
|
Chris@16
|
532 detail::reaction_result react_impl(
|
Chris@16
|
533 const event_base_type &,
|
Chris@16
|
534 typename rtti_policy_type::id_type )
|
Chris@16
|
535 {
|
Chris@16
|
536 return detail::do_forward_event;
|
Chris@16
|
537 }
|
Chris@16
|
538
|
Chris@16
|
539 void exit_impl(
|
Chris@16
|
540 inner_context_ptr_type &,
|
Chris@16
|
541 typename state_base_type::node_state_base_ptr_type &,
|
Chris@16
|
542 bool ) {}
|
Chris@16
|
543
|
Chris@16
|
544 void set_outermost_unstable_state(
|
Chris@16
|
545 typename state_base_type::node_state_base_ptr_type &
|
Chris@16
|
546 pOutermostUnstableState )
|
Chris@16
|
547 {
|
Chris@16
|
548 pOutermostUnstableState = 0;
|
Chris@16
|
549 }
|
Chris@16
|
550
|
Chris@16
|
551 // Returns a reference to the context identified by the template
|
Chris@16
|
552 // parameter. This can either be _this_ object or one of its direct or
|
Chris@16
|
553 // indirect contexts.
|
Chris@16
|
554 template< class Context >
|
Chris@16
|
555 Context & context()
|
Chris@16
|
556 {
|
Chris@16
|
557 // As we are in the outermost context here, only this object can be
|
Chris@16
|
558 // returned.
|
Chris@16
|
559 return *polymorphic_downcast< MostDerived * >( this );
|
Chris@16
|
560 }
|
Chris@16
|
561
|
Chris@16
|
562 template< class Context >
|
Chris@16
|
563 const Context & context() const
|
Chris@16
|
564 {
|
Chris@16
|
565 // As we are in the outermost context here, only this object can be
|
Chris@16
|
566 // returned.
|
Chris@16
|
567 return *polymorphic_downcast< const MostDerived * >( this );
|
Chris@16
|
568 }
|
Chris@16
|
569
|
Chris@16
|
570 outermost_context_type & outermost_context()
|
Chris@16
|
571 {
|
Chris@16
|
572 return *polymorphic_downcast< MostDerived * >( this );
|
Chris@16
|
573 }
|
Chris@16
|
574
|
Chris@16
|
575 const outermost_context_type & outermost_context() const
|
Chris@16
|
576 {
|
Chris@16
|
577 return *polymorphic_downcast< const MostDerived * >( this );
|
Chris@16
|
578 }
|
Chris@16
|
579
|
Chris@16
|
580 outermost_context_base_type & outermost_context_base()
|
Chris@16
|
581 {
|
Chris@16
|
582 return *this;
|
Chris@16
|
583 }
|
Chris@16
|
584
|
Chris@16
|
585 const outermost_context_base_type & outermost_context_base() const
|
Chris@16
|
586 {
|
Chris@16
|
587 return *this;
|
Chris@16
|
588 }
|
Chris@16
|
589
|
Chris@16
|
590 void terminate_as_reaction( state_base_type & theState )
|
Chris@16
|
591 {
|
Chris@16
|
592 terminate_impl( theState, performFullExit_ );
|
Chris@16
|
593 pOutermostUnstableState_ = 0;
|
Chris@16
|
594 }
|
Chris@16
|
595
|
Chris@16
|
596 void terminate_as_part_of_transit( state_base_type & theState )
|
Chris@16
|
597 {
|
Chris@16
|
598 terminate_impl( theState, performFullExit_ );
|
Chris@16
|
599 isInnermostCommonOuter_ = true;
|
Chris@16
|
600 }
|
Chris@16
|
601
|
Chris@16
|
602 void terminate_as_part_of_transit( state_machine & )
|
Chris@16
|
603 {
|
Chris@16
|
604 terminate_impl( *pOutermostState_, performFullExit_ );
|
Chris@16
|
605 isInnermostCommonOuter_ = true;
|
Chris@16
|
606 }
|
Chris@16
|
607
|
Chris@16
|
608
|
Chris@16
|
609 template< class State >
|
Chris@16
|
610 void add( const intrusive_ptr< State > & pState )
|
Chris@16
|
611 {
|
Chris@16
|
612 // The second dummy argument is necessary because the call to the
|
Chris@16
|
613 // overloaded function add_impl would otherwise be ambiguous.
|
Chris@16
|
614 node_state_base_ptr_type pNewOutermostUnstableStateCandidate =
|
Chris@16
|
615 add_impl( pState, *pState );
|
Chris@16
|
616
|
Chris@16
|
617 if ( isInnermostCommonOuter_ ||
|
Chris@16
|
618 ( is_in_highest_orthogonal_region< State >() &&
|
Chris@16
|
619 ( get_pointer( pOutermostUnstableState_ ) ==
|
Chris@16
|
620 pState->State::outer_state_ptr() ) ) )
|
Chris@16
|
621 {
|
Chris@16
|
622 isInnermostCommonOuter_ = false;
|
Chris@16
|
623 pOutermostUnstableState_ = pNewOutermostUnstableStateCandidate;
|
Chris@16
|
624 }
|
Chris@16
|
625 }
|
Chris@16
|
626
|
Chris@16
|
627
|
Chris@16
|
628 void add_inner_state(
|
Chris@16
|
629 detail::orthogonal_position_type position,
|
Chris@16
|
630 state_base_type * pOutermostState )
|
Chris@16
|
631 {
|
Chris@16
|
632 BOOST_ASSERT( position == 0 );
|
Chris@16
|
633 detail::avoid_unused_warning( position );
|
Chris@16
|
634 pOutermostState_ = pOutermostState;
|
Chris@16
|
635 }
|
Chris@16
|
636
|
Chris@16
|
637 void remove_inner_state( detail::orthogonal_position_type position )
|
Chris@16
|
638 {
|
Chris@16
|
639 BOOST_ASSERT( position == 0 );
|
Chris@16
|
640 detail::avoid_unused_warning( position );
|
Chris@16
|
641 pOutermostState_ = 0;
|
Chris@16
|
642 }
|
Chris@16
|
643
|
Chris@16
|
644
|
Chris@16
|
645 void release_events()
|
Chris@16
|
646 {
|
Chris@16
|
647 eventQueue_.splice( eventQueue_.begin(), deferredEventQueue_ );
|
Chris@16
|
648 }
|
Chris@16
|
649
|
Chris@16
|
650
|
Chris@16
|
651 template< class HistorizedState >
|
Chris@16
|
652 void store_shallow_history()
|
Chris@16
|
653 {
|
Chris@16
|
654 // 5.2.10.6 declares that reinterpret_casting a function pointer to a
|
Chris@16
|
655 // different function pointer and back must yield the same value. The
|
Chris@16
|
656 // following reinterpret_cast is the first half of such a sequence.
|
Chris@16
|
657 store_history_impl(
|
Chris@16
|
658 shallowHistoryMap_,
|
Chris@16
|
659 history_key_type::make_history_key< HistorizedState >(),
|
Chris@16
|
660 reinterpret_cast< void (*)() >( &HistorizedState::deep_construct ) );
|
Chris@16
|
661 }
|
Chris@16
|
662
|
Chris@16
|
663 template< class DefaultState >
|
Chris@16
|
664 void construct_with_shallow_history(
|
Chris@16
|
665 const typename DefaultState::context_ptr_type & pContext )
|
Chris@16
|
666 {
|
Chris@16
|
667 construct_with_history_impl< DefaultState >(
|
Chris@16
|
668 shallowHistoryMap_, pContext );
|
Chris@16
|
669 }
|
Chris@16
|
670
|
Chris@16
|
671
|
Chris@16
|
672 template< class HistorizedState, class LeafState >
|
Chris@16
|
673 void store_deep_history()
|
Chris@16
|
674 {
|
Chris@16
|
675 typedef typename detail::make_context_list<
|
Chris@16
|
676 typename HistorizedState::context_type,
|
Chris@16
|
677 LeafState >::type history_context_list;
|
Chris@16
|
678 typedef detail::constructor<
|
Chris@16
|
679 history_context_list, outermost_context_base_type > constructor_type;
|
Chris@16
|
680 // 5.2.10.6 declares that reinterpret_casting a function pointer to a
|
Chris@16
|
681 // different function pointer and back must yield the same value. The
|
Chris@16
|
682 // following reinterpret_cast is the first half of such a sequence.
|
Chris@16
|
683 store_history_impl(
|
Chris@16
|
684 deepHistoryMap_,
|
Chris@16
|
685 history_key_type::make_history_key< HistorizedState >(),
|
Chris@16
|
686 reinterpret_cast< void (*)() >( &constructor_type::construct ) );
|
Chris@16
|
687 }
|
Chris@16
|
688
|
Chris@16
|
689 template< class DefaultState >
|
Chris@16
|
690 void construct_with_deep_history(
|
Chris@16
|
691 const typename DefaultState::context_ptr_type & pContext )
|
Chris@16
|
692 {
|
Chris@16
|
693 construct_with_history_impl< DefaultState >(
|
Chris@16
|
694 deepHistoryMap_, pContext );
|
Chris@16
|
695 }
|
Chris@16
|
696
|
Chris@16
|
697 private: // implementation
|
Chris@16
|
698 //////////////////////////////////////////////////////////////////////////
|
Chris@16
|
699 void initial_construct()
|
Chris@16
|
700 {
|
Chris@16
|
701 InitialState::initial_deep_construct(
|
Chris@16
|
702 *polymorphic_downcast< MostDerived * >( this ) );
|
Chris@16
|
703 }
|
Chris@16
|
704
|
Chris@16
|
705 class initial_construct_function
|
Chris@16
|
706 {
|
Chris@16
|
707 public:
|
Chris@16
|
708 //////////////////////////////////////////////////////////////////////
|
Chris@16
|
709 initial_construct_function( state_machine & machine ) :
|
Chris@16
|
710 machine_( machine )
|
Chris@16
|
711 {
|
Chris@16
|
712 }
|
Chris@16
|
713
|
Chris@16
|
714 result operator()()
|
Chris@16
|
715 {
|
Chris@16
|
716 machine_.initial_construct();
|
Chris@16
|
717 return detail::result_utility::make_result(
|
Chris@16
|
718 detail::do_discard_event ); // there is nothing to be consumed
|
Chris@16
|
719 }
|
Chris@16
|
720
|
Chris@16
|
721 private:
|
Chris@16
|
722 //////////////////////////////////////////////////////////////////////
|
Chris@16
|
723 // avoids C4512 (assignment operator could not be generated)
|
Chris@16
|
724 initial_construct_function & operator=(
|
Chris@16
|
725 const initial_construct_function & );
|
Chris@16
|
726
|
Chris@16
|
727 state_machine & machine_;
|
Chris@16
|
728 };
|
Chris@16
|
729 friend class initial_construct_function;
|
Chris@16
|
730
|
Chris@16
|
731 class terminate_function
|
Chris@16
|
732 {
|
Chris@16
|
733 public:
|
Chris@16
|
734 //////////////////////////////////////////////////////////////////////
|
Chris@16
|
735 terminate_function( state_machine & machine ) : machine_( machine ) {}
|
Chris@16
|
736
|
Chris@16
|
737 result operator()()
|
Chris@16
|
738 {
|
Chris@16
|
739 machine_.terminate_impl( true );
|
Chris@16
|
740 return detail::result_utility::make_result(
|
Chris@16
|
741 detail::do_discard_event ); // there is nothing to be consumed
|
Chris@16
|
742 }
|
Chris@16
|
743
|
Chris@16
|
744 private:
|
Chris@16
|
745 //////////////////////////////////////////////////////////////////////
|
Chris@16
|
746 // avoids C4512 (assignment operator could not be generated)
|
Chris@16
|
747 terminate_function & operator=( const terminate_function & );
|
Chris@16
|
748
|
Chris@16
|
749 state_machine & machine_;
|
Chris@16
|
750 };
|
Chris@16
|
751 friend class terminate_function;
|
Chris@16
|
752
|
Chris@16
|
753 template< class ExceptionEvent >
|
Chris@16
|
754 detail::reaction_result handle_exception_event(
|
Chris@16
|
755 const ExceptionEvent & exceptionEvent,
|
Chris@16
|
756 state_base_type * pCurrentState )
|
Chris@16
|
757 {
|
Chris@16
|
758 if ( terminated() )
|
Chris@16
|
759 {
|
Chris@16
|
760 // there is no state that could handle the exception -> bail out
|
Chris@16
|
761 throw;
|
Chris@16
|
762 }
|
Chris@16
|
763
|
Chris@16
|
764 // If we are stable, an event handler has thrown.
|
Chris@16
|
765 // Otherwise, either a state constructor, a transition action or an exit
|
Chris@16
|
766 // function has thrown and the state machine is now in an invalid state.
|
Chris@16
|
767 // This situation can be resolved by the exception event handler
|
Chris@16
|
768 // function by orderly transiting to another state or terminating.
|
Chris@16
|
769 // As a result of this, the machine must not be unstable when this
|
Chris@16
|
770 // function is left.
|
Chris@16
|
771 state_base_type * const pOutermostUnstableState =
|
Chris@16
|
772 get_pointer( pOutermostUnstableState_ );
|
Chris@16
|
773 state_base_type * const pHandlingState = pOutermostUnstableState == 0 ?
|
Chris@16
|
774 pCurrentState : pOutermostUnstableState;
|
Chris@16
|
775
|
Chris@16
|
776 BOOST_ASSERT( pHandlingState != 0 );
|
Chris@16
|
777 terminator guard( *this, &exceptionEvent );
|
Chris@16
|
778 // There is another scope guard up the call stack, which will terminate
|
Chris@16
|
779 // the machine. So this guard only sets the triggering event.
|
Chris@16
|
780 guard.dismiss();
|
Chris@16
|
781
|
Chris@16
|
782 // Setting a member variable to a special value for the duration of a
|
Chris@16
|
783 // call surely looks like a kludge (normally it should be a parameter of
|
Chris@16
|
784 // the call). However, in this case it is unavoidable because the call
|
Chris@16
|
785 // below could result in a call to user code where passing through an
|
Chris@16
|
786 // additional bool parameter is not acceptable.
|
Chris@16
|
787 performFullExit_ = false;
|
Chris@16
|
788 const detail::reaction_result reactionResult = pHandlingState->react_impl(
|
Chris@16
|
789 exceptionEvent, exceptionEvent.dynamic_type() );
|
Chris@16
|
790 // If the above call throws then performFullExit_ will obviously not be
|
Chris@16
|
791 // set back to true. In this case the termination triggered by the
|
Chris@16
|
792 // scope guard further up in the call stack will take care of this.
|
Chris@16
|
793 performFullExit_ = true;
|
Chris@16
|
794
|
Chris@16
|
795 if ( ( reactionResult != detail::do_discard_event ) ||
|
Chris@16
|
796 ( get_pointer( pOutermostUnstableState_ ) != 0 ) )
|
Chris@16
|
797 {
|
Chris@16
|
798 throw;
|
Chris@16
|
799 }
|
Chris@16
|
800
|
Chris@16
|
801 return detail::do_discard_event;
|
Chris@16
|
802 }
|
Chris@16
|
803
|
Chris@16
|
804 class exception_event_handler
|
Chris@16
|
805 {
|
Chris@16
|
806 public:
|
Chris@16
|
807 //////////////////////////////////////////////////////////////////////
|
Chris@16
|
808 exception_event_handler(
|
Chris@16
|
809 state_machine & machine,
|
Chris@16
|
810 state_base_type * pCurrentState = 0
|
Chris@16
|
811 ) :
|
Chris@16
|
812 machine_( machine ),
|
Chris@16
|
813 pCurrentState_( pCurrentState )
|
Chris@16
|
814 {
|
Chris@16
|
815 }
|
Chris@16
|
816
|
Chris@16
|
817 template< class ExceptionEvent >
|
Chris@16
|
818 result operator()(
|
Chris@16
|
819 const ExceptionEvent & exceptionEvent )
|
Chris@16
|
820 {
|
Chris@16
|
821 return detail::result_utility::make_result(
|
Chris@16
|
822 machine_.handle_exception_event(
|
Chris@16
|
823 exceptionEvent, pCurrentState_ ) );
|
Chris@16
|
824 }
|
Chris@16
|
825
|
Chris@16
|
826 private:
|
Chris@16
|
827 //////////////////////////////////////////////////////////////////////
|
Chris@16
|
828 // avoids C4512 (assignment operator could not be generated)
|
Chris@16
|
829 exception_event_handler & operator=(
|
Chris@16
|
830 const exception_event_handler & );
|
Chris@16
|
831
|
Chris@16
|
832 state_machine & machine_;
|
Chris@16
|
833 state_base_type * pCurrentState_;
|
Chris@16
|
834 };
|
Chris@16
|
835 friend class exception_event_handler;
|
Chris@16
|
836
|
Chris@16
|
837 class terminator
|
Chris@16
|
838 {
|
Chris@16
|
839 public:
|
Chris@16
|
840 //////////////////////////////////////////////////////////////////////
|
Chris@16
|
841 terminator(
|
Chris@16
|
842 state_machine & machine, const event_base * pNewTriggeringEvent ) :
|
Chris@16
|
843 machine_( machine ),
|
Chris@16
|
844 pOldTriggeringEvent_(machine_.pTriggeringEvent_),
|
Chris@16
|
845 dismissed_( false )
|
Chris@16
|
846 {
|
Chris@16
|
847 machine_.pTriggeringEvent_ = pNewTriggeringEvent;
|
Chris@16
|
848 }
|
Chris@16
|
849
|
Chris@16
|
850 ~terminator()
|
Chris@16
|
851 {
|
Chris@16
|
852 if ( !dismissed_ ) { machine_.terminate_impl( false ); }
|
Chris@16
|
853 machine_.pTriggeringEvent_ = pOldTriggeringEvent_;
|
Chris@16
|
854 }
|
Chris@16
|
855
|
Chris@16
|
856 void dismiss() { dismissed_ = true; }
|
Chris@16
|
857
|
Chris@16
|
858 private:
|
Chris@16
|
859 //////////////////////////////////////////////////////////////////////
|
Chris@16
|
860 // avoids C4512 (assignment operator could not be generated)
|
Chris@16
|
861 terminator & operator=( const terminator & );
|
Chris@16
|
862
|
Chris@16
|
863 state_machine & machine_;
|
Chris@16
|
864 const event_base_type * const pOldTriggeringEvent_;
|
Chris@16
|
865 bool dismissed_;
|
Chris@16
|
866 };
|
Chris@16
|
867 friend class terminator;
|
Chris@16
|
868
|
Chris@16
|
869
|
Chris@16
|
870 detail::reaction_result send_event( const event_base_type & evt )
|
Chris@16
|
871 {
|
Chris@16
|
872 terminator guard( *this, &evt );
|
Chris@16
|
873 BOOST_ASSERT( get_pointer( pOutermostUnstableState_ ) == 0 );
|
Chris@16
|
874 const typename rtti_policy_type::id_type eventType = evt.dynamic_type();
|
Chris@16
|
875 detail::reaction_result reactionResult = detail::do_forward_event;
|
Chris@16
|
876
|
Chris@16
|
877 for (
|
Chris@16
|
878 typename state_list_type::iterator pState = currentStates_.begin();
|
Chris@16
|
879 ( reactionResult == detail::do_forward_event ) &&
|
Chris@16
|
880 ( pState != currentStatesEnd_ );
|
Chris@16
|
881 ++pState )
|
Chris@16
|
882 {
|
Chris@16
|
883 // CAUTION: The following statement could modify our state list!
|
Chris@16
|
884 // We must not continue iterating if the event was consumed
|
Chris@16
|
885 reactionResult = detail::result_utility::get_result( translator_(
|
Chris@16
|
886 detail::send_function<
|
Chris@16
|
887 state_base_type, event_base_type, rtti_policy_type::id_type >(
|
Chris@16
|
888 **pState, evt, eventType ),
|
Chris@16
|
889 exception_event_handler( *this, get_pointer( *pState ) ) ) );
|
Chris@16
|
890 }
|
Chris@16
|
891
|
Chris@16
|
892 guard.dismiss();
|
Chris@16
|
893
|
Chris@16
|
894 if ( reactionResult == detail::do_forward_event )
|
Chris@16
|
895 {
|
Chris@16
|
896 polymorphic_downcast< MostDerived * >( this )->unconsumed_event( evt );
|
Chris@16
|
897 }
|
Chris@16
|
898
|
Chris@16
|
899 return reactionResult;
|
Chris@16
|
900 }
|
Chris@16
|
901
|
Chris@16
|
902
|
Chris@16
|
903 void process_queued_events()
|
Chris@16
|
904 {
|
Chris@16
|
905 while ( !eventQueue_.empty() )
|
Chris@16
|
906 {
|
Chris@16
|
907 event_base_ptr_type pEvent = eventQueue_.front();
|
Chris@16
|
908 eventQueue_.pop_front();
|
Chris@16
|
909
|
Chris@16
|
910 if ( send_event( *pEvent ) == detail::do_defer_event )
|
Chris@16
|
911 {
|
Chris@16
|
912 deferredEventQueue_.push_back( pEvent );
|
Chris@16
|
913 }
|
Chris@16
|
914 }
|
Chris@16
|
915 }
|
Chris@16
|
916
|
Chris@16
|
917
|
Chris@16
|
918 void terminate_impl( bool performFullExit )
|
Chris@16
|
919 {
|
Chris@16
|
920 performFullExit_ = true;
|
Chris@16
|
921
|
Chris@16
|
922 if ( !terminated() )
|
Chris@16
|
923 {
|
Chris@16
|
924 terminate_impl( *pOutermostState_, performFullExit );
|
Chris@16
|
925 }
|
Chris@16
|
926
|
Chris@16
|
927 eventQueue_.clear();
|
Chris@16
|
928 deferredEventQueue_.clear();
|
Chris@16
|
929 shallowHistoryMap_.clear();
|
Chris@16
|
930 deepHistoryMap_.clear();
|
Chris@16
|
931 }
|
Chris@16
|
932
|
Chris@16
|
933 void terminate_impl( state_base_type & theState, bool performFullExit )
|
Chris@16
|
934 {
|
Chris@16
|
935 isInnermostCommonOuter_ = false;
|
Chris@16
|
936
|
Chris@16
|
937 // If pOutermostUnstableState_ == 0, we know for sure that
|
Chris@16
|
938 // currentStates_.size() > 0, otherwise theState couldn't be alive any
|
Chris@16
|
939 // more
|
Chris@16
|
940 if ( get_pointer( pOutermostUnstableState_ ) != 0 )
|
Chris@16
|
941 {
|
Chris@16
|
942 theState.remove_from_state_list(
|
Chris@16
|
943 currentStatesEnd_, pOutermostUnstableState_, performFullExit );
|
Chris@16
|
944 }
|
Chris@16
|
945 // Optimization: We want to find out whether currentStates_ has size 1
|
Chris@16
|
946 // and if yes use the optimized implementation below. Since
|
Chris@16
|
947 // list<>::size() is implemented quite inefficiently in some std libs
|
Chris@16
|
948 // it is best to just decrement the currentStatesEnd_ here and
|
Chris@16
|
949 // increment it again, if the test failed.
|
Chris@16
|
950 else if ( currentStates_.begin() == --currentStatesEnd_ )
|
Chris@16
|
951 {
|
Chris@16
|
952 // The machine is stable and there is exactly one innermost state.
|
Chris@16
|
953 // The following optimization is only correct for a stable machine
|
Chris@16
|
954 // without orthogonal regions.
|
Chris@16
|
955 leaf_state_ptr_type & pState = *currentStatesEnd_;
|
Chris@16
|
956 pState->exit_impl(
|
Chris@16
|
957 pState, pOutermostUnstableState_, performFullExit );
|
Chris@16
|
958 }
|
Chris@16
|
959 else
|
Chris@16
|
960 {
|
Chris@16
|
961 BOOST_ASSERT( currentStates_.size() > 1 );
|
Chris@16
|
962 // The machine is stable and there are multiple innermost states
|
Chris@16
|
963 theState.remove_from_state_list(
|
Chris@16
|
964 ++currentStatesEnd_, pOutermostUnstableState_, performFullExit );
|
Chris@16
|
965 }
|
Chris@16
|
966 }
|
Chris@16
|
967
|
Chris@16
|
968
|
Chris@16
|
969 node_state_base_ptr_type add_impl(
|
Chris@16
|
970 const leaf_state_ptr_type & pState,
|
Chris@16
|
971 detail::leaf_state< allocator_type, rtti_policy_type > & )
|
Chris@16
|
972 {
|
Chris@16
|
973 if ( currentStatesEnd_ == currentStates_.end() )
|
Chris@16
|
974 {
|
Chris@16
|
975 pState->set_list_position(
|
Chris@16
|
976 currentStates_.insert( currentStatesEnd_, pState ) );
|
Chris@16
|
977 }
|
Chris@16
|
978 else
|
Chris@16
|
979 {
|
Chris@16
|
980 *currentStatesEnd_ = pState;
|
Chris@16
|
981 pState->set_list_position( currentStatesEnd_ );
|
Chris@16
|
982 ++currentStatesEnd_;
|
Chris@16
|
983 }
|
Chris@16
|
984
|
Chris@16
|
985 return 0;
|
Chris@16
|
986 }
|
Chris@16
|
987
|
Chris@16
|
988 node_state_base_ptr_type add_impl(
|
Chris@16
|
989 const node_state_base_ptr_type & pState,
|
Chris@16
|
990 state_base_type & )
|
Chris@16
|
991 {
|
Chris@16
|
992 return pState;
|
Chris@16
|
993 }
|
Chris@16
|
994
|
Chris@16
|
995 template< class State >
|
Chris@16
|
996 static bool is_in_highest_orthogonal_region()
|
Chris@16
|
997 {
|
Chris@16
|
998 return mpl::equal_to<
|
Chris@16
|
999 typename State::orthogonal_position,
|
Chris@16
|
1000 mpl::minus<
|
Chris@16
|
1001 typename State::context_type::no_of_orthogonal_regions,
|
Chris@16
|
1002 mpl::integral_c< detail::orthogonal_position_type, 1 > >
|
Chris@16
|
1003 >::value;
|
Chris@16
|
1004 }
|
Chris@16
|
1005
|
Chris@16
|
1006
|
Chris@16
|
1007 typedef detail::history_key< rtti_policy_type > history_key_type;
|
Chris@16
|
1008
|
Chris@16
|
1009 typedef std::map<
|
Chris@16
|
1010 history_key_type, void (*)(),
|
Chris@16
|
1011 std::less< history_key_type >,
|
Chris@16
|
1012 typename boost::detail::allocator::rebind_to<
|
Chris@16
|
1013 allocator_type, std::pair< const history_key_type, void (*)() >
|
Chris@16
|
1014 >::type
|
Chris@16
|
1015 > history_map_type;
|
Chris@16
|
1016
|
Chris@16
|
1017 void store_history_impl(
|
Chris@16
|
1018 history_map_type & historyMap,
|
Chris@16
|
1019 const history_key_type & historyId,
|
Chris@16
|
1020 void (*pConstructFunction)() )
|
Chris@16
|
1021 {
|
Chris@16
|
1022 historyMap[ historyId ] = pConstructFunction;
|
Chris@16
|
1023 }
|
Chris@16
|
1024
|
Chris@16
|
1025 template< class DefaultState >
|
Chris@16
|
1026 void construct_with_history_impl(
|
Chris@16
|
1027 history_map_type & historyMap,
|
Chris@16
|
1028 const typename DefaultState::context_ptr_type & pContext )
|
Chris@16
|
1029 {
|
Chris@16
|
1030 typename history_map_type::iterator pFoundSlot = historyMap.find(
|
Chris@16
|
1031 history_key_type::make_history_key< DefaultState >() );
|
Chris@16
|
1032
|
Chris@16
|
1033 if ( ( pFoundSlot == historyMap.end() ) || ( pFoundSlot->second == 0 ) )
|
Chris@16
|
1034 {
|
Chris@16
|
1035 // We have never entered this state before or history was cleared
|
Chris@16
|
1036 DefaultState::deep_construct(
|
Chris@16
|
1037 pContext, *polymorphic_downcast< MostDerived * >( this ) );
|
Chris@16
|
1038 }
|
Chris@16
|
1039 else
|
Chris@16
|
1040 {
|
Chris@16
|
1041 typedef void construct_function(
|
Chris@16
|
1042 const typename DefaultState::context_ptr_type &,
|
Chris@16
|
1043 typename DefaultState::outermost_context_base_type & );
|
Chris@16
|
1044 // 5.2.10.6 declares that reinterpret_casting a function pointer to a
|
Chris@16
|
1045 // different function pointer and back must yield the same value. The
|
Chris@16
|
1046 // following reinterpret_cast is the second half of such a sequence.
|
Chris@16
|
1047 construct_function * const pConstructFunction =
|
Chris@16
|
1048 reinterpret_cast< construct_function * >( pFoundSlot->second );
|
Chris@16
|
1049 (*pConstructFunction)(
|
Chris@16
|
1050 pContext, *polymorphic_downcast< MostDerived * >( this ) );
|
Chris@16
|
1051 }
|
Chris@16
|
1052 }
|
Chris@16
|
1053
|
Chris@16
|
1054 typedef std::list<
|
Chris@16
|
1055 event_base_ptr_type,
|
Chris@16
|
1056 typename boost::detail::allocator::rebind_to<
|
Chris@16
|
1057 allocator_type, event_base_ptr_type >::type
|
Chris@16
|
1058 > event_queue_type;
|
Chris@16
|
1059
|
Chris@16
|
1060 typedef std::map<
|
Chris@16
|
1061 const state_base_type *, event_queue_type,
|
Chris@16
|
1062 std::less< const state_base_type * >,
|
Chris@16
|
1063 typename boost::detail::allocator::rebind_to<
|
Chris@16
|
1064 allocator_type,
|
Chris@16
|
1065 std::pair< const state_base_type * const, event_queue_type >
|
Chris@16
|
1066 >::type
|
Chris@16
|
1067 > deferred_map_type;
|
Chris@16
|
1068
|
Chris@16
|
1069
|
Chris@16
|
1070 event_queue_type eventQueue_;
|
Chris@16
|
1071 event_queue_type deferredEventQueue_;
|
Chris@16
|
1072 state_list_type currentStates_;
|
Chris@16
|
1073 typename state_list_type::iterator currentStatesEnd_;
|
Chris@16
|
1074 state_base_type * pOutermostState_;
|
Chris@16
|
1075 bool isInnermostCommonOuter_;
|
Chris@16
|
1076 node_state_base_ptr_type pOutermostUnstableState_;
|
Chris@16
|
1077 ExceptionTranslator translator_;
|
Chris@16
|
1078 bool performFullExit_;
|
Chris@16
|
1079 history_map_type shallowHistoryMap_;
|
Chris@16
|
1080 history_map_type deepHistoryMap_;
|
Chris@16
|
1081 const event_base_type * pTriggeringEvent_;
|
Chris@16
|
1082 };
|
Chris@16
|
1083
|
Chris@16
|
1084
|
Chris@16
|
1085
|
Chris@16
|
1086 } // namespace statechart
|
Chris@16
|
1087 } // namespace boost
|
Chris@16
|
1088
|
Chris@16
|
1089
|
Chris@16
|
1090
|
Chris@16
|
1091 #endif
|