1 // Copyright 2010 Christophe Henry
2 // henry UNDERSCORE christophe AT hotmail DOT com
3 // This is an extended version of the state machine available in the boost::mpl library
4 // Distributed under the same license as the original.
5 // Copyright for the original version:
6 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
7 // under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 
11 #include <boost/statechart/event.hpp>
12 #include <boost/statechart/state_machine.hpp>
13 #include <boost/statechart/simple_state.hpp>
14 #include <boost/statechart/transition.hpp>
15 #include "boost/mpl/list.hpp"
16 
17 #include <vector>
18 
19 #include <iostream>
20 #ifdef WIN32
21 #include "windows.h"
22 #else
23 #include <sys/time.h>
24 #endif
25 
26 namespace sc = boost::statechart;
27 namespace mpl = boost::mpl;
28 
29 namespace test_sc
30 {
31 
32     //events
33     struct play : sc::event< play > {};
34     struct end_pause : sc::event< end_pause > {};
35     struct stop : sc::event< stop > {};
36     struct pause : sc::event< pause > {};
37     struct open_close : sc::event< open_close > {};
38     struct cd_detected : sc::event< cd_detected > {};
39     struct NextSong: sc::event< NextSong > {};
40     struct PreviousSong : sc::event< PreviousSong >{};
41 
42     struct Empty;
43     struct Open;
44     struct Stopped;
45     struct Playing;
46     struct Paused;
47     // SM
48     struct player : sc::state_machine< player, Empty >
49     {
open_drawertest_sc::player50         void open_drawer(open_close const&)         { /*std::cout << "player::open_drawer\n";*/ }
store_cd_infotest_sc::player51         void store_cd_info(cd_detected const& cd)   {/*std::cout << "player::store_cd_info\n";*/ }
close_drawertest_sc::player52         void close_drawer(open_close const&)        { /*std::cout << "player::close_drawer\n";*/ }
start_playbacktest_sc::player53         void start_playback(play const&)            { /*std::cout << "player::start_playback\n";*/ }
stopped_againtest_sc::player54         void stopped_again(stop const&)             {/*std::cout << "player::stopped_again\n";*/}
stop_playbacktest_sc::player55         void stop_playback(stop const&)             { /*std::cout << "player::stop_playback\n";*/ }
pause_playbacktest_sc::player56         void pause_playback(pause const&)           { /*std::cout << "player::pause_playback\n"; */}
stop_and_opentest_sc::player57         void stop_and_open(open_close const&)       { /*std::cout << "player::stop_and_open\n";*/ }
resume_playbacktest_sc::player58         void resume_playback(end_pause const&)      { /*std::cout << "player::resume_playback\n";*/ }
59     };
60 
61     struct Empty : sc::simple_state< Empty, player >
62     {
Emptytest_sc::Empty63         Empty() { /*std::cout << "entering Empty" << std::endl;*/ } // entry
~Emptytest_sc::Empty64         ~Empty() { /*std::cout << "leaving Empty" << std::endl;*/ } // exit
65         typedef mpl::list<
66             sc::transition< open_close, Open,
67             player, &player::open_drawer >,
68             sc::transition< cd_detected, Stopped,
69             player, &player::store_cd_info > > reactions;
70 
71     };
72     struct Open : sc::simple_state< Open, player >
73     {
Opentest_sc::Open74         Open() { /*std::cout << "entering Open" << std::endl;*/ } // entry
~Opentest_sc::Open75         ~Open() { /*std::cout << "leaving Open" << std::endl;*/ } // exit
76         typedef sc::transition< open_close, Empty,
77             player, &player::close_drawer > reactions;
78 
79     };
80     struct Stopped : sc::simple_state< Stopped, player >
81     {
Stoppedtest_sc::Stopped82         Stopped() { /*std::cout << "entering Stopped" << std::endl;*/ } // entry
~Stoppedtest_sc::Stopped83         ~Stopped() { /*std::cout << "leaving Stopped" << std::endl;*/ } // exit
84         typedef mpl::list<
85             sc::transition< play, Playing,
86             player, &player::start_playback >,
87             sc::transition< open_close, Open,
88             player, &player::open_drawer >,
89             sc::transition< stop, Stopped,
90             player, &player::stopped_again > > reactions;
91 
92     };
93     struct Song1;
94     struct Playing : sc::simple_state< Playing, player,Song1 >
95     {
Playingtest_sc::Playing96         Playing() { /*std::cout << "entering Playing" << std::endl;*/ } // entry
~Playingtest_sc::Playing97         ~Playing() { /*std::cout << "leaving Playing" << std::endl;*/ } // exit
98         typedef mpl::list<
99             sc::transition< stop, Stopped,
100             player, &player::stop_playback >,
101             sc::transition< pause, Paused,
102             player, &player::pause_playback >,
103             sc::transition< open_close, Open,
104             player, &player::stop_and_open > > reactions;
start_next_songtest_sc::Playing105         void start_next_song(NextSong const&)       { /*std::cout << "Playing::start_next_song\n";*/ }
start_prev_songtest_sc::Playing106         void start_prev_song(PreviousSong const&)       { /*std::cout << "Playing::start_prev_song\n";*/ }
107     };
108     struct Song2;
109     struct Song1  : sc::simple_state< Song1, Playing >
110     {
Song1test_sc::Song1111         Song1() { /*std::cout << "entering Song1" << std::endl;*/ } // entry
~Song1test_sc::Song1112         ~Song1() { /*std::cout << "leaving Song1" << std::endl;*/ } // exit
113         typedef sc::transition< NextSong, Song2,
114             Playing, &Playing::start_next_song > reactions;
115     };
116     struct Song3;
117     struct Song2  : sc::simple_state< Song2, Playing >
118     {
Song2test_sc::Song2119         Song2() { /*std::cout << "entering Song2" << std::endl;*/ } // entry
~Song2test_sc::Song2120         ~Song2() { /*std::cout << "leaving Song2" << std::endl;*/ } // exit
121         typedef mpl::list<
122             sc::transition< NextSong, Song3,
123             Playing, &Playing::start_next_song >,
124             sc::transition< PreviousSong, Song1,
125             Playing, &Playing::start_prev_song > > reactions;
126     };
127     struct Song3  : sc::simple_state< Song3, Playing >
128     {
Song3test_sc::Song3129         Song3() { /*std::cout << "entering Song3" << std::endl;*/ } // entry
~Song3test_sc::Song3130         ~Song3() { /*std::cout << "leaving Song3" << std::endl;*/ } // exit
131         typedef sc::transition< PreviousSong, Song2,
132             Playing, &Playing::start_prev_song > reactions;
133     };
134     struct Paused : sc::simple_state< Paused, player >
135     {
Pausedtest_sc::Paused136         Paused() { /*std::cout << "entering Paused" << std::endl;*/ } // entry
~Pausedtest_sc::Paused137         ~Paused() { /*std::cout << "leaving Paused" << std::endl;*/ } // exit
138         typedef mpl::list<
139             sc::transition< end_pause, Playing,
140             player, &player::resume_playback >,
141             sc::transition< stop, Stopped,
142             player, &player::stop_playback >,
143             sc::transition< open_close, Open,
144             player, &player::stop_and_open > > reactions;
145     };
146 }
147 
148 
149 #ifndef WIN32
mtime(struct timeval & tv1,struct timeval & tv2)150 long mtime(struct timeval& tv1,struct timeval& tv2)
151 {
152     return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
153 }
154 #endif
155 
main()156 int main()
157 {
158     test_sc::player p;
159     p.initiate();
160     // for timing
161 #ifdef WIN32
162     LARGE_INTEGER res;
163     ::QueryPerformanceFrequency(&res);
164     LARGE_INTEGER li,li2;
165     ::QueryPerformanceCounter(&li);
166 #else
167     struct timeval tv1,tv2;
168     gettimeofday(&tv1,NULL);
169 #endif
170 
171     for (int i=0;i<100;++i)
172     {
173         p.process_event(test_sc::open_close());
174         p.process_event(test_sc::open_close());
175         p.process_event(test_sc::cd_detected());
176         p.process_event(test_sc::play());
177         for (int j=0;j<100;++j)
178         {
179             p.process_event(test_sc::NextSong());
180             p.process_event(test_sc::NextSong());
181             p.process_event(test_sc::PreviousSong());
182             p.process_event(test_sc::PreviousSong());
183         }
184 
185         p.process_event(test_sc::pause());
186         // go back to Playing
187         p.process_event(test_sc::end_pause());
188         p.process_event(test_sc::pause());
189         p.process_event(test_sc::stop());
190         // event leading to the same state
191         p.process_event(test_sc::stop());
192         p.process_event(test_sc::open_close());
193         p.process_event(test_sc::open_close());
194     }
195 #ifdef WIN32
196     ::QueryPerformanceCounter(&li2);
197 #else
198     gettimeofday(&tv2,NULL);
199 #endif
200 #ifdef WIN32
201     std::cout << "sc took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
202 #else
203     std::cout << "sc took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
204 #endif
205     return 0;
206 }
207 
208