////////////////////////////////////////////////////////////////////////////// // Copyright 2002-2006 Andreas Huber Doenni // Distributed under the Boost Software License, Version 1.0. (See accompany- // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // The following code implements the state-machine (this version details an // alternative way of retrieving the elapsed time from the main program): // // -------------------------------- // | | // | O Active | // | | |<---- // | v | | EvReset // | ---------------------------- | | // | | | |----- // | | Stopped | | // | ---------------------------- | // | | ^ | // | | EvStartStop | EvStartStop |<-----O // | v | | // | ---------------------------- | // | | | | // | | Running | | // | ---------------------------- | // -------------------------------- #include #include #include #include #include #include #include #include #include #ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::time; using ::difftime; using ::time_t; } #endif #ifdef BOOST_INTEL # pragma warning( disable: 304 ) // access control not specified # pragma warning( disable: 444 ) // destructor for base is not virtual # pragma warning( disable: 981 ) // operands are evaluated in unspecified order #endif namespace sc = boost::statechart; namespace mpl = boost::mpl; struct EvStartStop : sc::event< EvStartStop > {}; struct EvReset : sc::event< EvReset > {}; struct EvGetElapsedTime : sc::event< EvGetElapsedTime > { public: EvGetElapsedTime( double & time ) : time_( time ) {} void Assign( double time ) const { time_ = time; } private: double & time_; }; struct Active; struct StopWatch : sc::state_machine< StopWatch, Active > {}; struct Stopped; struct Active : sc::simple_state< Active, StopWatch, Stopped > { public: typedef sc::transition< EvReset, Active > reactions; Active() : elapsedTime_( 0.0 ) {} double & ElapsedTime() { return elapsedTime_; } double ElapsedTime() const { return elapsedTime_; } private: double elapsedTime_; }; struct Running : sc::simple_state< Running, Active > { public: typedef mpl::list< sc::custom_reaction< EvGetElapsedTime >, sc::transition< EvStartStop, Stopped > > reactions; Running() : startTime_( std::time( 0 ) ) {} ~Running() { context< Active >().ElapsedTime() = ElapsedTime(); } sc::result react( const EvGetElapsedTime & evt ) { evt.Assign( ElapsedTime() ); return discard_event(); } private: double ElapsedTime() const { return context< Active >().ElapsedTime() + std::difftime( std::time( 0 ), startTime_ ); } std::time_t startTime_; }; struct Stopped : sc::simple_state< Stopped, Active > { typedef mpl::list< sc::custom_reaction< EvGetElapsedTime >, sc::transition< EvStartStop, Running > > reactions; sc::result react( const EvGetElapsedTime & evt ) { evt.Assign( context< Active >().ElapsedTime() ); return discard_event(); } }; namespace { char GetKey() { char key; std::cin >> key; return key; } } int main() { std::cout << "Boost.Statechart StopWatch example\n\n"; std::cout << "s: Starts/Stops stop watch\n"; std::cout << "r: Resets stop watch\n"; std::cout << "d: Displays the elapsed time in seconds\n"; std::cout << "e: Exits the program\n\n"; std::cout << "You may chain commands, e.g. rs resets and starts stop watch\n\n"; StopWatch stopWatch; stopWatch.initiate(); char key = GetKey(); while ( key != 'e' ) { switch( key ) { case 'r': { stopWatch.process_event( EvReset() ); } break; case 's': { stopWatch.process_event( EvStartStop() ); } break; case 'd': { double elapsedTime = 0.0; stopWatch.process_event( EvGetElapsedTime( elapsedTime ) ); std::cout << "Elapsed time: " << elapsedTime << "\n"; } break; default: { std::cout << "Invalid key!\n"; } break; } key = GetKey(); } return 0; }