Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/statechart/state_machine.hpp @ 33

Last change on this file since 33 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

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