1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla code.
17 : *
18 : * The Initial Developer of the Original Code is the Mozilla Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Robert O'Callahan <robert@ocallahan.org>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef mozilla_TimeStamp_h
40 : #define mozilla_TimeStamp_h
41 :
42 : #include "mozilla/Assertions.h"
43 :
44 : #include "prinrval.h"
45 : #include "nsDebug.h"
46 : #include "prlong.h"
47 :
48 : namespace mozilla {
49 :
50 : class TimeStamp;
51 :
52 : /**
53 : * Instances of this class represent the length of an interval of time.
54 : * Negative durations are allowed, meaning the end is before the start.
55 : *
56 : * Internally the duration is stored as a PRInt64 in units of
57 : * PR_TicksPerSecond() when building with NSPR interval timers, or a
58 : * system-dependent unit when building with system clocks. The
59 : * system-dependent unit must be constant, otherwise the semantics of
60 : * this class would be broken.
61 : */
62 : class TimeDuration
63 : {
64 : public:
65 : // The default duration is 0.
66 : TimeDuration() : mValue(0) {}
67 : // Allow construction using '0' as the initial value, for readability,
68 : // but no other numbers (so we don't have any implicit unit conversions).
69 : struct _SomethingVeryRandomHere;
70 : TimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0) {
71 : MOZ_ASSERT(!aZero, "Who's playing funny games here?");
72 : }
73 : // Default copy-constructor and assignment are OK
74 :
75 : double ToSeconds() const;
76 : // Return a duration value that includes digits of time we think to
77 : // be significant. This method should be used when displaying a
78 : // time to humans.
79 : double ToSecondsSigDigits() const;
80 : double ToMilliseconds() const {
81 : return ToSeconds() * 1000.0;
82 : }
83 : double ToMicroseconds() const {
84 : return ToMilliseconds() * 1000.0;
85 : }
86 :
87 : // Using a double here is safe enough; with 53 bits we can represent
88 : // durations up to over 280,000 years exactly. If the units of
89 : // mValue do not allow us to represent durations of that length,
90 : // long durations are clamped to the max/min representable value
91 : // instead of overflowing.
92 : static inline TimeDuration FromSeconds(double aSeconds) {
93 : return FromMilliseconds(aSeconds * 1000.0);
94 : }
95 : static TimeDuration FromMilliseconds(double aMilliseconds);
96 : static inline TimeDuration FromMicroseconds(double aMicroseconds) {
97 : return FromMilliseconds(aMicroseconds / 1000.0);
98 : }
99 :
100 : TimeDuration operator+(const TimeDuration& aOther) const {
101 : return TimeDuration::FromTicks(mValue + aOther.mValue);
102 : }
103 : TimeDuration operator-(const TimeDuration& aOther) const {
104 : return TimeDuration::FromTicks(mValue - aOther.mValue);
105 : }
106 : TimeDuration& operator+=(const TimeDuration& aOther) {
107 : mValue += aOther.mValue;
108 : return *this;
109 : }
110 : TimeDuration& operator-=(const TimeDuration& aOther) {
111 : mValue -= aOther.mValue;
112 : return *this;
113 : }
114 : double operator/(const TimeDuration& aOther) {
115 : return static_cast<double>(mValue) / aOther.mValue;
116 : }
117 :
118 : bool operator<(const TimeDuration& aOther) const {
119 : return mValue < aOther.mValue;
120 : }
121 : bool operator<=(const TimeDuration& aOther) const {
122 : return mValue <= aOther.mValue;
123 : }
124 : bool operator>=(const TimeDuration& aOther) const {
125 : return mValue >= aOther.mValue;
126 : }
127 : bool operator>(const TimeDuration& aOther) const {
128 : return mValue > aOther.mValue;
129 : }
130 :
131 : // Return a best guess at the system's current timing resolution,
132 : // which might be variable. TimeDurations below this order of
133 : // magnitude are meaningless, and those at the same order of
134 : // magnitude or just above are suspect.
135 : static TimeDuration Resolution();
136 :
137 : // We could define additional operators here:
138 : // -- convert to/from other time units
139 : // -- scale duration by a float
140 : // but let's do that on demand.
141 : // Comparing durations for equality will only lead to bugs on
142 : // platforms with high-resolution timers.
143 :
144 : private:
145 : friend class TimeStamp;
146 :
147 : static TimeDuration FromTicks(PRInt64 aTicks) {
148 : TimeDuration t;
149 : t.mValue = aTicks;
150 : return t;
151 : }
152 :
153 : static TimeDuration FromTicks(double aTicks) {
154 : // NOTE: this MUST be a >= test, because PRInt64(double(LL_MAXINT))
155 : // overflows and gives LL_MININT.
156 : if (aTicks >= double(LL_MAXINT))
157 : return TimeDuration::FromTicks(LL_MAXINT);
158 :
159 : // This MUST be a <= test.
160 : if (aTicks <= double(LL_MININT))
161 : return TimeDuration::FromTicks(LL_MININT);
162 :
163 : return TimeDuration::FromTicks(PRInt64(aTicks));
164 : }
165 :
166 : // Duration in PRIntervalTime units
167 : PRInt64 mValue;
168 : };
169 :
170 : /**
171 : * Instances of this class represent moments in time, or a special
172 : * "null" moment. We do not use the non-monotonic system clock or
173 : * local time, since they can be reset, causing apparent backward
174 : * travel in time, which can confuse algorithms. Instead we measure
175 : * elapsed time according to the system. This time can never go
176 : * backwards (i.e. it never wraps around, at least not in less than
177 : * five million years of system elapsed time). It might not advance
178 : * while the system is sleeping. If TimeStamp::SetNow() is not called
179 : * at all for hours or days, we might not notice the passage of some
180 : * of that time.
181 : *
182 : * We deliberately do not expose a way to convert TimeStamps to some
183 : * particular unit. All you can do is compute a difference between two
184 : * TimeStamps to get a TimeDuration. You can also add a TimeDuration
185 : * to a TimeStamp to get a new TimeStamp. You can't do something
186 : * meaningless like add two TimeStamps.
187 : *
188 : * Internally this is implemented as either a wrapper around
189 : * - high-resolution, monotonic, system clocks if they exist on this
190 : * platform
191 : * - PRIntervalTime otherwise. We detect wraparounds of
192 : * PRIntervalTime and work around them.
193 : *
194 : * This class is similar to C++11's time_point, however it is
195 : * explicitly nullable and provides an IsNull() method. time_point
196 : * is initialized to the clock's epoch and provides a
197 : * time_since_epoch() method that functions similiarly. i.e.
198 : * t.IsNull() is equivalent to t.time_since_epoch() == decltype(t)::duration::zero();
199 : */
200 : class TimeStamp
201 : {
202 : public:
203 : /**
204 : * Initialize to the "null" moment
205 : */
206 0 : TimeStamp() : mValue(0) {}
207 : // Default copy-constructor and assignment are OK
208 :
209 : /**
210 : * Return true if this is the "null" moment
211 : */
212 0 : bool IsNull() const { return mValue == 0; }
213 : /**
214 : * Return a timestamp reflecting the current elapsed system time. This
215 : * is monotonically increasing (i.e., does not decrease) over the
216 : * lifetime of this process' XPCOM session.
217 : */
218 : static TimeStamp Now();
219 : /**
220 : * Compute the difference between two timestamps. Both must be non-null.
221 : */
222 : TimeDuration operator-(const TimeStamp& aOther) const {
223 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
224 : MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
225 : PR_STATIC_ASSERT(-LL_MAXINT > LL_MININT);
226 : PRInt64 ticks = PRInt64(mValue - aOther.mValue);
227 : // Check for overflow.
228 : if (mValue > aOther.mValue) {
229 : if (ticks < 0) {
230 : ticks = LL_MAXINT;
231 : }
232 : } else {
233 : if (ticks > 0) {
234 : ticks = LL_MININT;
235 : }
236 : }
237 : return TimeDuration::FromTicks(ticks);
238 : }
239 :
240 : TimeStamp operator+(const TimeDuration& aOther) const {
241 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
242 : return TimeStamp(mValue + aOther.mValue);
243 : }
244 : TimeStamp operator-(const TimeDuration& aOther) const {
245 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
246 : return TimeStamp(mValue - aOther.mValue);
247 : }
248 : TimeStamp& operator+=(const TimeDuration& aOther) {
249 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
250 : mValue += aOther.mValue;
251 : return *this;
252 : }
253 : TimeStamp& operator-=(const TimeDuration& aOther) {
254 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
255 : mValue -= aOther.mValue;
256 : return *this;
257 : }
258 :
259 0 : bool operator<(const TimeStamp& aOther) const {
260 0 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
261 0 : MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
262 0 : return mValue < aOther.mValue;
263 : }
264 : bool operator<=(const TimeStamp& aOther) const {
265 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
266 : MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
267 : return mValue <= aOther.mValue;
268 : }
269 : bool operator>=(const TimeStamp& aOther) const {
270 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
271 : MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
272 : return mValue >= aOther.mValue;
273 : }
274 : bool operator>(const TimeStamp& aOther) const {
275 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
276 : MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
277 : return mValue > aOther.mValue;
278 : }
279 : bool operator==(const TimeStamp& aOther) const {
280 : // Maybe it's ok to check == with null timestamps?
281 : MOZ_ASSERT(!IsNull() && "Cannot compute with a null value");
282 : MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
283 : return mValue == aOther.mValue;
284 : }
285 : bool operator!=(const TimeStamp& aOther) const {
286 : // Maybe it's ok to check != with null timestamps?
287 : MOZ_ASSERT(!IsNull(), "Cannot compute with a null value");
288 : MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value");
289 : return mValue != aOther.mValue;
290 : }
291 :
292 : // Comparing TimeStamps for equality should be discouraged. Adding
293 : // two TimeStamps, or scaling TimeStamps, is nonsense and must never
294 : // be allowed.
295 :
296 : static NS_HIDDEN_(nsresult) Startup();
297 : static NS_HIDDEN_(void) Shutdown();
298 :
299 : private:
300 : TimeStamp(PRUint64 aValue) : mValue(aValue) {}
301 :
302 : /**
303 : * When built with PRIntervalTime, a value of 0 means this instance
304 : * is "null". Otherwise, the low 32 bits represent a PRIntervalTime,
305 : * and the high 32 bits represent a counter of the number of
306 : * rollovers of PRIntervalTime that we've seen. This counter starts
307 : * at 1 to avoid a real time colliding with the "null" value.
308 : *
309 : * PR_INTERVAL_MAX is set at 100,000 ticks per second. So the minimum
310 : * time to wrap around is about 2^64/100000 seconds, i.e. about
311 : * 5,849,424 years.
312 : *
313 : * When using a system clock, a value is system dependent.
314 : */
315 : PRUint64 mValue;
316 : };
317 :
318 : }
319 :
320 : #endif /* mozilla_TimeStamp_h */
|