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