v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Groups Pages
time.h
1 /* -*- mode: C; c-basic-offset: 4; intent-tabs-mode: nil -*-
2  *
3  * This file is part of the public interface to the Sifteo SDK.
4  * Copyright <c> 2012 Sifteo, Inc. All rights reserved.
5  */
6 
7 #pragma once
8 #ifdef NOT_USERSPACE
9 # error This is a userspace-only header, not allowed by the current build.
10 #endif
11 
12 #include <sifteo/macros.h>
13 #include <sifteo/abi.h>
14 
15 namespace Sifteo {
16 
17 class SystemTime;
18 
19 
39 class TimeDelta {
40 public:
41 
48  TimeDelta(float sec) : mMilli(sec * 1e3) {}
49  TimeDelta(double sec) : mMilli(sec * 1e3) {}
50 
58  static TimeDelta hz(float h) {
59  return TimeDelta(1.0f / h);
60  }
61 
65  static TimeDelta fromMillisec(int32_t m) {
66  return TimeDelta(m);
67  }
68 
72  int32_t milliseconds() const {
73  return mMilli;
74  }
75 
79  int64_t nanoseconds() const {
80  return mMilli * (int64_t)1000000;
81  }
82 
86  float seconds() const {
87  return mMilli * 1e-3;
88  }
89 
103  unsigned frames(TimeDelta duration) const {
104  ASSERT(!isNegative());
105  ASSERT(duration.isPositive());
106  return mMilli / duration.mMilli;
107  }
108 
123  unsigned pullFrames(TimeDelta duration) {
124  unsigned f = frames(duration);
125  // Could be "*this -= duration * f", but operator* isn't defined yet.
126  mMilli -= duration.mMilli * f;
127  return f;
128  }
129 
136  bool isNegative() const {
137  return mMilli < 0;
138  }
139 
141  bool isPositive() const {
142  return mMilli > 0;
143  }
144 
146  operator float() const { return seconds(); }
148  operator double() const { return seconds(); }
149  // Accumulate time from another TimeDelta
150  TimeDelta operator+= (TimeDelta b) { mMilli += b.mMilli; return *this; }
151  // Accumulate negative time from another TimeDelta
152  TimeDelta operator-= (TimeDelta b) { mMilli -= b.mMilli; return *this; }
153 
154 private:
155  friend class SystemTime;
156 
157  TimeDelta(int32_t m) : mMilli(m) {}
158  int32_t mMilli;
159 };
160 
161 inline bool operator== (TimeDelta a, TimeDelta b) { return a.milliseconds() == b.milliseconds(); }
162 inline bool operator!= (TimeDelta a, TimeDelta b) { return a.milliseconds() != b.milliseconds(); }
163 inline bool operator< (TimeDelta a, TimeDelta b) { return a.milliseconds() < b.milliseconds(); }
164 inline bool operator> (TimeDelta a, TimeDelta b) { return a.milliseconds() > b.milliseconds(); }
165 inline bool operator<= (TimeDelta a, TimeDelta b) { return a.milliseconds() <= b.milliseconds(); }
166 inline bool operator>= (TimeDelta a, TimeDelta b) { return a.milliseconds() >= b.milliseconds(); }
167 
168 inline bool operator== (TimeDelta a, float b) { return a.milliseconds() == TimeDelta(b).milliseconds(); }
169 inline bool operator!= (TimeDelta a, float b) { return a.milliseconds() != TimeDelta(b).milliseconds(); }
170 inline bool operator< (TimeDelta a, float b) { return a.milliseconds() < TimeDelta(b).milliseconds(); }
171 inline bool operator> (TimeDelta a, float b) { return a.milliseconds() > TimeDelta(b).milliseconds(); }
172 inline bool operator<= (TimeDelta a, float b) { return a.milliseconds() <= TimeDelta(b).milliseconds(); }
173 inline bool operator>= (TimeDelta a, float b) { return a.milliseconds() >= TimeDelta(b).milliseconds(); }
174 
175 inline bool operator== (float a, TimeDelta b) { return TimeDelta(a).milliseconds() == b.milliseconds(); }
176 inline bool operator!= (float a, TimeDelta b) { return TimeDelta(a).milliseconds() != b.milliseconds(); }
177 inline bool operator< (float a, TimeDelta b) { return TimeDelta(a).milliseconds() < b.milliseconds(); }
178 inline bool operator> (float a, TimeDelta b) { return TimeDelta(a).milliseconds() > b.milliseconds(); }
179 inline bool operator<= (float a, TimeDelta b) { return TimeDelta(a).milliseconds() <= b.milliseconds(); }
180 inline bool operator>= (float a, TimeDelta b) { return TimeDelta(a).milliseconds() >= b.milliseconds(); }
181 
182 inline bool operator== (TimeDelta a, double b) { return a.milliseconds() == TimeDelta(b).milliseconds(); }
183 inline bool operator!= (TimeDelta a, double b) { return a.milliseconds() != TimeDelta(b).milliseconds(); }
184 inline bool operator< (TimeDelta a, double b) { return a.milliseconds() < TimeDelta(b).milliseconds(); }
185 inline bool operator> (TimeDelta a, double b) { return a.milliseconds() > TimeDelta(b).milliseconds(); }
186 inline bool operator<= (TimeDelta a, double b) { return a.milliseconds() <= TimeDelta(b).milliseconds(); }
187 inline bool operator>= (TimeDelta a, double b) { return a.milliseconds() >= TimeDelta(b).milliseconds(); }
188 
189 inline bool operator== (double a, TimeDelta b) { return TimeDelta(a).milliseconds() == b.milliseconds(); }
190 inline bool operator!= (double a, TimeDelta b) { return TimeDelta(a).milliseconds() != b.milliseconds(); }
191 inline bool operator< (double a, TimeDelta b) { return TimeDelta(a).milliseconds() < b.milliseconds(); }
192 inline bool operator> (double a, TimeDelta b) { return TimeDelta(a).milliseconds() > b.milliseconds(); }
193 inline bool operator<= (double a, TimeDelta b) { return TimeDelta(a).milliseconds() <= b.milliseconds(); }
194 inline bool operator>= (double a, TimeDelta b) { return TimeDelta(a).milliseconds() >= b.milliseconds(); }
195 
196 inline TimeDelta operator+ (TimeDelta a, TimeDelta b) { return TimeDelta::fromMillisec(a.milliseconds() + b.milliseconds()); }
197 inline TimeDelta operator- (TimeDelta a, TimeDelta b) { return TimeDelta::fromMillisec(a.milliseconds() - b.milliseconds()); }
198 
199 inline TimeDelta operator* (TimeDelta a, float b) { return TimeDelta::fromMillisec(a.milliseconds() * b); }
200 inline TimeDelta operator* (TimeDelta a, double b) { return TimeDelta::fromMillisec(a.milliseconds() * b); }
201 inline TimeDelta operator* (TimeDelta a, int b) { return TimeDelta::fromMillisec(a.milliseconds() * b); }
202 inline TimeDelta operator* (TimeDelta a, unsigned b) { return TimeDelta::fromMillisec(a.milliseconds() * b); }
203 
204 inline TimeDelta operator* (float a, TimeDelta b) { return TimeDelta::fromMillisec(b.milliseconds() * a); }
205 inline TimeDelta operator* (double a, TimeDelta b) { return TimeDelta::fromMillisec(b.milliseconds() * a); }
206 inline TimeDelta operator* (int a, TimeDelta b) { return TimeDelta::fromMillisec(b.milliseconds() * a); }
207 inline TimeDelta operator* (unsigned a, TimeDelta b) { return TimeDelta::fromMillisec(b.milliseconds() * a); }
208 
209 inline float operator+= (float &a, TimeDelta b) { return a += b.seconds(); }
210 inline float operator-= (float &a, TimeDelta b) { return a -= b.seconds(); }
211 
212 
237 class SystemTime {
238 public:
245  SystemTime() : mTicks(0) {}
246 
250  static SystemTime now() {
251  return SystemTime(_SYS_ticks_ns());
252  }
253 
260  bool isValid() const {
261  return mTicks != 0;
262  }
263 
267  bool inFuture() const {
268  return mTicks > now().mTicks;
269  }
270 
274  bool inPast() const {
275  return mTicks < now().mTicks;
276  }
277 
281  uint64_t uptimeNS() const {
282  ASSERT(isValid());
283  return mTicks;
284  }
285 
289  uint64_t uptimeUS() const {
290  ASSERT(isValid());
291  return mTicks / (uint64_t)1000;
292  }
293 
297  uint64_t uptimeMS() const {
298  ASSERT(isValid());
299  return mTicks / (uint64_t)1000000;
300  }
301 
306  double uptime() const {
307  ASSERT(isValid());
308  return mTicks * 1e-9;
309  }
310 
321  ASSERT(period.milliseconds() > 0);
322  return TimeDelta((int32_t)(uptimeMS() % (uint64_t)period.milliseconds()));
323  }
324 
330  float cyclePhase(TimeDelta period) const {
331  return cycleDelta(period).milliseconds() / (float) period.milliseconds();
332  }
333 
341  unsigned cycleFrame(TimeDelta period, unsigned frames) const {
342  return cycleDelta(period).milliseconds() * frames / period.milliseconds();
343  }
344 
354  int64_t diff = uptimeNS() - b.uptimeNS();
355  return TimeDelta((int32_t)(diff / 1000000));
356  }
357 
358  SystemTime &operator+= (const TimeDelta &rhs) { mTicks += rhs.nanoseconds(); return *this; }
359  SystemTime &operator-= (const TimeDelta &rhs) { mTicks -= rhs.nanoseconds(); return *this; }
360 
361  SystemTime operator+ (TimeDelta b) const { return SystemTime(mTicks + b.nanoseconds()); }
362  SystemTime operator- (TimeDelta b) const { return SystemTime(mTicks - b.nanoseconds()); }
363 
364 private:
365  SystemTime(uint64_t t) : mTicks(t) {}
366  uint64_t mTicks;
367 };
368 
369 inline bool operator== (SystemTime a, SystemTime b) { return a.uptimeNS() == b.uptimeNS(); }
370 inline bool operator!= (SystemTime a, SystemTime b) { return a.uptimeNS() != b.uptimeNS(); }
371 inline bool operator< (SystemTime a, SystemTime b) { return a.uptimeNS() < b.uptimeNS(); }
372 inline bool operator> (SystemTime a, SystemTime b) { return a.uptimeNS() > b.uptimeNS(); }
373 inline bool operator<= (SystemTime a, SystemTime b) { return a.uptimeNS() <= b.uptimeNS(); }
374 inline bool operator>= (SystemTime a, SystemTime b) { return a.uptimeNS() >= b.uptimeNS(); }
375 
376 inline SystemTime operator+ (TimeDelta a, SystemTime b) { return b + a; }
377 inline SystemTime operator- (TimeDelta a, SystemTime b) { return b - a; }
378 
379 
393 class TimeStep {
394 public:
395  TimeStep() : mPrevTime(), mDelta(0.0) {}
396 
403  TimeDelta delta() const {
404  return mDelta;
405  }
406 
414  SystemTime end() const {
415  ASSERT(mPrevTime.isValid());
416  return mPrevTime;
417  }
418 
426  SystemTime begin() const {
427  ASSERT(mDelta != TimeDelta(0.0));
428  ASSERT(mPrevTime.isValid());
429  return mPrevTime - mDelta;
430  }
431 
438  void next() {
439  SystemTime now = SystemTime::now();
440 
441  if (mPrevTime.isValid()) {
442  // This subtraction loses sub-millisecond precision.
443  // We feed that error back into mPrevTime, so that it will
444  // be corrected instead of amplified.
445 
446  mDelta = now - mPrevTime;
447  mPrevTime += mDelta;
448 
449  } else {
450  // Beginning of the very first timestep
451  mPrevTime = now;
452  }
453  }
454 
455 private:
456  SystemTime mPrevTime;
457  TimeDelta mDelta;
458 };
459 
460 
476 class TimeTicker {
477 public:
478  TimeTicker() : mRemainder(0.0f), mPeriod(0.0) {}
479  TimeTicker(float hz) : mRemainder(0.0f), mPeriod(TimeDelta::hz(hz)) {}
480 
481  void setPeriod(TimeDelta period) {
482  mPeriod = period;
483  }
484 
485  void setRate(float hz) {
486  mPeriod = TimeDelta::hz(hz);
487  }
488 
489  unsigned tick(TimeDelta dt) {
490  ASSERT(!dt.isNegative());
491  mRemainder += dt;
492  return mRemainder.pullFrames(mPeriod);
493  }
494 
495  TimeDelta getPeriod() const {
496  return mPeriod;
497  }
498 
499 private:
500  TimeDelta mRemainder;
501  TimeDelta mPeriod;
502 };
503 
508 } // namespace Sifteo
509