Open Lighting Architecture
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Clock.h
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15  *
16  * Clock.h
17  * Provides the TimeInterval and TimeStamp classes.
18  * Copyright (C) 2005-2012 Simon Newton
19  *
20  * The struct timeval can represent both absolute time and time intervals.
21  * We define our own wrapper classes that:
22  * - hide some of the platform differences, like the fact windows doesn't
23  * provide timersub.
24  * - Reduces bugs by using the compiler to check if the value was supposed
25  * to be an interval or absolute time. For example, passing an absolute
26  * time intstead of an Interval to RegisterTimeout would be bad.
27  */
28 
29 #ifndef INCLUDE_OLA_CLOCK_H_
30 #define INCLUDE_OLA_CLOCK_H_
31 
32 #if HAVE_CONFIG_H
33 # include <config.h>
34 #endif
35 
36 #include <stdint.h>
37 #include <sys/time.h>
38 
39 #include <iomanip>
40 #include <ostream>
41 #include <sstream>
42 #include <string>
43 
44 namespace ola {
45 
46 using std::ostream;
47 
48 static const int USEC_IN_SECONDS = 1000000;
49 static const int ONE_THOUSAND = 1000;
50 
55 class BaseTimeVal {
56  public:
57  // Constructors
58  BaseTimeVal() { timerclear(&m_tv); }
59 
60  BaseTimeVal(int32_t sec, int32_t usec) {
61  m_tv.tv_sec = sec;
62  m_tv.tv_usec = usec;
63  }
64 
65  explicit BaseTimeVal(const struct timeval &timestamp) { m_tv = timestamp; }
66  explicit BaseTimeVal(int64_t interval_useconds) { Set(interval_useconds); }
67 
68  BaseTimeVal(const BaseTimeVal &other) : m_tv(other.m_tv) {}
69 
70  // Assignable
71  BaseTimeVal& operator=(const BaseTimeVal& other) {
72  if (this != &other) {
73  m_tv = other.m_tv;
74  }
75  return *this;
76  }
77 
78  BaseTimeVal& operator=(const struct timeval &tv) {
79  m_tv = tv;
80  return *this;
81  }
82 
83  // Comparables
84  bool operator==(const BaseTimeVal &other) const {
85  return timercmp(&m_tv, &other.m_tv, ==);
86  }
87 
88  bool operator!=(const BaseTimeVal &other) const {
89  return !(*this == other);
90  }
91 
92  bool operator>(const BaseTimeVal &other) const {
93  return timercmp(&m_tv, &other.m_tv, >);
94  }
95 
96  bool operator>=(const BaseTimeVal &other) const {
97  return timercmp(&m_tv, &other.m_tv, >=);
98  }
99 
100  bool operator<(const BaseTimeVal &other) const {
101  return timercmp(&m_tv, &other.m_tv, <);
102  }
103 
104  bool operator<=(const BaseTimeVal &other) const {
105  return timercmp(&m_tv, &other.m_tv, <=);
106  }
107 
108  // Arithmetic
109  BaseTimeVal& operator+=(const BaseTimeVal& other) {
110  if (this != &other) {
111  timeradd(&m_tv, &other.m_tv, &m_tv);
112  }
113  return *this;
114  }
115 
116  BaseTimeVal &operator-=(const BaseTimeVal &other) {
117  if (this != &other) {
118  TimerSub(m_tv, other.m_tv, &m_tv);
119  }
120  return *this;
121  }
122 
123  const BaseTimeVal operator+(const BaseTimeVal &interval) const {
124  BaseTimeVal result = *this;
125  result += interval;
126  return result;
127  }
128 
129  const BaseTimeVal operator-(const BaseTimeVal &other) const {
130  BaseTimeVal result;
131  TimerSub(m_tv, other.m_tv, &result.m_tv);
132  return result;
133  }
134 
135  BaseTimeVal operator*(unsigned int i) const {
136  int64_t as_int = (*this).AsInt();
137  as_int *= i;
138  return BaseTimeVal(as_int);
139  }
140 
141  // Various other methods.
142  bool IsSet() const {
143  return timerisset(&m_tv);
144  }
145 
146  void AsTimeval(struct timeval *tv) const {
147  *tv = m_tv;
148  }
149 
150  // Returns the seconds portion.
151  time_t Seconds() const { return m_tv.tv_sec; }
152  // Returns the microseconds portion
153  suseconds_t MicroSeconds() const { return m_tv.tv_usec; }
154 
155  // Returns the entire BaseTimeVal as milliseconds
156  int64_t InMilliSeconds() const {
157  return (m_tv.tv_sec * static_cast<int64_t>(ONE_THOUSAND) +
158  m_tv.tv_usec / ONE_THOUSAND);
159  }
160 
161  // Returns the entire BaseTimeVal as microseconds.
162  int64_t AsInt() const {
163  return (m_tv.tv_sec * static_cast<int64_t>(USEC_IN_SECONDS) +
164  m_tv.tv_usec);
165  }
166 
167  std::string ToString() const {
168  std::stringstream str;
169  str << m_tv.tv_sec << "." << std::setfill('0') << std::setw(6)
170  << m_tv.tv_usec;
171  return str.str();
172  }
173 
174  private:
175  struct timeval m_tv;
176 
180  void TimerSub(const struct timeval &tv1, const struct timeval &tv2,
181  struct timeval *result) const {
182  result->tv_sec = tv1.tv_sec - tv2.tv_sec;
183  result->tv_usec = tv1.tv_usec - tv2.tv_usec;
184  if (result->tv_usec < 0) {
185  result->tv_sec--;
186  result->tv_usec += USEC_IN_SECONDS;
187  }
188  }
189 
190  void Set(int64_t interval_useconds) {
191 #ifdef HAVE_TIME_T
192  m_tv.tv_sec = static_cast<time_t>(
193  interval_useconds / USEC_IN_SECONDS);
194 #else
195  m_tv.tv_sec = interval_useconds / USEC_IN_SECONDS;
196 #endif
197 
198 #ifdef HAVE_SUSECONDS_T
199  m_tv.tv_usec = static_cast<suseconds_t>(
200  interval_useconds % USEC_IN_SECONDS);
201 #else
202  m_tv.tv_usec = interval_useconds % USEC_IN_SECONDS;
203 #endif
204  }
205 };
206 
207 /*
208  * A time interval, with usecond accuracy.
209  */
211  public:
212  // Constructors
213  TimeInterval() {}
214  TimeInterval(int32_t sec, int32_t usec) : m_interval(sec, usec) {}
215  explicit TimeInterval(int64_t usec) : m_interval(usec) {}
216 
217  TimeInterval(const TimeInterval &other) : m_interval(other.m_interval) {}
218 
219  // Assignable
220  TimeInterval& operator=(const TimeInterval& other) {
221  if (this != &other) {
222  m_interval = other.m_interval;
223  }
224  return *this;
225  }
226 
227  // Comparables
228  bool operator==(const TimeInterval &other) const {
229  return m_interval == other.m_interval;
230  }
231 
232  bool operator!=(const TimeInterval &other) const {
233  return m_interval != other.m_interval;
234  }
235 
236  bool operator>(const TimeInterval &other) const {
237  return m_interval > other.m_interval;
238  }
239 
240  bool operator>=(const TimeInterval &other) const {
241  return m_interval >= other.m_interval;
242  }
243 
244  bool operator<(const TimeInterval &other) const {
245  return m_interval < other.m_interval;
246  }
247 
248  bool operator<=(const TimeInterval &other) const {
249  return m_interval <= other.m_interval;
250  }
251 
252  // Arithmetic
253  TimeInterval& operator+=(const TimeInterval& other) {
254  if (this != &other) {
255  m_interval += other.m_interval;
256  }
257  return *this;
258  }
259 
260  TimeInterval operator*(unsigned int i) const {
261  return TimeInterval(m_interval * i);
262  }
263 
264  // Various other methods.
265  void AsTimeval(struct timeval *tv) const { m_interval.AsTimeval(tv); }
266 
267  time_t Seconds() const { return m_interval.Seconds(); }
268  suseconds_t MicroSeconds() const { return m_interval.MicroSeconds(); }
269 
270  int64_t InMilliSeconds() const { return m_interval.InMilliSeconds(); }
271  int64_t AsInt() const { return m_interval.AsInt(); }
272 
273  std::string ToString() const { return m_interval.ToString(); }
274 
275  friend ostream& operator<< (ostream &out, const TimeInterval &interval) {
276  return out << interval.m_interval.ToString();
277  }
278 
279  private:
280  explicit TimeInterval(const BaseTimeVal &time_val) : m_interval(time_val) {}
281 
282  BaseTimeVal m_interval;
283  friend class TimeStamp;
284 };
285 
286 
287 /*
288  * Represents a point in time with usecond accuracy.
289  */
290 class TimeStamp {
291  public:
292  // Constructors
293  TimeStamp() {}
294  explicit TimeStamp(const struct timeval &timestamp) : m_tv(timestamp) {}
295 
296  TimeStamp(const TimeStamp &other) : m_tv(other.m_tv) {}
297 
298  // Assignable
299  TimeStamp& operator=(const TimeStamp& other) {
300  if (this != &other) {
301  m_tv = other.m_tv;
302  }
303  return *this;
304  }
305 
306  TimeStamp& operator=(const struct timeval &tv) {
307  m_tv = tv;
308  return *this;
309  }
310 
311  // Comparables
312  bool operator==(const TimeStamp &other) const { return m_tv == other.m_tv; }
313  bool operator!=(const TimeStamp &other) const { return m_tv != other.m_tv; }
314  bool operator>(const TimeStamp &other) const { return m_tv > other.m_tv; }
315  bool operator>=(const TimeStamp &other) const { return m_tv >= other.m_tv; }
316  bool operator<(const TimeStamp &other) const { return m_tv < other.m_tv; }
317  bool operator<=(const TimeStamp &other) const { return m_tv <= other.m_tv; }
318 
319  // Arithmetic
320  TimeStamp &operator+=(const TimeInterval &interval) {
321  m_tv += interval.m_interval;
322  return *this;
323  }
324 
325  TimeStamp &operator-=(const TimeInterval &interval) {
326  m_tv -= interval.m_interval;
327  return *this;
328  }
329 
330  const TimeStamp operator+(const TimeInterval &interval) const {
331  return TimeStamp(m_tv + interval.m_interval);
332  }
333 
334  const TimeInterval operator-(const TimeStamp &other) const {
335  return TimeInterval(m_tv - other.m_tv);
336  }
337 
338  const TimeStamp operator-(const TimeInterval &interval) const {
339  return TimeStamp(m_tv - interval.m_interval);
340  }
341 
342  // Various other methods.
343  bool IsSet() const { return m_tv.IsSet(); }
344 
345  time_t Seconds() const { return m_tv.Seconds(); }
346  suseconds_t MicroSeconds() const { return m_tv.MicroSeconds(); }
347 
348  std::string ToString() const { return m_tv.ToString(); }
349 
350  friend ostream& operator<< (ostream &out, const TimeStamp &timestamp) {
351  return out << timestamp.m_tv.ToString();
352  }
353 
354  private:
355  BaseTimeVal m_tv;
356 
357  explicit TimeStamp(const BaseTimeVal &time_val) : m_tv(time_val) {}
358 };
359 
360 
361 /*
362  * Used to get the current time.
363  */
364 class Clock {
365  public:
366  Clock() {}
367  virtual ~Clock() {}
368  virtual void CurrentTime(TimeStamp *timestamp) const {
369  struct timeval tv;
370  gettimeofday(&tv, NULL);
371  *timestamp = tv;
372  }
373 
374  private:
375  Clock(const Clock &other);
376  Clock& operator=(const Clock &other);
377 };
378 
379 
383 class MockClock: public Clock {
384  public:
385  MockClock() : Clock() {}
386 
387  // Advance the time
388  void AdvanceTime(const TimeInterval &interval) {
389  m_offset += interval;
390  }
391 
392  void AdvanceTime(int32_t sec, int32_t usec) {
393  TimeInterval interval(sec, usec);
394  m_offset += interval;
395  }
396 
397  void CurrentTime(TimeStamp *timestamp) const {
398  struct timeval tv;
399  gettimeofday(&tv, NULL);
400  *timestamp = tv;
401  *timestamp += m_offset;
402  }
403  private:
404  TimeInterval m_offset;
405 };
406 } // namespace ola
407 #endif // INCLUDE_OLA_CLOCK_H_