1 //////////////////////////////////////////////////////////////////////////////
2 // Copyright 2002-2006 Andreas Huber Doenni
3 // Distributed under the Boost Software License, Version 1.0. (See accompany-
4 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 //////////////////////////////////////////////////////////////////////////////
6 
7 
8 
9 //////////////////////////////////////////////////////////////////////////////
10 // The following code implements the state-machine (this version details an
11 // alternative way of retrieving the elapsed time from the main program):
12 //
13 //  --------------------------------
14 // |                                |
15 // |           O     Active         |
16 // |           |                    |<----
17 // |           v                    |     | EvReset
18 // |  ----------------------------  |     |
19 // | |                            | |-----
20 // | |         Stopped            | |
21 // |  ----------------------------  |
22 // |  |              ^              |
23 // |  | EvStartStop  | EvStartStop  |<-----O
24 // |  v              |              |
25 // |  ----------------------------  |
26 // | |                            | |
27 // | |         Running            | |
28 // |  ----------------------------  |
29 //  --------------------------------
30 
31 
32 
33 #include <boost/statechart/event.hpp>
34 #include <boost/statechart/state_machine.hpp>
35 #include <boost/statechart/simple_state.hpp>
36 #include <boost/statechart/transition.hpp>
37 #include <boost/statechart/custom_reaction.hpp>
38 
39 #include <boost/mpl/list.hpp>
40 
41 #include <boost/config.hpp>
42 
43 #include <ctime>
44 #include <iostream>
45 
46 #ifdef BOOST_NO_STDC_NAMESPACE
47 namespace std
48 {
49   using ::time;
50   using ::difftime;
51   using ::time_t;
52 }
53 #endif
54 
55 #ifdef BOOST_INTEL
56 #  pragma warning( disable: 304 ) // access control not specified
57 #  pragma warning( disable: 444 ) // destructor for base is not virtual
58 #  pragma warning( disable: 981 ) // operands are evaluated in unspecified order
59 #endif
60 
61 
62 
63 namespace sc = boost::statechart;
64 namespace mpl = boost::mpl;
65 
66 
67 
68 struct EvStartStop : sc::event< EvStartStop > {};
69 struct EvReset : sc::event< EvReset > {};
70 struct EvGetElapsedTime : sc::event< EvGetElapsedTime >
71 {
72   public:
EvGetElapsedTimeEvGetElapsedTime73     EvGetElapsedTime( double & time ) : time_( time ) {}
74 
AssignEvGetElapsedTime75     void Assign( double time ) const
76     {
77       time_ = time;
78     }
79 
80   private:
81     double & time_;
82 };
83 
84 
85 struct Active;
86 struct StopWatch : sc::state_machine< StopWatch, Active > {};
87 
88 
89 struct Stopped;
90 struct Active : sc::simple_state< Active, StopWatch, Stopped >
91 {
92   public:
93     typedef sc::transition< EvReset, Active > reactions;
94 
ActiveActive95     Active() : elapsedTime_( 0.0 ) {}
96 
ElapsedTimeActive97     double & ElapsedTime()
98     {
99       return elapsedTime_;
100     }
101 
ElapsedTimeActive102     double ElapsedTime() const
103     {
104       return elapsedTime_;
105     }
106 
107   private:
108     double elapsedTime_;
109 };
110 
111 struct Running : sc::simple_state< Running, Active >
112 {
113   public:
114     typedef mpl::list<
115       sc::custom_reaction< EvGetElapsedTime >,
116       sc::transition< EvStartStop, Stopped >
117     > reactions;
118 
RunningRunning119     Running() : startTime_( std::time( 0 ) ) {}
120 
~RunningRunning121     ~Running()
122     {
123       context< Active >().ElapsedTime() = ElapsedTime();
124     }
125 
reactRunning126     sc::result react( const EvGetElapsedTime & evt )
127     {
128       evt.Assign( ElapsedTime() );
129       return discard_event();
130     }
131 
132   private:
ElapsedTimeRunning133     double ElapsedTime() const
134     {
135       return context< Active >().ElapsedTime() +
136         std::difftime( std::time( 0 ), startTime_ );
137     }
138 
139     std::time_t startTime_;
140 };
141 
142 struct Stopped : sc::simple_state< Stopped, Active >
143 {
144   typedef mpl::list<
145     sc::custom_reaction< EvGetElapsedTime >,
146     sc::transition< EvStartStop, Running >
147   > reactions;
148 
reactStopped149   sc::result react( const EvGetElapsedTime & evt )
150   {
151     evt.Assign( context< Active >().ElapsedTime() );
152     return discard_event();
153   }
154 };
155 
156 
157 namespace
158 {
GetKey()159   char GetKey()
160   {
161     char key;
162     std::cin >> key;
163     return key;
164   }
165 }
166 
main()167 int main()
168 {
169   std::cout << "Boost.Statechart StopWatch example\n\n";
170   std::cout << "s<CR>: Starts/Stops stop watch\n";
171   std::cout << "r<CR>: Resets stop watch\n";
172   std::cout << "d<CR>: Displays the elapsed time in seconds\n";
173   std::cout << "e<CR>: Exits the program\n\n";
174   std::cout << "You may chain commands, e.g. rs<CR> resets and starts stop watch\n\n";
175 
176   StopWatch stopWatch;
177   stopWatch.initiate();
178 
179   char key = GetKey();
180 
181   while ( key != 'e' )
182   {
183     switch( key )
184     {
185       case 'r':
186       {
187         stopWatch.process_event( EvReset() );
188       }
189       break;
190 
191       case 's':
192       {
193         stopWatch.process_event( EvStartStop() );
194       }
195       break;
196 
197       case 'd':
198       {
199         double elapsedTime = 0.0;
200         stopWatch.process_event( EvGetElapsedTime( elapsedTime ) );
201         std::cout << "Elapsed time: " << elapsedTime << "\n";
202       }
203       break;
204 
205       default:
206       {
207         std::cout << "Invalid key!\n";
208       }
209       break;
210     }
211 
212     key = GetKey();
213   }
214 
215   return 0;
216 }
217