fix doc example typo
[boost.git] / boost / statechart / state_machine.hpp
blob9c99cd1932aadcad6c16cbac156e68e8c79e31ab
1 #ifndef BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED
2 #define BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED
3 //////////////////////////////////////////////////////////////////////////////
4 // Copyright 2002-2008 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 //////////////////////////////////////////////////////////////////////////////
11 #include <boost/statechart/event.hpp>
12 #include <boost/statechart/null_exception_translator.hpp>
13 #include <boost/statechart/result.hpp>
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>
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>
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/cast.hpp> // boost::polymorphic_downcast
37 // BOOST_NO_EXCEPTIONS, BOOST_MSVC, BOOST_MSVC_STD_ITERATOR
38 #include <boost/config.hpp>
40 #include <boost/detail/allocator_utilities.hpp>
42 #ifdef BOOST_MSVC
43 # pragma warning( push )
44 # pragma warning( disable: 4702 ) // unreachable code (in release mode only)
45 #endif
47 #include <map>
49 #ifdef BOOST_MSVC
50 # pragma warning( pop )
51 #endif
53 #include <memory> // std::allocator
54 #include <typeinfo> // std::bad_cast
55 #include <functional> // std::less
56 #include <iterator>
60 namespace boost
62 namespace statechart
64 namespace detail
69 //////////////////////////////////////////////////////////////////////////////
70 template< class StateBaseType, class EventBaseType, class IdType >
71 class send_function
73 public:
74 //////////////////////////////////////////////////////////////////////////
75 send_function(
76 StateBaseType & toState,
77 const EventBaseType & evt,
78 IdType eventType
79 ) :
80 toState_( toState ), evt_( evt ), eventType_( eventType )
84 result operator()()
86 return detail::result_utility::make_result(
87 toState_.react_impl( evt_, eventType_ ) );
90 private:
91 //////////////////////////////////////////////////////////////////////////
92 // avoids C4512 (assignment operator could not be generated)
93 send_function & operator=( const send_function & );
95 StateBaseType & toState_;
96 const EventBaseType & evt_;
97 IdType eventType_;
101 //////////////////////////////////////////////////////////////////////////////
102 struct state_cast_impl_pointer_target
104 public:
105 //////////////////////////////////////////////////////////////////////////
106 template< class StateBaseType >
107 static const StateBaseType * deref_if_necessary(
108 const StateBaseType * pState )
110 return pState;
113 template< class Target, class IdType >
114 static IdType type_id()
116 Target p = 0;
117 return type_id_impl< IdType >( p );
120 static bool found( const void * pFound )
122 return pFound != 0;
125 template< class Target >
126 static Target not_found()
128 return 0;
131 private:
132 //////////////////////////////////////////////////////////////////////////
133 template< class IdType, class Type >
134 static IdType type_id_impl( const Type * )
136 return Type::static_type();
140 struct state_cast_impl_reference_target
142 template< class StateBaseType >
143 static const StateBaseType & deref_if_necessary(
144 const StateBaseType * pState )
146 return *pState;
149 template< class Target, class IdType >
150 static IdType type_id()
152 return remove_reference< Target >::type::static_type();
155 template< class Dummy >
156 static bool found( const Dummy & )
158 return true;
161 template< class Target >
162 static Target not_found()
164 throw std::bad_cast();
168 template< class Target >
169 struct state_cast_impl : public mpl::if_<
170 is_pointer< Target >,
171 state_cast_impl_pointer_target,
172 state_cast_impl_reference_target
173 >::type {};
176 //////////////////////////////////////////////////////////////////////////////
177 template< class RttiPolicy >
178 class history_key
180 public:
181 //////////////////////////////////////////////////////////////////////////
182 template< class HistorizedState >
183 static history_key make_history_key()
185 return history_key(
186 HistorizedState::context_type::static_type(),
187 HistorizedState::orthogonal_position::value );
190 typename RttiPolicy::id_type history_context_type() const
192 return historyContextType_;
195 friend bool operator<(
196 const history_key & left, const history_key & right )
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_ ) );
206 private:
207 //////////////////////////////////////////////////////////////////////////
208 history_key(
209 typename RttiPolicy::id_type historyContextType,
210 orthogonal_position_type historizedOrthogonalRegion
212 historyContextType_( historyContextType ),
213 historizedOrthogonalRegion_( historizedOrthogonalRegion )
217 // avoids C4512 (assignment operator could not be generated)
218 history_key & operator=( const history_key & );
220 const typename RttiPolicy::id_type historyContextType_;
221 const orthogonal_position_type historizedOrthogonalRegion_;
226 } // namespace detail
230 //////////////////////////////////////////////////////////////////////////////
231 template< class MostDerived,
232 class InitialState,
233 class Allocator = std::allocator< void >,
234 class ExceptionTranslator = null_exception_translator >
235 class state_machine : noncopyable
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;
244 void initiate()
246 terminate();
249 terminator guard( *this );
250 detail::result_utility::get_result( translator_(
251 initial_construct_function( *this ),
252 exception_event_handler( *this ) ) );
253 guard.dismiss();
256 process_queued_events();
259 void terminate()
261 terminator guard( *this );
262 detail::result_utility::get_result( translator_(
263 terminate_function( *this ),
264 exception_event_handler( *this ) ) );
265 guard.dismiss();
268 bool terminated() const
270 return pOutermostState_ == 0;
273 void process_event( const event_base_type & evt )
275 send_event( evt );
276 process_queued_events();
279 template< class Target >
280 Target state_cast() const
282 typedef detail::state_cast_impl< Target > impl;
284 for ( typename state_list_type::const_iterator pCurrentLeafState =
285 currentStates_.begin();
286 pCurrentLeafState != currentStatesEnd_;
287 ++pCurrentLeafState )
289 const state_base_type * pCurrentState(
290 get_pointer( *pCurrentLeafState ) );
292 while ( pCurrentState != 0 )
294 // The unnecessary try/catch overhead for pointer targets is
295 // typically small compared to the cycles dynamic_cast needs
296 #ifndef BOOST_NO_EXCEPTIONS
298 #endif
300 Target result = dynamic_cast< Target >(
301 impl::deref_if_necessary( pCurrentState ) );
303 if ( impl::found( result ) )
305 return result;
308 #ifndef BOOST_NO_EXCEPTIONS
309 // Intentionally swallow std::bad_cast exceptions. We'll throw one
310 // ourselves when we fail to find a state that can be cast to Target
311 catch ( const std::bad_cast & ) {}
312 #endif
314 pCurrentState = pCurrentState->outer_state_ptr();
318 return impl::template not_found< Target >();
321 template< class Target >
322 Target state_downcast() const
324 typedef detail::state_cast_impl< Target > impl;
326 typename rtti_policy_type::id_type targetType =
327 impl::template type_id< Target, rtti_policy_type::id_type >();
329 for ( typename state_list_type::const_iterator pCurrentLeafState =
330 currentStates_.begin();
331 pCurrentLeafState != currentStatesEnd_;
332 ++pCurrentLeafState )
334 const state_base_type * pCurrentState(
335 get_pointer( *pCurrentLeafState ) );
337 while ( pCurrentState != 0 )
339 if ( pCurrentState->dynamic_type() == targetType )
341 return static_cast< Target >(
342 impl::deref_if_necessary( pCurrentState ) );
345 pCurrentState = pCurrentState->outer_state_ptr();
349 return impl::template not_found< Target >();
352 typedef detail::state_base< allocator_type, rtti_policy_type >
353 state_base_type;
355 class state_iterator : public std::iterator<
356 std::forward_iterator_tag,
357 state_base_type, std::ptrdiff_t
358 #ifndef BOOST_MSVC_STD_ITERATOR
359 , const state_base_type *, const state_base_type &
360 #endif
363 public:
364 //////////////////////////////////////////////////////////////////////
365 explicit state_iterator(
366 typename state_base_type::state_list_type::const_iterator
367 baseIterator
368 ) : baseIterator_( baseIterator ) {}
370 const state_base_type & operator*() const { return **baseIterator_; }
371 const state_base_type * operator->() const
373 return &**baseIterator_;
376 state_iterator & operator++() { ++baseIterator_; return *this; }
377 state_iterator operator++( int )
379 return state_iterator( baseIterator_++ );
382 bool operator==( const state_iterator & right ) const
384 return baseIterator_ == right.baseIterator_;
386 bool operator!=( const state_iterator & right ) const
388 return !( *this == right );
391 private:
392 typename state_base_type::state_list_type::const_iterator
393 baseIterator_;
396 state_iterator state_begin() const
398 return state_iterator( currentStates_.begin() );
401 state_iterator state_end() const
403 return state_iterator( currentStatesEnd_ );
406 void unconsumed_event( const event_base & ) {}
408 protected:
409 //////////////////////////////////////////////////////////////////////////
410 state_machine() :
411 currentStatesEnd_( currentStates_.end() ),
412 pOutermostState_( 0 ),
413 isInnermostCommonOuter_( false ),
414 performFullExit_( true )
418 // This destructor was only made virtual so that that
419 // polymorphic_downcast can be used to cast to MostDerived.
420 virtual ~state_machine()
422 terminate_impl( false );
425 public:
426 //////////////////////////////////////////////////////////////////////////
427 // The following declarations should be protected.
428 // They are only public because many compilers lack template friends.
429 //////////////////////////////////////////////////////////////////////////
430 void post_event( const event_base_ptr_type & pEvent )
432 BOOST_ASSERT( get_pointer( pEvent ) != 0 );
433 eventQueue_.push_back( pEvent );
436 void post_event( const event_base & evt )
438 post_event( evt.intrusive_from_this() );
441 public:
442 //////////////////////////////////////////////////////////////////////////
443 // The following declarations should be private.
444 // They are only public because many compilers lack template friends.
445 //////////////////////////////////////////////////////////////////////////
446 typedef MostDerived inner_context_type;
447 typedef mpl::integral_c< detail::orthogonal_position_type, 0 >
448 inner_orthogonal_position;
449 typedef mpl::integral_c< detail::orthogonal_position_type, 1 >
450 no_of_orthogonal_regions;
452 typedef MostDerived outermost_context_type;
453 typedef state_machine outermost_context_base_type;
454 typedef state_machine * inner_context_ptr_type;
455 typedef typename state_base_type::node_state_base_ptr_type
456 node_state_base_ptr_type;
457 typedef typename state_base_type::leaf_state_ptr_type leaf_state_ptr_type;
458 typedef typename state_base_type::state_list_type state_list_type;
460 typedef mpl::clear< mpl::list<> >::type context_type_list;
462 typedef mpl::bool_< false > shallow_history;
463 typedef mpl::bool_< false > deep_history;
464 typedef mpl::bool_< false > inherited_deep_history;
466 detail::reaction_result react_impl(
467 const event_base_type &,
468 typename rtti_policy_type::id_type )
470 return detail::do_forward_event;
473 void exit_impl(
474 inner_context_ptr_type &,
475 typename state_base_type::node_state_base_ptr_type &,
476 bool ) {}
478 void set_outermost_unstable_state(
479 typename state_base_type::node_state_base_ptr_type &
480 pOutermostUnstableState )
482 pOutermostUnstableState = 0;
485 // Returns a reference to the context identified by the template
486 // parameter. This can either be _this_ object or one of its direct or
487 // indirect contexts.
488 template< class Context >
489 Context & context()
491 // As we are in the outermost context here, only this object can be
492 // returned.
493 return *polymorphic_downcast< MostDerived * >( this );
496 template< class Context >
497 const Context & context() const
499 // As we are in the outermost context here, only this object can be
500 // returned.
501 return *polymorphic_downcast< const MostDerived * >( this );
504 outermost_context_type & outermost_context()
506 return *polymorphic_downcast< MostDerived * >( this );
509 const outermost_context_type & outermost_context() const
511 return *polymorphic_downcast< const MostDerived * >( this );
514 outermost_context_base_type & outermost_context_base()
516 return *this;
519 const outermost_context_base_type & outermost_context_base() const
521 return *this;
524 void terminate_as_reaction( state_base_type & theState )
526 terminate_impl( theState, performFullExit_ );
527 pOutermostUnstableState_ = 0;
530 void terminate_as_part_of_transit( state_base_type & theState )
532 terminate_impl( theState, performFullExit_ );
533 isInnermostCommonOuter_ = true;
536 void terminate_as_part_of_transit( state_machine & )
538 terminate_impl( *pOutermostState_, performFullExit_ );
539 isInnermostCommonOuter_ = true;
543 template< class State >
544 void add( const intrusive_ptr< State > & pState )
546 // The second dummy argument is necessary because the call to the
547 // overloaded function add_impl would otherwise be ambiguous.
548 node_state_base_ptr_type pNewOutermostUnstableStateCandidate =
549 add_impl( pState, *pState );
551 if ( isInnermostCommonOuter_ ||
552 ( is_in_highest_orthogonal_region< State >() &&
553 ( get_pointer( pOutermostUnstableState_ ) ==
554 pState->State::outer_state_ptr() ) ) )
556 isInnermostCommonOuter_ = false;
557 pOutermostUnstableState_ = pNewOutermostUnstableStateCandidate;
562 void add_inner_state(
563 detail::orthogonal_position_type position,
564 state_base_type * pOutermostState )
566 BOOST_ASSERT( position == 0 );
567 detail::avoid_unused_warning( position );
568 pOutermostState_ = pOutermostState;
571 void remove_inner_state( detail::orthogonal_position_type position )
573 BOOST_ASSERT( position == 0 );
574 detail::avoid_unused_warning( position );
575 pOutermostState_ = 0;
579 void defer_event(
580 const event_base_type & evt,
581 const state_base_type * pForState )
583 deferredMap_[ pForState ].push_back( evt.intrusive_from_this() );
586 void release_events( const state_base_type * pForState )
588 const typename deferred_map_type::iterator pFound =
589 deferredMap_.find( pForState );
591 // We are not guaranteed to find an entry because a state is marked for
592 // having deferred events _before_ the event is actually deferred. An
593 // exception might be thrown during deferral.
594 if ( pFound != deferredMap_.end() )
596 eventQueue_.splice( eventQueue_.end(), pFound->second );
597 deferredMap_.erase( pFound );
602 template< class HistorizedState >
603 void store_shallow_history()
605 // 5.2.10.6 declares that reinterpret_casting a function pointer to a
606 // different function pointer and back must yield the same value. The
607 // following reinterpret_cast is the first half of such a sequence.
608 store_history_impl(
609 shallowHistoryMap_,
610 history_key_type::make_history_key< HistorizedState >(),
611 reinterpret_cast< void (*)() >( &HistorizedState::deep_construct ) );
614 template<
615 class HistoryContext,
616 detail::orthogonal_position_type orthogonalPosition >
617 void clear_shallow_history()
619 // If you receive a
620 // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or
621 // similar compiler error here then you tried to clear shallow history
622 // for a state that does not have shallow history. That is, the state
623 // does not pass either statechart::has_shallow_history or
624 // statechart::has_full_history to its base class template.
625 BOOST_STATIC_ASSERT( HistoryContext::shallow_history::value );
627 typedef typename mpl::at_c<
628 typename HistoryContext::inner_initial_list,
629 orthogonalPosition >::type historized_state;
631 store_history_impl(
632 shallowHistoryMap_,
633 history_key_type::make_history_key< historized_state >(),
634 0 );
637 template< class DefaultState >
638 void construct_with_shallow_history(
639 const typename DefaultState::context_ptr_type & pContext )
641 construct_with_history_impl< DefaultState >(
642 shallowHistoryMap_, pContext );
646 template< class HistorizedState, class LeafState >
647 void store_deep_history()
649 typedef typename detail::make_context_list<
650 typename HistorizedState::context_type,
651 LeafState >::type history_context_list;
652 typedef detail::constructor<
653 history_context_list, outermost_context_base_type > constructor_type;
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 deepHistoryMap_,
659 history_key_type::make_history_key< HistorizedState >(),
660 reinterpret_cast< void (*)() >( &constructor_type::construct ) );
663 template<
664 class HistoryContext,
665 detail::orthogonal_position_type orthogonalPosition >
666 void clear_deep_history()
668 // If you receive a
669 // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or
670 // similar compiler error here then you tried to clear deep history for
671 // a state that does not have deep history. That is, the state does not
672 // pass either statechart::has_deep_history or
673 // statechart::has_full_history to its base class template
674 BOOST_STATIC_ASSERT( HistoryContext::deep_history::value );
676 typedef typename mpl::at_c<
677 typename HistoryContext::inner_initial_list,
678 orthogonalPosition >::type historized_state;
680 store_history_impl(
681 deepHistoryMap_,
682 history_key_type::make_history_key< historized_state >(),
683 0 );
686 template< class DefaultState >
687 void construct_with_deep_history(
688 const typename DefaultState::context_ptr_type & pContext )
690 construct_with_history_impl< DefaultState >(
691 deepHistoryMap_, pContext );
694 private: // implementation
695 //////////////////////////////////////////////////////////////////////////
696 void initial_construct()
698 InitialState::initial_deep_construct(
699 *polymorphic_downcast< MostDerived * >( this ) );
702 class initial_construct_function
704 public:
705 //////////////////////////////////////////////////////////////////////
706 initial_construct_function( state_machine & machine ) :
707 machine_( machine )
711 result operator()()
713 machine_.initial_construct();
714 return detail::result_utility::make_result(
715 detail::do_discard_event ); // there is nothing to be consumed
718 private:
719 //////////////////////////////////////////////////////////////////////
720 // avoids C4512 (assignment operator could not be generated)
721 initial_construct_function & operator=(
722 const initial_construct_function & );
724 state_machine & machine_;
726 friend class initial_construct_function;
728 class terminate_function
730 public:
731 //////////////////////////////////////////////////////////////////////
732 terminate_function( state_machine & machine ) : machine_( machine ) {}
734 result operator()()
736 machine_.terminate_impl( true );
737 return detail::result_utility::make_result(
738 detail::do_discard_event ); // there is nothing to be consumed
741 private:
742 //////////////////////////////////////////////////////////////////////
743 // avoids C4512 (assignment operator could not be generated)
744 terminate_function & operator=( const terminate_function & );
746 state_machine & machine_;
748 friend class terminate_function;
750 template< class ExceptionEvent >
751 detail::reaction_result handle_exception_event(
752 const ExceptionEvent & exceptionEvent,
753 state_base_type * pCurrentState )
755 if ( terminated() )
757 // there is no state that could handle the exception -> bail out
758 throw;
761 // If we are stable, an event handler has thrown.
762 // Otherwise, either a state constructor, a transition action or an exit
763 // function has thrown and the state machine is now in an invalid state.
764 // This situation can be resolved by the exception event handler
765 // function by orderly transiting to another state or terminating.
766 // As a result of this, the machine must not be unstable when this
767 // function is left.
768 state_base_type * const pOutermostUnstableState =
769 get_pointer( pOutermostUnstableState_ );
770 state_base_type * const pHandlingState = pOutermostUnstableState == 0 ?
771 pCurrentState : pOutermostUnstableState;
773 BOOST_ASSERT( pHandlingState != 0 );
775 // Setting a member variable to a special value for the duration of a
776 // call surely looks like a kludge (normally it should be a parameter of
777 // the call). However, in this case it is unavoidable because the call
778 // below could result in a call to user code where passing through an
779 // additional bool parameter is not acceptable.
780 performFullExit_ = false;
781 const detail::reaction_result reactionResult = pHandlingState->react_impl(
782 exceptionEvent, exceptionEvent.dynamic_type() );
783 // If the above call throws then performFullExit_ will obviously not be
784 // set back to true. In this case the termination triggered by the
785 // scope guard further up in the call stack will take care of this.
786 performFullExit_ = true;
788 if ( ( reactionResult != detail::do_discard_event ) ||
789 ( get_pointer( pOutermostUnstableState_ ) != 0 ) )
791 throw;
794 return detail::do_discard_event;
797 class exception_event_handler
799 public:
800 //////////////////////////////////////////////////////////////////////
801 exception_event_handler(
802 state_machine & machine,
803 state_base_type * pCurrentState = 0
805 machine_( machine ),
806 pCurrentState_( pCurrentState )
810 template< class ExceptionEvent >
811 result operator()(
812 const ExceptionEvent & exceptionEvent )
814 return detail::result_utility::make_result(
815 machine_.handle_exception_event(
816 exceptionEvent, pCurrentState_ ) );
819 private:
820 //////////////////////////////////////////////////////////////////////
821 // avoids C4512 (assignment operator could not be generated)
822 exception_event_handler & operator=(
823 const exception_event_handler & );
825 state_machine & machine_;
826 state_base_type * pCurrentState_;
828 friend class exception_event_handler;
830 class terminator
832 public:
833 //////////////////////////////////////////////////////////////////////
834 terminator( state_machine & machine ) :
835 machine_( machine ), dismissed_( false ) {}
836 ~terminator()
838 if ( !dismissed_ ) { machine_.terminate_impl( false ); }
840 void dismiss() { dismissed_ = true; }
842 private:
843 //////////////////////////////////////////////////////////////////////
844 // avoids C4512 (assignment operator could not be generated)
845 terminator & operator=( const terminator & );
847 state_machine & machine_;
848 bool dismissed_;
850 friend class terminator;
853 void send_event( const event_base_type & evt )
855 terminator guard( *this );
856 BOOST_ASSERT( get_pointer( pOutermostUnstableState_ ) == 0 );
857 const typename rtti_policy_type::id_type eventType = evt.dynamic_type();
858 detail::reaction_result reactionResult = detail::do_forward_event;
860 for (
861 typename state_list_type::iterator pState = currentStates_.begin();
862 ( reactionResult == detail::do_forward_event ) &&
863 ( pState != currentStatesEnd_ );
864 ++pState )
866 // CAUTION: The following statement could modify our state list!
867 // We must not continue iterating if the event was consumed
868 reactionResult = detail::result_utility::get_result( translator_(
869 detail::send_function<
870 state_base_type, event_base_type, rtti_policy_type::id_type >(
871 **pState, evt, eventType ),
872 exception_event_handler( *this, get_pointer( *pState ) ) ) );
875 guard.dismiss();
877 if ( reactionResult == detail::do_forward_event )
879 polymorphic_downcast< MostDerived * >( this )->unconsumed_event( evt );
884 void process_queued_events()
886 while ( !eventQueue_.empty() )
888 const event_base_ptr_type pCurrentEvent( eventQueue_.front() );
889 eventQueue_.pop_front();
890 send_event( *pCurrentEvent );
895 void terminate_impl( bool performFullExit )
897 performFullExit_ = true;
899 if ( !terminated() )
901 // this also empties deferredMap_
902 terminate_impl( *pOutermostState_, performFullExit );
905 eventQueue_.clear();
906 shallowHistoryMap_.clear();
907 deepHistoryMap_.clear();
910 void terminate_impl( state_base_type & theState, bool performFullExit )
912 isInnermostCommonOuter_ = false;
914 // If pOutermostUnstableState_ == 0, we know for sure that
915 // currentStates_.size() > 0, otherwise theState couldn't be alive any
916 // more
917 if ( get_pointer( pOutermostUnstableState_ ) != 0 )
919 theState.remove_from_state_list(
920 currentStatesEnd_, pOutermostUnstableState_, performFullExit );
922 // Optimization: We want to find out whether currentStates_ has size 1
923 // and if yes use the optimized implementation below. Since
924 // list<>::size() is implemented quite inefficiently in some std libs
925 // it is best to just decrement the currentStatesEnd_ here and
926 // increment it again, if the test failed.
927 else if ( currentStates_.begin() == --currentStatesEnd_ )
929 // The machine is stable and there is exactly one innermost state.
930 // The following optimization is only correct for a stable machine
931 // without orthogonal regions.
932 leaf_state_ptr_type & pState = *currentStatesEnd_;
933 pState->exit_impl(
934 pState, pOutermostUnstableState_, performFullExit );
936 else
938 BOOST_ASSERT( currentStates_.size() > 1 );
939 // The machine is stable and there are multiple innermost states
940 theState.remove_from_state_list(
941 ++currentStatesEnd_, pOutermostUnstableState_, performFullExit );
946 node_state_base_ptr_type add_impl(
947 const leaf_state_ptr_type & pState,
948 detail::leaf_state< allocator_type, rtti_policy_type > & )
950 if ( currentStatesEnd_ == currentStates_.end() )
952 pState->set_list_position(
953 currentStates_.insert( currentStatesEnd_, pState ) );
955 else
957 *currentStatesEnd_ = pState;
958 pState->set_list_position( currentStatesEnd_ );
959 ++currentStatesEnd_;
962 return 0;
965 node_state_base_ptr_type add_impl(
966 const node_state_base_ptr_type & pState,
967 state_base_type & )
969 return pState;
972 template< class State >
973 static bool is_in_highest_orthogonal_region()
975 return mpl::equal_to<
976 typename State::orthogonal_position,
977 mpl::minus<
978 typename State::context_type::no_of_orthogonal_regions,
979 mpl::integral_c< detail::orthogonal_position_type, 1 > >
980 >::value;
984 typedef detail::history_key< rtti_policy_type > history_key_type;
986 typedef std::map<
987 history_key_type, void (*)(),
988 std::less< history_key_type >,
989 typename boost::detail::allocator::rebind_to<
990 allocator_type, std::pair< const history_key_type, void (*)() >
991 >::type
992 > history_map_type;
994 void store_history_impl(
995 history_map_type & historyMap,
996 const history_key_type & historyId,
997 void (*pConstructFunction)() )
999 historyMap[ historyId ] = pConstructFunction;
1002 template< class DefaultState >
1003 void construct_with_history_impl(
1004 history_map_type & historyMap,
1005 const typename DefaultState::context_ptr_type & pContext )
1007 typename history_map_type::iterator pFoundSlot = historyMap.find(
1008 history_key_type::make_history_key< DefaultState >() );
1010 if ( ( pFoundSlot == historyMap.end() ) || ( pFoundSlot->second == 0 ) )
1012 // We have never entered this state before or history was cleared
1013 DefaultState::deep_construct(
1014 pContext, *polymorphic_downcast< MostDerived * >( this ) );
1016 else
1018 typedef void construct_function(
1019 const typename DefaultState::context_ptr_type &,
1020 typename DefaultState::outermost_context_base_type & );
1021 // 5.2.10.6 declares that reinterpret_casting a function pointer to a
1022 // different function pointer and back must yield the same value. The
1023 // following reinterpret_cast is the second half of such a sequence.
1024 construct_function * const pConstructFunction =
1025 reinterpret_cast< construct_function * >( pFoundSlot->second );
1026 (*pConstructFunction)(
1027 pContext, *polymorphic_downcast< MostDerived * >( this ) );
1031 typedef std::list<
1032 event_base_ptr_type,
1033 typename boost::detail::allocator::rebind_to<
1034 allocator_type, event_base_ptr_type >::type
1035 > event_queue_type;
1037 typedef std::map<
1038 const state_base_type *, event_queue_type,
1039 std::less< const state_base_type * >,
1040 typename boost::detail::allocator::rebind_to<
1041 allocator_type,
1042 std::pair< const state_base_type * const, event_queue_type >
1043 >::type
1044 > deferred_map_type;
1047 event_queue_type eventQueue_;
1048 deferred_map_type deferredMap_;
1049 state_list_type currentStates_;
1050 typename state_list_type::iterator currentStatesEnd_;
1051 state_base_type * pOutermostState_;
1052 bool isInnermostCommonOuter_;
1053 node_state_base_ptr_type pOutermostUnstableState_;
1054 ExceptionTranslator translator_;
1055 bool performFullExit_;
1056 history_map_type shallowHistoryMap_;
1057 history_map_type deepHistoryMap_;
1062 } // namespace statechart
1063 } // namespace boost
1067 #endif