| // Copyright 2010 Christophe Henry |
| // henry UNDERSCORE christophe AT hotmail DOT com |
| // This is an extended version of the state machine available in the boost::mpl library |
| // Distributed under the same license as the original. |
| // Copyright for the original version: |
| // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed |
| // under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| #include <boost/statechart/event.hpp> |
| #include <boost/statechart/state_machine.hpp> |
| #include <boost/statechart/simple_state.hpp> |
| #include <boost/statechart/transition.hpp> |
| #include "boost/mpl/list.hpp" |
| |
| #include <vector> |
| |
| #include <iostream> |
| #ifdef WIN32 |
| #include "windows.h" |
| #else |
| #include <sys/time.h> |
| #endif |
| |
| namespace sc = boost::statechart; |
| namespace mpl = boost::mpl; |
| |
| namespace test_sc |
| { |
| |
| //events |
| struct play : sc::event< play > {}; |
| struct end_pause : sc::event< end_pause > {}; |
| struct stop : sc::event< stop > {}; |
| struct pause : sc::event< pause > {}; |
| struct open_close : sc::event< open_close > {}; |
| struct cd_detected : sc::event< cd_detected > {}; |
| struct NextSong: sc::event< NextSong > {}; |
| struct PreviousSong : sc::event< PreviousSong >{}; |
| |
| struct Empty; |
| struct Open; |
| struct Stopped; |
| struct Playing; |
| struct Paused; |
| // SM |
| struct player : sc::state_machine< player, Empty > |
| { |
| void open_drawer(open_close const&) { /*std::cout << "player::open_drawer\n";*/ } |
| void store_cd_info(cd_detected const& cd) {/*std::cout << "player::store_cd_info\n";*/ } |
| void close_drawer(open_close const&) { /*std::cout << "player::close_drawer\n";*/ } |
| void start_playback(play const&) { /*std::cout << "player::start_playback\n";*/ } |
| void stopped_again(stop const&) {/*std::cout << "player::stopped_again\n";*/} |
| void stop_playback(stop const&) { /*std::cout << "player::stop_playback\n";*/ } |
| void pause_playback(pause const&) { /*std::cout << "player::pause_playback\n"; */} |
| void stop_and_open(open_close const&) { /*std::cout << "player::stop_and_open\n";*/ } |
| void resume_playback(end_pause const&) { /*std::cout << "player::resume_playback\n";*/ } |
| }; |
| |
| struct Empty : sc::simple_state< Empty, player > |
| { |
| Empty() { /*std::cout << "entering Empty" << std::endl;*/ } // entry |
| ~Empty() { /*std::cout << "leaving Empty" << std::endl;*/ } // exit |
| typedef mpl::list< |
| sc::transition< open_close, Open, |
| player, &player::open_drawer >, |
| sc::transition< cd_detected, Stopped, |
| player, &player::store_cd_info > > reactions; |
| |
| }; |
| struct Open : sc::simple_state< Open, player > |
| { |
| Open() { /*std::cout << "entering Open" << std::endl;*/ } // entry |
| ~Open() { /*std::cout << "leaving Open" << std::endl;*/ } // exit |
| typedef sc::transition< open_close, Empty, |
| player, &player::close_drawer > reactions; |
| |
| }; |
| struct Stopped : sc::simple_state< Stopped, player > |
| { |
| Stopped() { /*std::cout << "entering Stopped" << std::endl;*/ } // entry |
| ~Stopped() { /*std::cout << "leaving Stopped" << std::endl;*/ } // exit |
| typedef mpl::list< |
| sc::transition< play, Playing, |
| player, &player::start_playback >, |
| sc::transition< open_close, Open, |
| player, &player::open_drawer >, |
| sc::transition< stop, Stopped, |
| player, &player::stopped_again > > reactions; |
| |
| }; |
| struct Song1; |
| struct Playing : sc::simple_state< Playing, player,Song1 > |
| { |
| Playing() { /*std::cout << "entering Playing" << std::endl;*/ } // entry |
| ~Playing() { /*std::cout << "leaving Playing" << std::endl;*/ } // exit |
| typedef mpl::list< |
| sc::transition< stop, Stopped, |
| player, &player::stop_playback >, |
| sc::transition< pause, Paused, |
| player, &player::pause_playback >, |
| sc::transition< open_close, Open, |
| player, &player::stop_and_open > > reactions; |
| void start_next_song(NextSong const&) { /*std::cout << "Playing::start_next_song\n";*/ } |
| void start_prev_song(PreviousSong const&) { /*std::cout << "Playing::start_prev_song\n";*/ } |
| }; |
| struct Song2; |
| struct Song1 : sc::simple_state< Song1, Playing > |
| { |
| Song1() { /*std::cout << "entering Song1" << std::endl;*/ } // entry |
| ~Song1() { /*std::cout << "leaving Song1" << std::endl;*/ } // exit |
| typedef sc::transition< NextSong, Song2, |
| Playing, &Playing::start_next_song > reactions; |
| }; |
| struct Song3; |
| struct Song2 : sc::simple_state< Song2, Playing > |
| { |
| Song2() { /*std::cout << "entering Song2" << std::endl;*/ } // entry |
| ~Song2() { /*std::cout << "leaving Song2" << std::endl;*/ } // exit |
| typedef mpl::list< |
| sc::transition< NextSong, Song3, |
| Playing, &Playing::start_next_song >, |
| sc::transition< PreviousSong, Song1, |
| Playing, &Playing::start_prev_song > > reactions; |
| }; |
| struct Song3 : sc::simple_state< Song3, Playing > |
| { |
| Song3() { /*std::cout << "entering Song3" << std::endl;*/ } // entry |
| ~Song3() { /*std::cout << "leaving Song3" << std::endl;*/ } // exit |
| typedef sc::transition< PreviousSong, Song2, |
| Playing, &Playing::start_prev_song > reactions; |
| }; |
| struct Paused : sc::simple_state< Paused, player > |
| { |
| Paused() { /*std::cout << "entering Paused" << std::endl;*/ } // entry |
| ~Paused() { /*std::cout << "leaving Paused" << std::endl;*/ } // exit |
| typedef mpl::list< |
| sc::transition< end_pause, Playing, |
| player, &player::resume_playback >, |
| sc::transition< stop, Stopped, |
| player, &player::stop_playback >, |
| sc::transition< open_close, Open, |
| player, &player::stop_and_open > > reactions; |
| }; |
| } |
| |
| |
| #ifndef WIN32 |
| long mtime(struct timeval& tv1,struct timeval& tv2) |
| { |
| return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec)); |
| } |
| #endif |
| |
| int main() |
| { |
| test_sc::player p; |
| p.initiate(); |
| // for timing |
| #ifdef WIN32 |
| LARGE_INTEGER res; |
| ::QueryPerformanceFrequency(&res); |
| LARGE_INTEGER li,li2; |
| ::QueryPerformanceCounter(&li); |
| #else |
| struct timeval tv1,tv2; |
| gettimeofday(&tv1,NULL); |
| #endif |
| |
| for (int i=0;i<100;++i) |
| { |
| p.process_event(test_sc::open_close()); |
| p.process_event(test_sc::open_close()); |
| p.process_event(test_sc::cd_detected()); |
| p.process_event(test_sc::play()); |
| for (int j=0;j<100;++j) |
| { |
| p.process_event(test_sc::NextSong()); |
| p.process_event(test_sc::NextSong()); |
| p.process_event(test_sc::PreviousSong()); |
| p.process_event(test_sc::PreviousSong()); |
| } |
| |
| p.process_event(test_sc::pause()); |
| // go back to Playing |
| p.process_event(test_sc::end_pause()); |
| p.process_event(test_sc::pause()); |
| p.process_event(test_sc::stop()); |
| // event leading to the same state |
| p.process_event(test_sc::stop()); |
| p.process_event(test_sc::open_close()); |
| p.process_event(test_sc::open_close()); |
| } |
| #ifdef WIN32 |
| ::QueryPerformanceCounter(&li2); |
| #else |
| gettimeofday(&tv2,NULL); |
| #endif |
| #ifdef WIN32 |
| std::cout << "sc took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl; |
| #else |
| std::cout << "sc took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl; |
| #endif |
| return 0; |
| } |
| |