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

source code of boost/libs/statechart/include/boost/statechart/state_machine.hpp