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