////////////////////////////////////////////////////////////////////////////// // 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 is the version // discussed in the tutorial): // // -------------------------------- // | | // | O Active | // | | |<---- // | v | | EvReset // | ---------------------------- | | // | | | |----- // | | Stopped | | // | ---------------------------- | // | | ^ | // | | EvStartStop | EvStartStop |<-----O // | v | | // | ---------------------------- | // | | | | // | | Running | | // | ---------------------------- | // -------------------------------- #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; ////////////////////////////////////////////////////////////////////////////// struct EvStartStop : sc::event< EvStartStop > {}; struct EvReset : sc::event< EvReset > {}; struct IElapsedTime { virtual double ElapsedTime() const = 0; }; 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 : IElapsedTime, sc::simple_state< Running, Active > { public: typedef sc::transition< EvStartStop, Stopped > reactions; Running() : startTime_( std::time( 0 ) ) {} ~Running() { context< Active >().ElapsedTime() = ElapsedTime(); } virtual double ElapsedTime() const { return context< Active >().ElapsedTime() + std::difftime( std::time( 0 ), startTime_ ); } private: std::time_t startTime_; }; struct Stopped : IElapsedTime, sc::simple_state< Stopped, Active > { typedef sc::transition< EvStartStop, Running > reactions; virtual double ElapsedTime() const { return context< Active >().ElapsedTime(); } }; ////////////////////////////////////////////////////////////////////////////// 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': { std::cout << "Elapsed time: " << stopWatch.state_cast< const IElapsedTime & >().ElapsedTime() << "\n"; } break; default: { std::cout << "Invalid key!\n"; } break; } key = GetKey(); } return 0; }