v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Modules Pages
time.h
1 /* -*- mode: C; c-basic-offset: 4; intent-tabs-mode: nil -*-
2  *
3  * Sifteo SDK
4  *
5  * Copyright <c> 2012 Sifteo, Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 
26 #pragma once
27 #ifdef NOT_USERSPACE
28 # error This is a userspace-only header, not allowed by the current build.
29 #endif
30 
31 #include <sifteo/macros.h>
32 #include <sifteo/abi.h>
33 
34 namespace Sifteo {
35 
36 class SystemTime;
37 
38 
58 class TimeDelta {
59 public:
60 
67  TimeDelta(float sec) : mMilli(sec * 1e3) {}
68  TimeDelta(double sec) : mMilli(sec * 1e3) {}
69 
77  static TimeDelta hz(float h) {
78  return TimeDelta(1.0f / h);
79  }
80 
84  static TimeDelta fromMillisec(int32_t m) {
85  return TimeDelta(m);
86  }
87 
91  int32_t milliseconds() const {
92  return mMilli;
93  }
94 
98  int64_t nanoseconds() const {
99  return mMilli * (int64_t)1000000;
100  }
101 
105  float seconds() const {
106  return mMilli * 1e-3;
107  }
108 
122  unsigned frames(TimeDelta duration) const {
123  ASSERT(!isNegative());
124  ASSERT(duration.isPositive());
125  return mMilli / duration.mMilli;
126  }
127 
142  unsigned pullFrames(TimeDelta duration) {
143  unsigned f = frames(duration);
144  // Could be "*this -= duration * f", but operator* isn't defined yet.
145  mMilli -= duration.mMilli * f;
146  return f;
147  }
148 
155  bool isNegative() const {
156  return mMilli < 0;
157  }
158 
160  bool isPositive() const {
161  return mMilli > 0;
162  }
163 
165  operator float() const { return seconds(); }
167  operator double() const { return seconds(); }
168  // Accumulate time from another TimeDelta
169  TimeDelta operator+= (TimeDelta b) { mMilli += b.mMilli; return *this; }
170  // Accumulate negative time from another TimeDelta
171  TimeDelta operator-= (TimeDelta b) { mMilli -= b.mMilli; return *this; }
172 
173 private:
174  friend class SystemTime;
175 
176  TimeDelta(int32_t m) : mMilli(m) {}
177  int32_t mMilli;
178 };
179 
180 inline bool operator== (TimeDelta a, TimeDelta b) { return a.milliseconds() == b.milliseconds(); }
181 inline bool operator!= (TimeDelta a, TimeDelta b) { return a.milliseconds() != b.milliseconds(); }
182 inline bool operator< (TimeDelta a, TimeDelta b) { return a.milliseconds() < b.milliseconds(); }
183 inline bool operator> (TimeDelta a, TimeDelta b) { return a.milliseconds() > b.milliseconds(); }
184 inline bool operator<= (TimeDelta a, TimeDelta b) { return a.milliseconds() <= b.milliseconds(); }
185 inline bool operator>= (TimeDelta a, TimeDelta b) { return a.milliseconds() >= b.milliseconds(); }
186 
187 inline bool operator== (TimeDelta a, float b) { return a.milliseconds() == TimeDelta(b).milliseconds(); }
188 inline bool operator!= (TimeDelta a, float b) { return a.milliseconds() != TimeDelta(b).milliseconds(); }
189 inline bool operator< (TimeDelta a, float b) { return a.milliseconds() < TimeDelta(b).milliseconds(); }
190 inline bool operator> (TimeDelta a, float b) { return a.milliseconds() > TimeDelta(b).milliseconds(); }
191 inline bool operator<= (TimeDelta a, float b) { return a.milliseconds() <= TimeDelta(b).milliseconds(); }
192 inline bool operator>= (TimeDelta a, float b) { return a.milliseconds() >= TimeDelta(b).milliseconds(); }
193 
194 inline bool operator== (float a, TimeDelta b) { return TimeDelta(a).milliseconds() == b.milliseconds(); }
195 inline bool operator!= (float a, TimeDelta b) { return TimeDelta(a).milliseconds() != b.milliseconds(); }
196 inline bool operator< (float a, TimeDelta b) { return TimeDelta(a).milliseconds() < b.milliseconds(); }
197 inline bool operator> (float a, TimeDelta b) { return TimeDelta(a).milliseconds() > b.milliseconds(); }
198 inline bool operator<= (float a, TimeDelta b) { return TimeDelta(a).milliseconds() <= b.milliseconds(); }
199 inline bool operator>= (float a, TimeDelta b) { return TimeDelta(a).milliseconds() >= b.milliseconds(); }
200 
201 inline bool operator== (TimeDelta a, double b) { return a.milliseconds() == TimeDelta(b).milliseconds(); }
202 inline bool operator!= (TimeDelta a, double b) { return a.milliseconds() != TimeDelta(b).milliseconds(); }
203 inline bool operator< (TimeDelta a, double b) { return a.milliseconds() < TimeDelta(b).milliseconds(); }
204 inline bool operator> (TimeDelta a, double b) { return a.milliseconds() > TimeDelta(b).milliseconds(); }
205 inline bool operator<= (TimeDelta a, double b) { return a.milliseconds() <= TimeDelta(b).milliseconds(); }
206 inline bool operator>= (TimeDelta a, double b) { return a.milliseconds() >= TimeDelta(b).milliseconds(); }
207 
208 inline bool operator== (double a, TimeDelta b) { return TimeDelta(a).milliseconds() == b.milliseconds(); }
209 inline bool operator!= (double a, TimeDelta b) { return TimeDelta(a).milliseconds() != b.milliseconds(); }
210 inline bool operator< (double a, TimeDelta b) { return TimeDelta(a).milliseconds() < b.milliseconds(); }
211 inline bool operator> (double a, TimeDelta b) { return TimeDelta(a).milliseconds() > b.milliseconds(); }
212 inline bool operator<= (double a, TimeDelta b) { return TimeDelta(a).milliseconds() <= b.milliseconds(); }
213 inline bool operator>= (double a, TimeDelta b) { return TimeDelta(a).milliseconds() >= b.milliseconds(); }
214 
215 inline TimeDelta operator+ (TimeDelta a, TimeDelta b) { return TimeDelta::fromMillisec(a.milliseconds() + b.milliseconds()); }
216 inline TimeDelta operator- (TimeDelta a, TimeDelta b) { return TimeDelta::fromMillisec(a.milliseconds() - b.milliseconds()); }
217 
218 inline TimeDelta operator* (TimeDelta a, float b) { return TimeDelta::fromMillisec(a.milliseconds() * b); }
219 inline TimeDelta operator* (TimeDelta a, double b) { return TimeDelta::fromMillisec(a.milliseconds() * b); }
220 inline TimeDelta operator* (TimeDelta a, int b) { return TimeDelta::fromMillisec(a.milliseconds() * b); }
221 inline TimeDelta operator* (TimeDelta a, unsigned b) { return TimeDelta::fromMillisec(a.milliseconds() * b); }
222 
223 inline TimeDelta operator* (float a, TimeDelta b) { return TimeDelta::fromMillisec(b.milliseconds() * a); }
224 inline TimeDelta operator* (double a, TimeDelta b) { return TimeDelta::fromMillisec(b.milliseconds() * a); }
225 inline TimeDelta operator* (int a, TimeDelta b) { return TimeDelta::fromMillisec(b.milliseconds() * a); }
226 inline TimeDelta operator* (unsigned a, TimeDelta b) { return TimeDelta::fromMillisec(b.milliseconds() * a); }
227 
228 inline float operator+= (float &a, TimeDelta b) { return a += b.seconds(); }
229 inline float operator-= (float &a, TimeDelta b) { return a -= b.seconds(); }
230 
231 
256 class SystemTime {
257 public:
264  SystemTime() : mTicks(0) {}
265 
269  static SystemTime now() {
270  return SystemTime(_SYS_ticks_ns());
271  }
272 
279  bool isValid() const {
280  return mTicks != 0;
281  }
282 
286  bool inFuture() const {
287  return mTicks > now().mTicks;
288  }
289 
293  bool inPast() const {
294  return mTicks < now().mTicks;
295  }
296 
300  uint64_t uptimeNS() const {
301  ASSERT(isValid());
302  return mTicks;
303  }
304 
308  uint64_t uptimeUS() const {
309  ASSERT(isValid());
310  return mTicks / (uint64_t)1000;
311  }
312 
316  uint64_t uptimeMS() const {
317  ASSERT(isValid());
318  return mTicks / (uint64_t)1000000;
319  }
320 
325  double uptime() const {
326  ASSERT(isValid());
327  return mTicks * 1e-9;
328  }
329 
340  ASSERT(period.milliseconds() > 0);
341  return TimeDelta((int32_t)(uptimeMS() % (uint64_t)period.milliseconds()));
342  }
343 
349  float cyclePhase(TimeDelta period) const {
350  return cycleDelta(period).milliseconds() / (float) period.milliseconds();
351  }
352 
360  unsigned cycleFrame(TimeDelta period, unsigned frames) const {
361  return cycleDelta(period).milliseconds() * frames / period.milliseconds();
362  }
363 
373  int64_t diff = uptimeNS() - b.uptimeNS();
374  return TimeDelta((int32_t)(diff / 1000000));
375  }
376 
377  SystemTime &operator+= (const TimeDelta &rhs) { mTicks += rhs.nanoseconds(); return *this; }
378  SystemTime &operator-= (const TimeDelta &rhs) { mTicks -= rhs.nanoseconds(); return *this; }
379 
380  SystemTime operator+ (TimeDelta b) const { return SystemTime(mTicks + b.nanoseconds()); }
381  SystemTime operator- (TimeDelta b) const { return SystemTime(mTicks - b.nanoseconds()); }
382 
383 private:
384  SystemTime(uint64_t t) : mTicks(t) {}
385  uint64_t mTicks;
386 };
387 
388 inline bool operator== (SystemTime a, SystemTime b) { return a.uptimeNS() == b.uptimeNS(); }
389 inline bool operator!= (SystemTime a, SystemTime b) { return a.uptimeNS() != b.uptimeNS(); }
390 inline bool operator< (SystemTime a, SystemTime b) { return a.uptimeNS() < b.uptimeNS(); }
391 inline bool operator> (SystemTime a, SystemTime b) { return a.uptimeNS() > b.uptimeNS(); }
392 inline bool operator<= (SystemTime a, SystemTime b) { return a.uptimeNS() <= b.uptimeNS(); }
393 inline bool operator>= (SystemTime a, SystemTime b) { return a.uptimeNS() >= b.uptimeNS(); }
394 
395 inline SystemTime operator+ (TimeDelta a, SystemTime b) { return b + a; }
396 inline SystemTime operator- (TimeDelta a, SystemTime b) { return b - a; }
397 
398 
412 class TimeStep {
413 public:
414  TimeStep() : mPrevTime(), mDelta(0.0) {}
415 
422  TimeDelta delta() const {
423  return mDelta;
424  }
425 
433  SystemTime end() const {
434  ASSERT(mPrevTime.isValid());
435  return mPrevTime;
436  }
437 
445  SystemTime begin() const {
446  ASSERT(mDelta != TimeDelta(0.0));
447  ASSERT(mPrevTime.isValid());
448  return mPrevTime - mDelta;
449  }
450 
457  void next() {
458  SystemTime now = SystemTime::now();
459 
460  if (mPrevTime.isValid()) {
461  // This subtraction loses sub-millisecond precision.
462  // We feed that error back into mPrevTime, so that it will
463  // be corrected instead of amplified.
464 
465  mDelta = now - mPrevTime;
466  mPrevTime += mDelta;
467 
468  } else {
469  // Beginning of the very first timestep
470  mPrevTime = now;
471  }
472  }
473 
474 private:
475  SystemTime mPrevTime;
476  TimeDelta mDelta;
477 };
478 
479 
495 class TimeTicker {
496 public:
497  TimeTicker() : mRemainder(0.0f), mPeriod(0.0) {}
498  TimeTicker(float hz) : mRemainder(0.0f), mPeriod(TimeDelta::hz(hz)) {}
499 
500  void setPeriod(TimeDelta period) {
501  mPeriod = period;
502  }
503 
504  void setRate(float hz) {
505  mPeriod = TimeDelta::hz(hz);
506  }
507 
508  unsigned tick(TimeDelta dt) {
509  ASSERT(!dt.isNegative());
510  mRemainder += dt;
511  return mRemainder.pullFrames(mPeriod);
512  }
513 
514  TimeDelta getPeriod() const {
515  return mPeriod;
516  }
517 
518 private:
519  TimeDelta mRemainder;
520  TimeDelta mPeriod;
521 };
522 
527 } // namespace Sifteo
528 
SystemTime()
Creates an invalid SystemTime.
Definition: time.h:264
int32_t milliseconds() const
Return the delta in milliseconds.
Definition: time.h:91
SystemTime end() const
Retrieve the SystemTime at the end of the interval described by delta().
Definition: time.h:433
uint64_t uptimeUS() const
Return the SystemTime as a count of microseconds since boot.
Definition: time.h:308
SystemTime begin() const
Retrieve the SystemTime at the beginning of the interval described by delta().
Definition: time.h:445
Represents a difference between two SystemTimes, with moderate resolution.
Definition: time.h:58
bool inFuture() const
Is this time in the future?
Definition: time.h:286
static SystemTime now()
Returns a new SystemTime representing the current system clock value.
Definition: time.h:269
void next()
Advance to the next time interval.
Definition: time.h:457
#define ASSERT(_x)
Runtime debug assertion.
Definition: macros.h:205
TimeDelta cycleDelta(TimeDelta period) const
Measure the amount of time since the beginning of a repeating cycle with arbitrary phase and the spec...
Definition: time.h:339
TimeStep is a higher-level utility for keeping track of time the duration of game timesteps...
Definition: time.h:412
unsigned pullFrames(TimeDelta duration)
Return a frame count, and subtract (pull) the time corresponding with those frames from this TimeDelt...
Definition: time.h:142
bool inPast() const
Is this time in the past?
Definition: time.h:293
bool isNegative() const
Is this time value negative?
Definition: time.h:155
double uptime() const
Return the SystemTime, in seconds since boot. Returns a double-precision floating point value...
Definition: time.h:325
bool isValid() const
Is this SystemTime valid?
Definition: time.h:279
bool isPositive() const
Is this time value positive?
Definition: time.h:160
int64_t nanoseconds() const
Return the delta in nanoseconds.
Definition: time.h:98
TimeDelta delta() const
Retrieve the duration of the last time interval.
Definition: time.h:422
TimeDelta(float sec)
Construct a new TimeDelta from a floating point time, in seconds.
Definition: time.h:67
uint64_t uptimeMS() const
Return the SystemTime as a count of milliseconds since boot.
Definition: time.h:316
unsigned frames(TimeDelta duration) const
Return the number of frames, of a particular duration, that are represented by this time delta...
Definition: time.h:122
float seconds() const
Return the delta in seconds, as a floating point value.
Definition: time.h:105
TimeTicker is a utility for converting a stream of time deltas into a stream of discrete ticks...
Definition: time.h:495
static TimeDelta hz(float h)
Construct a TimeDelta representing the period which corresponds with a given frequency.
Definition: time.h:77
Absolute time, measured by the system's monotonically increasing nanosecond timer.
Definition: time.h:256
Definition: array.h:34
static TimeDelta fromMillisec(int32_t m)
Construct a new TimeDelta from an integer time, in milliseconds.
Definition: time.h:84
unsigned cycleFrame(TimeDelta period, unsigned frames) const
Like cycleDelta(), but scales the result to the range [0, frames-1].
Definition: time.h:360
TimeDelta operator-(SystemTime b) const
Subtract two SystemTimes, and return a 32-bit TimeDelta, with millisecond resolution.
Definition: time.h:372
uint64_t uptimeNS() const
Return the SystemTime as a count of nanoseconds since boot.
Definition: time.h:300
float cyclePhase(TimeDelta period) const
Like cycleDelta(), but scales the result to the range [0,1], where 0 and 1 represent the beginning an...
Definition: time.h:349