diff --git a/example/BitMachine/BitMachine.cpp b/example/BitMachine/BitMachine.cpp index c3854c0..9d59f91 100644 --- a/example/BitMachine/BitMachine.cpp +++ b/example/BitMachine/BitMachine.cpp @@ -9,7 +9,7 @@ ////////////////////////////////////////////////////////////////////////////// -const unsigned int noOfBits = 1; +const unsigned int noOfBits = 6; ////////////////////////////////////////////////////////////////////////////// // This program demonstrates the fact that measures must be taken to hide some // of the complexity (e.g. in separate .cpp file) of a boost::fsm state @@ -29,10 +29,10 @@ const unsigned int noOfBits = 1; // (i.e. no attempt is made to hide inner state implementation in a .cpp file) // can be deduced. // -// Compiler | max. noOfBits b | max. states s | max. transitions t -// --------------|-----------------|---------------|------------------- -// MSVC 7.0 | b < 5 | 16 < s < 32 | 64 < t < 120 -// MSVC 7.1 | b < 6 | 32 < s < 64 | 120 < t < 384 +// Compiler | max. noOfBits b | max. states s | max. transitions t +// --------------|-----------------|----------------|------------------- +// MSVC 7.0 | b < 5 | 16 < s < 32 | 64 < t < 120 +// MSVC 7.1 | b < 7 | 64 < s < 128 | 384 < t < 896 // // CAUTION: Due to the fact that the amount of generated code more than // *doubles* each time noOfBits is *incremented*, build times soar when @@ -50,6 +50,7 @@ const unsigned int noOfBits = 1; #include #include #include +#include #include #include #include @@ -57,8 +58,6 @@ const unsigned int noOfBits = 1; #include #include -#include -#include #ifdef BOOST_MSVC #pragma warning( push ) @@ -114,7 +113,7 @@ void DisplayBits( unsigned int number ) ////////////////////////////////////////////////////////////////////////////// template< unsigned int bitNo > -class EvFlipBit : public fsm::event< EvFlipBit > {}; +class EvFlipBit : public fsm::event {}; const EvFlipBit< 0 > flip0; const EvFlipBit< 1 > flip1; const EvFlipBit< 2 > flip2; @@ -125,7 +124,7 @@ const EvFlipBit< 6 > flip6; const EvFlipBit< 7 > flip7; const EvFlipBit< 8 > flip8; const EvFlipBit< 9 > flip9; -const fsm::event_base * const pFlipBitEvents[] = +const fsm::event * const pFlipBitEvents[] = { &flip0, &flip1, &flip2, &flip3, &flip4, &flip5, &flip6, &flip7, &flip8, &flip9 }; @@ -207,7 +206,7 @@ void VisitAllStates( BitMachine & bitMachine ) #endif if ( display ) { - bitMachine.current_state< IDisplay >().DisplayBits(); + bitMachine.state_cast< const IDisplay & >().DisplayBits(); } #ifdef BOOST_MSVC #pragma warning( pop ) @@ -228,7 +227,7 @@ void VisitAllStates< 0, true >( BitMachine & bitMachine ) { bitMachine.process_event( *pFlipBitEvents[ 0 ] ); ++eventsSentTotal; - bitMachine.current_state< IDisplay >().DisplayBits(); + bitMachine.state_cast< const IDisplay & >().DisplayBits(); } @@ -246,9 +245,12 @@ int main( int argc, char * argv[] ) argc; argv; + BOOST_ASSERT( noOfBits <= 10 ); + std::cout << "boost::fsm BitMachine example\n"; std::cout << "Machine configuration: " << noOfStates << " states interconnected with " << noOfTransitions << " transitions.\n\n"; + for ( unsigned int bit = 0; bit < noOfBits; ++bit ) { std::cout << bit - 0 << ": Flips bit " << bit - 0 << "\n"; @@ -271,7 +273,7 @@ int main( int argc, char * argv[] ) { bitMachine.process_event( *pFlipBitEvents[ key - '0' ] ); ++eventsSentTotal; - bitMachine.current_state< IDisplay >().DisplayBits(); + bitMachine.state_cast< const IDisplay & >().DisplayBits(); } else { diff --git a/example/BitMachine/BitMachine.vcproj b/example/BitMachine/BitMachine.vcproj index 10ad99c..9797afe 100644 --- a/example/BitMachine/BitMachine.vcproj +++ b/example/BitMachine/BitMachine.vcproj @@ -148,10 +148,10 @@ RelativePath="..\..\..\..\boost\fsm\custom_reaction.hpp"> + RelativePath="..\..\..\..\boost\fsm\deferal.hpp"> + RelativePath="..\..\..\..\boost\fsm\event.hpp"> diff --git a/example/BitMachine/UniqueObjectAllocator.hpp b/example/BitMachine/UniqueObjectAllocator.hpp index 8c57d8e..b51eac3 100644 --- a/example/BitMachine/UniqueObjectAllocator.hpp +++ b/example/BitMachine/UniqueObjectAllocator.hpp @@ -10,6 +10,9 @@ +#include +#include + #include // size_t diff --git a/example/Camera/Camera.hpp b/example/Camera/Camera.hpp index a927131..759317e 100644 --- a/example/Camera/Camera.hpp +++ b/example/Camera/Camera.hpp @@ -19,10 +19,10 @@ namespace fsm = boost::fsm; -class EvShutterHalf : public fsm::event< EvShutterHalf > {}; -class EvShutterFull : public fsm::event< EvShutterFull > {}; -class EvShutterRelease : public fsm::event< EvShutterRelease > {}; -class EvConfig : public fsm::event< EvConfig > {}; +class EvShutterHalf : public fsm::event {}; +class EvShutterFull : public fsm::event {}; +class EvShutterRelease : public fsm::event {}; +class EvConfig : public fsm::event {}; struct NotShooting; @@ -40,7 +40,7 @@ struct NotShooting : public fsm::simple_state< NotShooting, Camera, NotShooting(); ~NotShooting(); - virtual fsm::result react( const EvShutterHalf & ); + fsm::result react( const EvShutterHalf & ); }; struct Idle : public fsm::simple_state< Idle, NotShooting, @@ -49,7 +49,7 @@ struct Idle : public fsm::simple_state< Idle, NotShooting, Idle(); ~Idle(); - virtual fsm::result react( const EvConfig & ); + fsm::result react( const EvConfig & ); }; diff --git a/example/Camera/Camera.vcproj b/example/Camera/Camera.vcproj index 0dc562f..3edb262 100644 --- a/example/Camera/Camera.vcproj +++ b/example/Camera/Camera.vcproj @@ -189,18 +189,18 @@ + + + RelativePath="..\..\..\..\boost\fsm\exception_translator.hpp"> - - diff --git a/example/Camera/Shooting.cpp b/example/Camera/Shooting.cpp index 31b1274..df2783f 100644 --- a/example/Camera/Shooting.cpp +++ b/example/Camera/Shooting.cpp @@ -54,8 +54,6 @@ fsm::result Focused::react( const EvShutterFull & ) } -struct EvInFocus : public fsm::event< EvInFocus > {}; - Focusing::Focusing( my_context ctx ) : my_base( ctx ) { post_event( boost::intrusive_ptr< EvInFocus >( new EvInFocus() ) ); diff --git a/example/Camera/Shooting.hpp b/example/Camera/Shooting.hpp index b5644da..695c6b2 100644 --- a/example/Camera/Shooting.hpp +++ b/example/Camera/Shooting.hpp @@ -16,13 +16,16 @@ #include #include #include +#include #include namespace fsm = boost::fsm; +namespace mpl = boost::mpl; -struct EvInFocus; +struct EvInFocus : public fsm::event {}; + struct Focusing; struct Shooting : public fsm::simple_state< Shooting, Camera, fsm::transition< EvShutterRelease, NotShooting >, Focusing > @@ -36,11 +39,11 @@ struct Shooting : public fsm::simple_state< Shooting, Camera, } }; -struct Focusing : public fsm::state< Focusing, Shooting, - fsm::custom_reaction< EvInFocus > > +struct Focusing : public fsm::state< Focusing, Shooting, mpl::list< + fsm::custom_reaction< EvInFocus >, fsm::deferal< EvShutterFull > > > { Focusing( my_context ctx ); - virtual fsm::result react( const EvInFocus & ); + fsm::result react( const EvInFocus & ); }; diff --git a/example/StateSize/StateSize.cpp b/example/StateSize/StateSize.cpp index 1e007e3..8de6c8b 100644 --- a/example/StateSize/StateSize.cpp +++ b/example/StateSize/StateSize.cpp @@ -27,10 +27,10 @@ namespace mpl = boost::mpl; ////////////////////////////////////////////////////////////////////////////// // Displays the runtime sizes of states ////////////////////////////////////////////////////////////////////////////// -class DummyEvent1 : public fsm::event< DummyEvent1 > {}; -class DummyEvent2 : public fsm::event< DummyEvent2 > {}; -class DummyEvent3 : public fsm::event< DummyEvent3 > {}; -class DummyEvent4 : public fsm::event< DummyEvent4 > {}; +class DummyEvent1 : public fsm::event {}; +class DummyEvent2 : public fsm::event {}; +class DummyEvent3 : public fsm::event {}; +class DummyEvent4 : public fsm::event {}; class UnconnectedOuterState; diff --git a/example/StateSize/StateSize.vcproj b/example/StateSize/StateSize.vcproj index 221ba27..b505902 100644 --- a/example/StateSize/StateSize.vcproj +++ b/example/StateSize/StateSize.vcproj @@ -145,18 +145,18 @@ + + + RelativePath="..\..\..\..\boost\fsm\exception_translator.hpp"> - - diff --git a/example/StopWatch/StopWatch.cpp b/example/StopWatch/StopWatch.cpp index 446738e..313e954 100644 --- a/example/StopWatch/StopWatch.cpp +++ b/example/StopWatch/StopWatch.cpp @@ -48,8 +48,8 @@ namespace mpl = boost::mpl; -class EvStartStop : public fsm::event< EvStartStop > {}; -class EvReset : public fsm::event< EvReset > {}; +class EvStartStop : public fsm::event {}; +class EvReset : public fsm::event {}; struct IElapsedTime { @@ -161,7 +161,7 @@ int main( int argc, char * argv[] ) case 'd': { std::cout << "Elapsed time: " << - stopWatch.current_state< IElapsedTime >().ElapsedTime() << "\n"; + stopWatch.state_cast< const IElapsedTime & >().ElapsedTime() << "\n"; } break; diff --git a/example/StopWatch/StopWatch.vcproj b/example/StopWatch/StopWatch.vcproj index 6820114..e37e3bf 100644 --- a/example/StopWatch/StopWatch.vcproj +++ b/example/StopWatch/StopWatch.vcproj @@ -146,10 +146,10 @@ RelativePath="..\..\..\..\boost\fsm\custom_reaction.hpp"> + RelativePath="..\..\..\..\boost\fsm\deferal.hpp"> + RelativePath="..\..\..\..\boost\fsm\event.hpp"> diff --git a/include/boost/statechart/custom_reaction.hpp b/include/boost/statechart/custom_reaction.hpp index a64d863..83e95f1 100644 --- a/include/boost/statechart/custom_reaction.hpp +++ b/include/boost/statechart/custom_reaction.hpp @@ -10,7 +10,12 @@ -#include +#include +#include + +#include // boost::polymorphic_downcast + +#include // std::type_info @@ -21,14 +26,23 @@ namespace fsm +////////////////////////////////////////////////////////////////////////////// template< class Event > struct custom_reaction { - template< class Derived > - struct apply + template< class State > + static result react( + State & stt, const event & evt, const std::type_info & eventType ) { - typedef detail::reaction< Event > type; - }; + if ( eventType == typeid( const Event ) ) + { + return stt.react( *polymorphic_downcast< const Event * >( &evt ) ); + } + else + { + return no_reaction; + } + } }; diff --git a/include/boost/statechart/detail/reaction.hpp b/include/boost/statechart/deferal.hpp similarity index 59% rename from include/boost/statechart/detail/reaction.hpp rename to include/boost/statechart/deferal.hpp index a0e050e..b322f69 100644 --- a/include/boost/statechart/detail/reaction.hpp +++ b/include/boost/statechart/deferal.hpp @@ -1,5 +1,5 @@ -#ifndef BOOST_FSM_EVENT_HANDLER_HPP_INCLUDED -#define BOOST_FSM_EVENT_HANDLER_HPP_INCLUDED +#ifndef BOOST_FSM_DEFERAL_HPP_INCLUDED +#define BOOST_FSM_DEFERAL_HPP_INCLUDED ////////////////////////////////////////////////////////////////////////////// // Copyright (c) 2002-2003 Andreas Huber Doenni, Switzerland // Permission to copy, use, modify, sell and distribute this software @@ -10,8 +10,11 @@ +#include #include +#include // std::type_info + namespace boost @@ -20,36 +23,28 @@ namespace fsm { - -template< class Derived > -class event; - - - -namespace detail -{ - - ////////////////////////////////////////////////////////////////////////////// template< class Event > -class reaction +struct deferal { - protected: - ////////////////////////////////////////////////////////////////////////// - reaction() {} - ~reaction() {} - - private: - ////////////////////////////////////////////////////////////////////////// - virtual result react( const Event & toEvent ) = 0; - - friend class event< Event >; + template< class State > + static result react( + State & stt, const event &, const std::type_info & eventType ) + { + if ( eventType == typeid( const Event ) ) + { + return stt.defer_event(); + } + else + { + return no_reaction; + } + }; }; -} // namespace detail } // namespace fsm } // namespace boost diff --git a/include/boost/statechart/detail/counted_base.hpp b/include/boost/statechart/detail/counted_base.hpp index 4f03e84..2b61f8a 100644 --- a/include/boost/statechart/detail/counted_base.hpp +++ b/include/boost/statechart/detail/counted_base.hpp @@ -50,6 +50,11 @@ class counted_base : private locked_base< NeedsLocking > ////////////////////////////////////////////////////////////////////////// virtual ~counted_base() {} + bool ref_counted() const + { + return count_ != 0; + } + protected: ////////////////////////////////////////////////////////////////////////// counted_base() : count_( 0 ) {} diff --git a/include/boost/statechart/detail/state_base.hpp b/include/boost/statechart/detail/state_base.hpp index ef3527e..398f5b6 100644 --- a/include/boost/statechart/detail/state_base.hpp +++ b/include/boost/statechart/detail/state_base.hpp @@ -10,11 +10,14 @@ +#include #include #include // boost::noncopyable #include // BOOST_ASSERT +#include // std::type_info + #ifdef BOOST_MSVC @@ -33,7 +36,7 @@ namespace fsm -class event_base; +class event; @@ -54,22 +57,26 @@ class state_base : private noncopyable, { public: ////////////////////////////////////////////////////////////////////////// + virtual result react_impl( + const event & evt, const std::type_info & eventType ) = 0; + // returns a pointer to the immediate outer state _if_ there is one, // returns 0 otherwise (this is the outermost state then) - state_base * outer_state_ptr() const - { - return pOuterState_; - } + virtual state_base * outer_state_ptr() const = 0; protected: ////////////////////////////////////////////////////////////////////////// state_base() : reactionEnabled_( false ), - deferredEvents_( false ), - pOuterState_( 0 ) + deferredEvents_( false ) { } + void enable_reaction() + { + reactionEnabled_ = true; + } + void reaction_initiated() { // This assert fails when you try to call a reaction function outside @@ -92,39 +99,10 @@ class state_base : private noncopyable, return deferredEvents_; } - void set_context( state_base * pOuterState ) - { - // Context must only be set once - BOOST_ASSERT( ( pOuterState != 0 ) && ( pOuterState_ == 0 ) ); - pOuterState_ = pOuterState; - } - - void set_context( void * pMachine ) - { - // Context must only be set once - BOOST_ASSERT( ( pMachine != 0 ) && ( pOuterState_ == 0 ) ); - pMachine; - } - private: ////////////////////////////////////////////////////////////////////////// - friend class ::boost::fsm::event_base; - - void enable_reaction() - { - reactionEnabled_ = true; - } - bool reactionEnabled_; bool deferredEvents_; - // Storing another pointer to our outer state looks like a bit of a waste - // but the alternatives are not really appealing either. To begin with, - // there is a tiny difference between the two pointers: The subclass - // pointer references the context of a state which can be another state - // or the state machine. This pointer however only points to our outer - // state _if_ there is one. It is 0 if the outer context of this state - // is the state machine itself. - state_base * pOuterState_; }; diff --git a/include/boost/statechart/detail/universal_state.hpp b/include/boost/statechart/detail/universal_state.hpp index 71c657f..ae7932b 100644 --- a/include/boost/statechart/detail/universal_state.hpp +++ b/include/boost/statechart/detail/universal_state.hpp @@ -35,7 +35,6 @@ class universal_state : public state_base template< class Context > void set_context( orthogonal_position_type position, Context * pContext ) { - base_type::set_context( pContext ); pContext->add_inner_state( position, this ); } diff --git a/include/boost/statechart/event.hpp b/include/boost/statechart/event.hpp index c64bfd9..59ee75b 100644 --- a/include/boost/statechart/event.hpp +++ b/include/boost/statechart/event.hpp @@ -10,11 +10,13 @@ -#include -#include -#include +#include -#include // boost::polymorphic_downcast +#include +#include +#include + +#include @@ -25,48 +27,20 @@ namespace fsm -class state_base; - - - -template< class Derived > -class event : public event_base +////////////////////////////////////////////////////////////////////////////// +class event : private noncopyable, public detail::counted_base< unsigned int > { + public: + ////////////////////////////////////////////////////////////////////////// + intrusive_ptr< const event > clone() const + { + BOOST_ASSERT( ref_counted() ); + return intrusive_ptr< const event >( this ); + } + protected: ////////////////////////////////////////////////////////////////////////// event() {} - - private: - ////////////////////////////////////////////////////////////////////////// - virtual result send( detail::state_base & toState ) const - { - result reactionResult = do_forward_event; - detail::state_base * pCurrentState( &toState ); - - while ( ( reactionResult == do_forward_event ) && - ( pCurrentState != 0 ) ) - { - detail::reaction< Derived > * const pReceiver = - dynamic_cast< detail::reaction< Derived > * >( pCurrentState ); - - if ( pReceiver != 0 ) - { - enable_reaction( *pCurrentState ); - // the following statement could delete pCurrentState! - reactionResult = pReceiver->react( - *polymorphic_downcast< const Derived * >( this ) ); - } - - if ( reactionResult == do_forward_event ) - { - // we can only safely access pCurrentState if the handler did not - // return do_discard_event! - pCurrentState = pCurrentState->outer_state_ptr(); - } - } - - return reactionResult; - } }; diff --git a/include/boost/statechart/event_base.hpp b/include/boost/statechart/event_base.hpp deleted file mode 100644 index f62a8f1..0000000 --- a/include/boost/statechart/event_base.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef BOOST_FSM_EVENT_BASE_HPP_INCLUDED -#define BOOST_FSM_EVENT_BASE_HPP_INCLUDED -////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2002-2003 Andreas Huber Doenni, Switzerland -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -////////////////////////////////////////////////////////////////////////////// - - - -#include -#include - -#include - -#include - - - -#ifdef BOOST_MSVC -// We permanently turn off the following level 4 warnings because users will -// have to do so themselves anyway if we turn them back on -#pragma warning( disable: 4511 ) // copy constructor could not be generated -#pragma warning( disable: 4512 ) // assignment operator could not be generated -#endif - - - -namespace boost -{ -namespace fsm -{ - - - -////////////////////////////////////////////////////////////////////////////// -class event_base : private noncopyable, public detail::counted_base< unsigned int > -{ - public: - ////////////////////////////////////////////////////////////////////////// - virtual ~event_base() {} - - protected: - ////////////////////////////////////////////////////////////////////////// - event_base() {} - - static void enable_reaction( detail::state_base & fromState ) - { - fromState.enable_reaction(); - } - - public: - ////////////////////////////////////////////////////////////////////////// - // CAUTION: The following declarations should be private. - // They are only public because many compilers lack template friends. - ////////////////////////////////////////////////////////////////////////// - virtual result send( detail::state_base & toState ) const = 0; -}; - - - -} // namespace fsm -} // namespace boost - - - -#endif diff --git a/include/boost/statechart/exception_translator.hpp b/include/boost/statechart/exception_translator.hpp index 5a49ad1..3e9ccc5 100644 --- a/include/boost/statechart/exception_translator.hpp +++ b/include/boost/statechart/exception_translator.hpp @@ -22,10 +22,12 @@ namespace fsm -class exception_thrown : public event< exception_thrown > {}; +////////////////////////////////////////////////////////////////////////////// +class exception_thrown : public event {}; +////////////////////////////////////////////////////////////////////////////// struct exception_translator { template< class Action, class ExceptionEventHandler > diff --git a/include/boost/statechart/result.hpp b/include/boost/statechart/result.hpp index 563ed7d..e89033f 100644 --- a/include/boost/statechart/result.hpp +++ b/include/boost/statechart/result.hpp @@ -17,8 +17,10 @@ namespace fsm +////////////////////////////////////////////////////////////////////////////// enum result { + no_reaction, do_forward_event, do_discard_event, do_defer_event diff --git a/include/boost/statechart/simple_state.hpp b/include/boost/statechart/simple_state.hpp index 5da3dcb..95d7af2 100644 --- a/include/boost/statechart/simple_state.hpp +++ b/include/boost/statechart/simple_state.hpp @@ -13,14 +13,13 @@ #include #include -#include +#include #include #include #include #include #include -#include #include #include #include @@ -33,19 +32,17 @@ #include #include #include -#include #include -#include #include -#include - #include #include +#include +#include #include // boost::polymorphic_downcast #include // BOOST_STATIC_CONSTANT -#include // BOOST_ASSERT +#include // std::type_info namespace boost @@ -59,6 +56,7 @@ namespace detail typedef mpl::clear< mpl::list<> >::type empty_list; +////////////////////////////////////////////////////////////////////////////// template< class T > struct make_list : public mpl::apply_if< mpl::is_sequence< T >, @@ -67,7 +65,8 @@ struct make_list : public mpl::apply_if< using namespace mpl::placeholders; -template< class Derived, class Context, class Reactions, class InnerInitial > +////////////////////////////////////////////////////////////////////////////// +template< class Context, class InnerInitial > struct state_base_type { private: @@ -75,24 +74,18 @@ struct state_base_type // orthogonal_position typedef typename detail::make_list< InnerInitial >::type inner_initial_list; + + public: typedef typename mpl::apply_if< mpl::empty< inner_initial_list >, mpl::identity< leaf_state< typename Context::state_list_type > >, mpl::identity< node_state< mpl::size< inner_initial_list >::type::value, - typename Context::state_list_type > > >::type base; - - typedef typename detail::make_list< Reactions >::type reaction_list; - typedef typename mpl::transform< - reaction_list, mpl::apply1< _, Derived > >::type handler_list; - - public: - typedef typename mpl::fold< - typename mpl::reverse< typename mpl::push_front< handler_list, base >::type >::type, - mpl::empty_base, mpl::inherit2< _1, _2 > >::type type; + typename Context::state_list_type > > >::type type; }; +////////////////////////////////////////////////////////////////////////////// struct no_transition_function { template< class CommonContext > @@ -173,6 +166,7 @@ struct get_orthogonal_position< int > }; +////////////////////////////////////////////////////////////////////////////// template< class ContextList, class TopContext > struct outer_constructor { @@ -238,19 +232,17 @@ typedef detail::empty_list no_reactions; -// Base class for all states +////////////////////////////////////////////////////////////////////////////// template< class Derived, class Context, // either an outer state or a state_machine class Reactions = no_reactions, class InnerInitial = detail::empty_list > // initial inner state -class simple_state : public // mpl::aux::msvc_eti_base< - /*typename*/ detail::state_base_type< - Derived, typename Context::inner_context_type, - Reactions, InnerInitial >::type //>::type +class simple_state : public detail::state_base_type< + typename Context::inner_context_type, InnerInitial >::type { typedef typename detail::state_base_type< - Derived, typename Context::inner_context_type, - Reactions, InnerInitial >::type base_type; + typename Context::inner_context_type, + InnerInitial >::type base_type; public: ////////////////////////////////////////////////////////////////////////// @@ -289,6 +281,25 @@ class simple_state : public // mpl::aux::msvc_eti_base< return context_impl( static_cast< OtherContext * >( 0 ) ); } + void post_event( const event_ptr_type & pEvent ) + { + top_context().post_event( pEvent ); + } + + // see state_machine class for documentation + template< class Target > + Target state_cast() const + { + return top_context().state_cast< Target >(); + } + + // see state_machine class for documentation + template< class Target > + Target state_downcast() const + { + return top_context().state_downcast< Target >(); + } + result discard_event() { @@ -305,7 +316,7 @@ class simple_state : public // mpl::aux::msvc_eti_base< result defer_event() { state_base::reaction_initiated(); - defer_event(); + state_base::defer_event(); return do_defer_event; } @@ -340,12 +351,6 @@ class simple_state : public // mpl::aux::msvc_eti_base< return do_discard_event; } - - void post_event( const event_ptr_type & pEvent ) - { - top_context().post_event( pEvent ); - } - protected: ////////////////////////////////////////////////////////////////////////// simple_state() {} @@ -356,6 +361,11 @@ class simple_state : public // mpl::aux::msvc_eti_base< // can be called before the context is set. if ( get_pointer( pContext_ ) != 0 ) { + if ( deferred_events() ) + { + top_context().release_events( this ); + } + pContext_->remove_inner_state( orthogonal_position ); } } @@ -382,12 +392,43 @@ class simple_state : public // mpl::aux::msvc_eti_base< context_type >::type context_type_list; + virtual result react_impl( + const event & evt, const std::type_info & eventType ) + { + enable_reaction(); + typedef detail::make_list< Reactions >::type reaction_list; + result reactionResult = + local_react_impl< reaction_list >( evt, eventType ); + + if ( reactionResult == do_forward_event ) + { + // we can only safely access pCurrentState if the handler did not + // return do_discard_event! + reactionResult = pContext_->Context::react_impl( evt, eventType ); + } + + return reactionResult; + } + + virtual detail::state_base * outer_state_ptr() const + { + return outer_state_ptr_impl< + is_same< top_context_type, Context >::value >(); + } + + top_context_type & top_context() { BOOST_ASSERT( get_pointer( pContext_ ) != 0 ); return pContext_->top_context(); } + const top_context_type & top_context() const + { + BOOST_ASSERT( get_pointer( pContext_ ) != 0 ); + return pContext_->top_context(); + } + // Returns a pointer to the direct or indirect context identified by the // template parameter. In contrast to context(), this function cannot @@ -545,6 +586,42 @@ class simple_state : public // mpl::aux::msvc_eti_base< return do_discard_event; } + template< class ReactionList > + result local_react_impl( + const event & evt, const std::type_info & eventType ) + { + result reactionResult = mpl::front< ReactionList >::type::react( + *polymorphic_downcast< Derived * >( this ), evt, eventType ); + + if ( reactionResult == no_reaction ) + { + reactionResult = + local_react_impl< mpl::pop_front< ReactionList >::type >( + evt, eventType ); + } + + return reactionResult; + } + + template<> + result local_react_impl< no_reactions >( + const event &, const std::type_info & ) + { + return do_forward_event; + } + + template< bool isOutermost > + detail::state_base * outer_state_ptr_impl() const + { + return get_pointer( pContext_ ); + } + + template<> + detail::state_base * outer_state_ptr_impl< true >() const + { + return 0; + } + template< class InnerList > static void deep_construct_inner_impl( diff --git a/include/boost/statechart/state.hpp b/include/boost/statechart/state.hpp index 2c27434..d4833db 100644 --- a/include/boost/statechart/state.hpp +++ b/include/boost/statechart/state.hpp @@ -25,8 +25,7 @@ template< class Derived, class Context, // either an outer state or a state_machine class Reactions = no_reactions, class InnerInitial = detail::empty_list > // initial inner state -class state : - public simple_state< Derived, Context, Reactions, InnerInitial > +class state : public simple_state< Derived, Context, Reactions, InnerInitial > { typedef simple_state< Derived, Context, Reactions, InnerInitial > base_type; diff --git a/include/boost/statechart/state_machine.hpp b/include/boost/statechart/state_machine.hpp index bdb2c53..97b1429 100644 --- a/include/boost/statechart/state_machine.hpp +++ b/include/boost/statechart/state_machine.hpp @@ -12,7 +12,7 @@ #include -#include +#include #include #include @@ -20,9 +20,10 @@ #include #include +#include +#include +#include #include // boost::polymorphic_downcast -#include // boost::noncopyable -#include // BOOST_ASSERT #include // BOOST_STATIC_CONSTANT #ifdef BOOST_MSVC @@ -31,13 +32,14 @@ #endif #include +#include #ifdef BOOST_MSVC #pragma warning( pop ) #endif #include // std::allocator -#include // std::bad_cast +#include // std::type_info, std::bad_cast @@ -66,26 +68,96 @@ class node_state; template< class StateList > class leaf_state; + +////////////////////////////////////////////////////////////////////////////// class send_function { public: ////////////////////////////////////////////////////////////////////////// send_function( - const event_base & evt, state_base & toState + state_base & toState, + const event & evt, + const std::type_info & eventType ) : - evt_( evt ), toState_( toState ) + toState_( toState ), evt_( evt ), eventType_( eventType ) { } result operator()() { - return evt_.send( toState_ ); + return toState_.react_impl( evt_, eventType_ ); } private: ////////////////////////////////////////////////////////////////////////// - const event_base & evt_; state_base & toState_; + const event & evt_; + const std::type_info & eventType_; +}; + + +////////////////////////////////////////////////////////////////////////////// +template< bool pointerTarget > +struct state_cast_impl +{ + public: + ////////////////////////////////////////////////////////////////////////// + static const state_base * deref_if_necessary( const state_base * pState ) + { + return pState; + } + + template< class Target > + static const type_info & type() + { + Target p = 0; + return type_impl( p ); + } + + static bool found( const void * pFound ) + { + return pFound != 0; + } + + template< class Target > + static Target not_found() + { + return 0; + } + + private: + ////////////////////////////////////////////////////////////////////////// + template< class Type > + static const type_info & type_impl( const Type * ) + { + return typeid( const Type ); + } +}; + +template<> +struct state_cast_impl< false > +{ + static const state_base & deref_if_necessary( const state_base * pState ) + { + return *pState; + } + + template< class Target > + static const type_info & type() + { + return typeid( Target ); + } + + static bool found( ... ) + { + return true; + } + + template< class Target > + static Target not_found() + { + throw std::bad_cast(); + } }; @@ -105,7 +177,7 @@ class state_machine : private noncopyable { public: ////////////////////////////////////////////////////////////////////////// - typedef intrusive_ptr< event_base > event_ptr_type; + typedef intrusive_ptr< const event > event_ptr_type; void initiate() { @@ -123,52 +195,99 @@ class state_machine : private noncopyable } - void process_event( const event_base & evt ) + void process_event( const event & evt ) { send_event( evt ); process_queued_events(); } - // Polymorphic state query. Returns a pointer to the state identified by - // the template parameter _if_ the machine is currently in this state. - // Throws std::bad_cast otherwise. - template< class State > - const State & current_state() const + // Has semantics similar to dynamic_cast. Returns a pointer or a reference + // to a state with the specified type _if_ the machine is currently in + // such a state. Can _cross_ inheritance trees, e.g. if the machine is in + // state A, which derives from simple_state _and_ B then + // state_cast< const B & >() will return a reference to B and + // state_cast< const A & >() will return a reference to A. + // Target can take either of the following forms: + // - const X &: throws std::bad_cast if the machine is not currently in + // state X + // - const X *: returns 0 if the machine is not currently in state X + template< class Target > + Target state_cast() const { - const State * const pCurrentState( current_state_ptr< State >() ); - - if ( pCurrentState != 0 ) - { - return *pCurrentState; - } - - throw std::bad_cast(); - } - - // Polymorphic state query. Returns a pointer to the state identified by - // the template parameter _if_ the machine is currently in this state. - // Returns 0 otherwise. - template< class State > - const State * current_state_ptr() const - { - const State * pResult = 0; + typedef detail::state_cast_impl< is_pointer< Target >::value > impl; for ( state_list_type::const_iterator pCurrentLeafState = currentStates_.begin(); - ( pCurrentLeafState != currentStates_.end() ) && ( pResult == 0 ); + pCurrentLeafState != currentStates_.end(); ++pCurrentLeafState ) { const detail::state_base * pCurrentState( get_pointer( *pCurrentLeafState ) ); - while ( ( pCurrentState != 0 ) && ( ( pResult = - dynamic_cast< const State * >( pCurrentState ) ) == 0 ) ) + while ( pCurrentState != 0 ) { + // The unnecessary try/catch overhead for pointer targets is + // typically small compared to the cycles dynamic_cast needs + try + { + Target result = dynamic_cast< Target >( + impl::deref_if_necessary( pCurrentState ) ); + + if ( impl::found( result ) ) + { + return result; + } + } + catch ( const std::bad_cast & ) + { + } + pCurrentState = pCurrentState->outer_state_ptr(); } } - return pResult; + return impl::not_found< Target >(); + } + + // Typically much faster variant of state_cast. Returns a pointer or a + // reference to a state with the specified type _if_ the machine is + // currently in such a state. + // Does _not_ cross inheritance trees, i.e. Target must be a most-derived + // type, e.g. if the machine is in state A, which derives from + // simple_state _and_ B then state_downcast< const B & >() will not + // compile while state_downcast< const A & >() will return a reference to + // A. + // Target can take either of the following forms: + // - const X &: throws std::bad_cast if the machine is not currently in + // state X + // - const X *: returns 0 if the machine is not currently in state X + template< class Target > + Target state_downcast() const + { + typedef detail::state_cast_impl< is_pointer< Target >::value > impl; + const type_info & targetType = impl::type< Target >(); + + for ( state_list_type::const_iterator pCurrentLeafState = + currentStates_.begin(); + pCurrentLeafState != currentStates_.end(); + ++pCurrentLeafState ) + { + const detail::state_base * pCurrentState( + get_pointer( *pCurrentLeafState ) ); + + while ( pCurrentState != 0 ) + { + if ( typeid( *pCurrentState ) == targetType ) + { + return static_cast< Target >( + impl::deref_if_necessary( pCurrentState ) ); + } + + pCurrentState = pCurrentState->outer_state_ptr(); + } + } + + return impl::not_found< Target >(); } protected: @@ -202,6 +321,12 @@ class state_machine : private noncopyable typedef mpl::clear< mpl::list<> >::type context_type_list; + result react_impl( const event &, const std::type_info & ) + { + return do_discard_event; + } + + // Returns a reference to the context identified by the template // parameter. This can either be _this_ object or one of its direct or // indirect contexts. @@ -219,12 +344,16 @@ class state_machine : private noncopyable return *polymorphic_downcast< const Derived * >( this ); } - top_context_type & top_context() { return *polymorphic_downcast< Derived * >( this ); } + const top_context_type & top_context() const + { + return *polymorphic_downcast< const Derived * >( this ); + } + void terminate( state_machine & ) { @@ -291,12 +420,23 @@ class state_machine : private noncopyable position; } + void release_events( const detail::state_base * pForState ) + { + const deferred_map_type::iterator pFound = + deferredMap_.find( pForState ); + + // We are not guaranteed to find an entry because a state is marked for + // having deferred events _before_ the event is actually deferred. An + // exception might be thrown during deferal. + if ( pFound != deferredMap_.end() ) + { + eventQueue_.splice( eventQueue_.end(), pFound->second ); + deferredMap_.erase( pFound ); + } + } + private: // implementation ////////////////////////////////////////////////////////////////////////// - typedef std::list< - event_ptr_type, - typename Allocator::rebind< event_ptr_type >::other > event_queue_type; - void initial_construct() { InitialState::deep_construct( @@ -352,14 +492,23 @@ class state_machine : private noncopyable BOOST_ASSERT( pHandlingState != 0 ); - const result reaction_result = translator_( - detail::send_function( exceptionEvent, *pHandlingState ), + const result reactionResult = translator_( + detail::send_function( + *pHandlingState, exceptionEvent, typeid( exceptionEvent ) ), exception_event_handler( *this, pCurrentState ), do_discard_event ); - // TODO: defer event here + if ( reactionResult == do_defer_event ) + { + // For clone() to work, the exception event must have been allocated + // with new. Out of the box this is not the case, so users will have + // to replace the exception_translator should they ever need to do so. + // Deferring exception events makes sense only in very rare cases and + // is dangerous unless operator new never throws. + defer_event( exceptionEvent, pHandlingState ); + } - return ( reaction_result != do_forward_event ) && + return ( reactionResult != do_forward_event ) && ( machine_status() != unstable ); } @@ -390,42 +539,61 @@ class state_machine : private noncopyable friend exception_event_handler; - void send_event( const event_base & evt ) + class terminator { + public: + terminator( state_machine & machine ) : + machine_( machine ), dismissed_( false ) {} + ~terminator() { if ( !dismissed_ ) { machine_.terminate(); } } + void dismiss() { dismissed_ = true; } + + private: + state_machine & machine_; + bool dismissed_; + }; + + void send_event( const event & evt ) + { + terminator guard( *this ); BOOST_ASSERT( machine_status() != unstable ); - result reaction_result = do_forward_event; + const std::type_info & eventType = typeid( evt ); + + result reactionResult = do_forward_event; state_list_type::iterator pState = currentStates_.begin(); - while ( ( reaction_result == do_forward_event ) && + while ( ( reactionResult == do_forward_event ) && ( pState != currentStates_.end() ) ) { - try - { - // CAUTION: The following statement could modify our state list! - // We must not continue iterating, if the event was consumed - reaction_result = translator_( - detail::send_function( evt, **pState ), - exception_event_handler( *this, get_pointer( *pState ) ), - do_discard_event ); - } - catch ( ... ) - { - terminate(); - throw; - } + // CAUTION: The following statement could modify our state list! + // We must not continue iterating, if the event was consumed + reactionResult = translator_( + detail::send_function( **pState, evt, eventType ), + exception_event_handler( *this, get_pointer( *pState ) ), + do_discard_event ); - // TODO: defer event here - - if ( reaction_result == do_forward_event ) + switch ( reactionResult ) { - // we can only safely advance the iterator if currentStates has - // not been modified! - ++pState; + case do_defer_event: + defer_event( evt, get_pointer( *pState ) ); break; + case do_forward_event: + ++pState; break; + // intentionally no default case (do nothing) } } + + guard.dismiss(); } + + void defer_event( + const event & evt, + const detail::state_base * pForState ) + { + deferredMap_[ pForState ].push_back( evt.clone() ); + } + + void process_queued_events() { while ( !eventQueue_.empty() ) @@ -466,7 +634,8 @@ class state_machine : private noncopyable return **pUnstableState_; } - template< detail::orthogonal_position_type noOfOrthogonalRegions, class StateList > + template< detail::orthogonal_position_type noOfOrthogonalRegions, + class StateList > void add_impl( const detail::node_state< noOfOrthogonalRegions, StateList > & ) {} @@ -477,7 +646,18 @@ class state_machine : private noncopyable pUnstableState_ = currentStates_.end(); } + typedef std::list< + event_ptr_type, + typename Allocator::rebind< event_ptr_type >::other > event_queue_type; + + typedef std::map< + const detail::state_base *, event_queue_type, + std::less< const detail::state_base * >, + typename Allocator::rebind< std::pair< const detail::state_base * const, + event_queue_type > >::other > deferred_map_type; + event_queue_type eventQueue_; + deferred_map_type deferredMap_; state_list_type currentStates_; typename state_list_type::iterator pUnstableState_; ExceptionTranslator translator_; diff --git a/include/boost/statechart/termination.hpp b/include/boost/statechart/termination.hpp index a6d0866..e5d4463 100644 --- a/include/boost/statechart/termination.hpp +++ b/include/boost/statechart/termination.hpp @@ -10,9 +10,10 @@ -#include +#include +#include -#include // boost::polymorphic_downcast +#include // std::type_info @@ -20,34 +21,25 @@ namespace boost { namespace fsm { -namespace detail -{ - - - -template< class Derived, class Event > -class termination_reaction : public reaction< Event > -{ - private: - virtual result react( const Event & ) - { - return polymorphic_downcast< Derived * >( this )->terminate(); - } -}; - - - -} // namespace detail +////////////////////////////////////////////////////////////////////////////// template< class Event > struct termination { - template< class Derived > - struct apply + template< class State > + static result react( + State & stt, const event &, const std::type_info & eventType ) { - typedef detail::termination_reaction< Derived, Event > type; + if ( eventType == typeid( const Event ) ) + { + return stt.terminate(); + } + else + { + return no_reaction; + } }; }; diff --git a/include/boost/statechart/transition.hpp b/include/boost/statechart/transition.hpp index 52dc7a1..94bf418 100644 --- a/include/boost/statechart/transition.hpp +++ b/include/boost/statechart/transition.hpp @@ -10,9 +10,12 @@ -#include +#include +#include -#include +#include // boost::polymorphic_downcast + +#include // std::type_info @@ -25,6 +28,7 @@ namespace detail +////////////////////////////////////////////////////////////////////////////// struct no_context { template< class Event > @@ -33,51 +37,52 @@ struct no_context -template< class Derived, class Event, class Destination, - class TransitionContext, - void ( TransitionContext::*pTransitionAction )( const Event & ) > -class transition_reaction : public reaction< Event > -{ - private: - virtual result react( const Event & toEvent ) - { - return react_impl< TransitionContext >( toEvent ); - } - - template< class TransitionContext > - result react_impl( const Event & toEvent ) - { - return polymorphic_downcast< Derived * >( this )-> - transit< Destination >( pTransitionAction, toEvent ); - } - - template<> - result react_impl< no_context >( const Event & ) - { - return polymorphic_downcast< Derived * >( this )-> - transit< Destination >(); - } -}; - - - } // namespace detail +////////////////////////////////////////////////////////////////////////////// template< class Event, class Destination, class TransitionContext = detail::no_context, void ( TransitionContext::*pTransitionAction )( const Event & ) = &detail::no_context::no_function< Event > > struct transition { - template< class Derived > - struct apply - { - typedef detail::transition_reaction< - Derived, Event, Destination, - TransitionContext, pTransitionAction > type; - }; + private: + ////////////////////////////////////////////////////////////////////////// + template< class State > + struct impl + { + template< class TransitionContext2 > + static result react( State & stt, const event & toEvent ) + { + return stt.transit< Destination >( pTransitionAction, + *polymorphic_downcast< const Event * >( &toEvent ) ); + } + + template<> + static result react< detail::no_context >( + State & stt, const event & ) + { + return stt.transit< Destination >(); + } + }; + + public: + ////////////////////////////////////////////////////////////////////////// + template< class State > + static result react( + State & stt, const event & evt, const std::type_info & eventType ) + { + if ( eventType == typeid( const Event ) ) + { + return impl< State >::react< TransitionContext >( stt, evt ); + } + else + { + return no_reaction; + } + } };