]> Dogcows Code - chaz/yoink/blob - src/moof/timer.hh
edd1de2deaf2cab1a98eff1502dffb0802efed86
[chaz/yoink] / src / moof / timer.hh
1
2 /*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
3 **] All rights reserved.
4 *
5 * Distributable under the terms and conditions of the 2-clause BSD license;
6 * see the file COPYING for a complete text of the license.
7 *
8 *****************************************************************************/
9
10 #ifndef _MOOF_TIMER_HH_
11 #define _MOOF_TIMER_HH_
12
13 /**
14 * \file timer.hh
15 * Functions for measuring time in a friendly unit.
16 */
17
18 #include <boost/bind.hpp>
19 #include <boost/function.hpp>
20 #include <boost/noncopyable.hpp>
21
22 #include <moof/hash.hh>
23 #include <moof/math.hh>
24
25
26 namespace moof {
27
28
29 // forward declarations
30 class runloop;
31
32 /**
33 * A timer source is an object that keeps track of increasing time in units
34 * of seconds. A timer source does not necessarily have to increment at
35 * the same rate or in the same way as the real time. The time source must
36 * begin at zero and always remain the same or increase each time the time
37 * is queried.
38 */
39 class timer_source
40 {
41 public:
42
43 /**
44 * Deconstruct a timer source.
45 */
46 virtual ~timer_source() {}
47
48 /**
49 * Get the number seconds since the timer source was created or reset.
50 */
51 virtual scalar ticks() const = 0;
52
53 /**
54 * Reset the timer such that the current time will become zero.
55 */
56 virtual void reset() = 0;
57
58 /**
59 * Scale the time. After calling this, the timer source should either
60 * increment faster or slower, depending on the scale factor.
61 */
62 virtual void scale(scalar factor) = 0;
63 };
64
65
66 /**
67 * A class to represent a timer for scheduled events. The timer events
68 * will be executed on or sometime after their schedculed time. The
69 * runloop associated with the current running view will make an attempt to
70 * fire any expired timers as close to their scheduled times as possible.
71 */
72 class timer : public boost::noncopyable
73 {
74 public:
75
76 /**
77 * A type for the state of a timer.
78 */
79 enum mode
80 {
81 invalid = 0, /// Timer is not scheduled.
82 relative = 1, /// Timer is scheduled by a relative time.
83 absolute = 2, /// Timer is scheduled by an absolute time.
84 repeat = 3 /// Timer is scheduled by a periodic time.
85 };
86
87 /**
88 * Function protocol for a timer event handler. A function matching
89 * this protocol will be called when the timer expires. The function
90 * takes two parameters: the timer object that just expired, and the
91 * absolute time of the time source which caused the timer to expire.
92 */
93 typedef boost::function<void(timer&,scalar)> function;
94
95 /**
96 * Construct an invalid (uninitialized) timer.
97 */
98 timer() :
99 mode_(invalid),
100 absolute_(SCALAR(0.0)),
101 runloop_(0) {}
102
103 /**
104 * Construct a scheduled timer.
105 * \param function The event handler.
106 * \param seconds The number of seconds; the meaning of this depends on
107 * the mode of the timer.
108 * \param mode The timer mode. If the mode is relative (default), the
109 * seconds parameter is the number of seconds from the current time to
110 * wait before expiring the timer. If the mode is absolute, the
111 * seconds parameter is the number of seconds from some arbitrary,
112 * fixed time in the past. If the mode is repeat, the seconds
113 * parameter is the number of seconds from now to wait before expiring
114 * the timer, at which time the timer will be rescheduled to expired
115 * again at that many seconds from the expiration time. A repeating
116 * timer can be invalidated manually using invalidate().
117 */
118 timer(const function& function,
119 scalar seconds,
120 mode mode = relative,
121 timer_source& source = default_source()) :
122 runloop_(0)
123 {
124 init(function, seconds, mode, source);
125 }
126
127 /**
128 * Deconstruct a timer. This will automagically invalidate the timer,
129 * so it will not expire or fire an event.
130 */
131 ~timer();
132
133 /**
134 * Initialize a timer with a scheduled time. If the timer is already
135 * scheduled, its prior schedule will be invalidated and replaced by
136 * this new schedule.
137 * \param function The event handler.
138 * \param seconds The number of seconds; the meaning of this depends on
139 * the mode of the timer.
140 * \param mode The timer mode. If the mode is relative (default), the
141 * seconds parameter is the number of seconds from the current time to
142 * wait before expiring the timer. If the mode is absolute, the
143 * seconds parameter is the number of seconds from some arbitrary,
144 * fixed time in the past. If the mode is repeat, the seconds
145 * parameter is the number of seconds from now to wait before expiring
146 * the timer, at which time the timer will be rescheduled to expired
147 * again at that many seconds from the expiration time. A repeating
148 * timer can be invalidated manually using invalidate().
149 */
150 void init(const function& function,
151 scalar seconds,
152 enum mode mode = relative,
153 timer_source& source = default_source());
154
155 /**
156 * Manually invalidated the timer, removing any schedule such that the
157 * timer will not expired and no event will be fired.
158 */
159 void invalidate();
160
161 enum mode mode() const
162 {
163 return mode_;
164 }
165
166 /**
167 * Manually fire the timer event. Usually, the timer event will be
168 * fired when the timer expires, but this can be used to fire it
169 * prematurely. If the timer is scheduled, it will be invalidated. If
170 * the timer is already invalid (but is initialized with an event
171 * handler), the event will be fired and the timer will remain invalid.
172 * \param t The absolute time passed to the timer event function.
173 */
174 void fire(scalar t);
175 void fire()
176 {
177 fire(source_->ticks());
178 }
179
180 /**
181 * Fire the timer event if it is expired.
182 * \param t The absolute time used as a reference to determine if the
183 * timer is expired; defaults to the current time.
184 * \return The absolute time of the next expiration (if repeating), or
185 * 0.0 otherwise.
186 */
187 bool fire_if_expired(scalar t)
188 {
189 if (is_expired(t))
190 {
191 fire(t);
192 return true;
193 }
194 return false;
195 }
196 bool fire_if_expired()
197 {
198 return fire_if_expired(source_->ticks());
199 }
200
201 /**
202 * Get the absolute time of the next expiration of this timer.
203 * \return Seconds.
204 */
205 scalar expiration() const
206 {
207 return absolute_;
208 }
209
210 /**
211 * Get the number of seconds remaining before the timer is scheduled to
212 * expired. If the timer is invalid, the retured value will be
213 * negative.
214 * \param t The absolute time used as a reference to determine the
215 * amount of time left; defaults to the current time.
216 * \return Seconds.
217 */
218 scalar remaining(scalar t) const
219 {
220 return expiration() - t;
221 }
222 scalar remaining() const
223 {
224 return remaining(source_->ticks());
225 }
226
227 /**
228 * Get whether or not the timer is expired. A timer on a repeating
229 * schedule will never be expired since it will always have a scheduled
230 * expiration time in the future. If the timer is expired but not
231 * invalid, the timer event has not yet fired; the timer will be
232 * invalidated when it does fire.
233 * \param t The absolute time used as a reference to determine if the
234 * timer is expired; defaults to the current time.
235 * \return True if the timer is expired, false otherwise.
236 */
237 bool is_expired(scalar t) const
238 {
239 return remaining(t) < SCALAR(0.0);
240 }
241 bool is_expired() const
242 {
243 return is_expired(source_->ticks());
244 }
245
246 static timer_source& default_source();
247
248 /**
249 * Get the number of real seconds since the default timer was first
250 * created or last reset.
251 * \return Seconds.
252 */
253 static scalar ticks();
254
255 /**
256 * Put the thread to sleep for a certain period of time. If absolute
257 * is true, then it will sleep until the default timer reaches the
258 * specified number of seconds. If the mode is relative, the thread
259 * will sleep for that many seconds. Unlike system sleep functions,
260 * this one automatically resumes sleep if sleep was interrupted by a
261 * signal. Therefore, calling this function is guaranteed to sleep for
262 * at least the requested amount of time.
263 * \param seconds Number of seconds.
264 * \param mode The timer mode.
265 */
266 static void sleep(scalar seconds, enum mode mode = relative);
267
268 private:
269
270 void added_to_runloop(runloop& runloop);
271 void detach_from_runloop();
272
273 function function_;
274 enum mode mode_;
275 scalar absolute_;
276 scalar interval_;
277 timer_source* source_;
278 runloop* runloop_;
279 };
280
281
282 class game_time : public timer_source
283 {
284 public:
285
286 game_time(scalar timestep = SCALAR(1.0)) :
287 scale_(timestep),
288 scalefactor_(SCALAR(1.0))
289 {
290 reset(timestep);
291 }
292
293 scalar ticks() const
294 {
295 return reference_ + scalar(ticks_) * scale_;
296 }
297
298 void reset()
299 {
300 reference_ = SCALAR(0.0);
301 ticks_ = 0;
302 }
303 void reset(scalar timestep)
304 {
305 reset();
306 timestep_ = timestep;
307 scale_ = timestep_ * scalefactor_;
308 }
309
310 void scale(scalar factor)
311 {
312 reference_ = ticks();
313 ticks_ = 0;
314 scale_ = timestep_ * factor;
315 scalefactor_ = factor;
316 }
317
318 scalar step(unsigned step = 1)
319 {
320 ticks_ += step;
321 return scale_;
322 }
323
324 private:
325
326 scalar reference_;
327 unsigned ticks_;
328 scalar timestep_;
329 scalar scale_;
330 scalar scalefactor_;
331 };
332
333
334 } // namespace moof
335
336 #endif // _MOOF_TIMER_HH_
337
This page took 0.050815 seconds and 3 git commands to generate.