1 //Written in the D programming language
2
3 /++
4 Module containing core time functionality, such as $(LREF Duration) (which
5 represents a duration of time) or $(LREF MonoTime) (which represents a
6 timestamp of the system's monotonic clock).
7
8 Various functions take a string (or strings) to represent a unit of time
9 (e.g. $(D convert!("days", "hours")(numDays))). The valid strings to use
10 with such functions are "years", "months", "weeks", "days", "hours",
11 "minutes", "seconds", "msecs" (milliseconds), "usecs" (microseconds),
12 "hnsecs" (hecto-nanoseconds - i.e. 100 ns) or some subset thereof. There
13 are a few functions that also allow "nsecs", but very little actually
14 has precision greater than hnsecs.
15
16 $(BOOKTABLE Cheat Sheet,
17 $(TR $(TH Symbol) $(TH Description))
18 $(LEADINGROW Types)
19 $(TR $(TDNW $(LREF Duration)) $(TD Represents a duration of time of weeks
20 or less (kept internally as hnsecs). (e.g. 22 days or 700 seconds).))
21 $(TR $(TDNW $(LREF TickDuration)) $(TD Represents a duration of time in
22 system clock ticks, using the highest precision that the system provides.))
23 $(TR $(TDNW $(LREF MonoTime)) $(TD Represents a monotonic timestamp in
24 system clock ticks, using the highest precision that the system provides.))
25 $(LEADINGROW Functions)
26 $(TR $(TDNW $(LREF convert)) $(TD Generic way of converting between two time
27 units.))
28 $(TR $(TDNW $(LREF dur)) $(TD Allows constructing a $(LREF Duration) from
29 the given time units with the given length.))
30 $(TR $(TDNW $(LREF weeks)$(NBSP)$(LREF days)$(NBSP)$(LREF hours)$(BR)
31 $(LREF minutes)$(NBSP)$(LREF seconds)$(NBSP)$(LREF msecs)$(BR)
32 $(LREF usecs)$(NBSP)$(LREF hnsecs)$(NBSP)$(LREF nsecs))
33 $(TD Convenience aliases for $(LREF dur).))
34 $(TR $(TDNW $(LREF abs)) $(TD Returns the absolute value of a duration.))
35 )
36
37 $(BOOKTABLE Conversions,
38 $(TR $(TH )
39 $(TH From $(LREF Duration))
40 $(TH From $(LREF TickDuration))
41 $(TH From units)
42 )
43 $(TR $(TD $(B To $(LREF Duration)))
44 $(TD -)
45 $(TD $(D tickDuration.)$(REF_SHORT to, std,conv)$(D !Duration()))
46 $(TD $(D dur!"msecs"(5)) or $(D 5.msecs()))
47 )
48 $(TR $(TD $(B To $(LREF TickDuration)))
49 $(TD $(D duration.)$(REF_SHORT to, std,conv)$(D !TickDuration()))
50 $(TD -)
51 $(TD $(D TickDuration.from!"msecs"(msecs)))
52 )
53 $(TR $(TD $(B To units))
54 $(TD $(D duration.total!"days"))
55 $(TD $(D tickDuration.msecs))
56 $(TD $(D convert!("days", "msecs")(msecs)))
57 ))
58
59 Copyright: Copyright 2010 - 2012
60 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
61 Authors: $(HTTP jmdavisprog.com, Jonathan M Davis) and Kato Shoichi
62 Source: $(DRUNTIMESRC core/_time.d)
63 Macros:
64 NBSP=
65 +/
66 module core.time;
67
68 import core.exception;
69 import core.stdc.time;
70 import core.stdc.stdio;
71 import core.internal.string;
72
version(Windows)73 version (Windows)
74 {
75 import core.sys.windows.winbase /+: QueryPerformanceCounter, QueryPerformanceFrequency+/;
76 }
77 else version (Posix)
78 {
79 import core.sys.posix.time;
80 import core.sys.posix.sys.time;
81 }
82
83 version (OSX)
84 version = Darwin;
85 else version (iOS)
86 version = Darwin;
87 else version (TVOS)
88 version = Darwin;
89 else version (WatchOS)
90 version = Darwin;
91
92 //This probably should be moved somewhere else in druntime which
93 //is Darwin-specific.
94 version (Darwin)
95 {
96
97 public import core.sys.darwin.mach.kern_return;
98
99 extern(C) nothrow @nogc
100 {
101
102 struct mach_timebase_info_data_t
103 {
104 uint numer;
105 uint denom;
106 }
107
108 alias mach_timebase_info_data_t* mach_timebase_info_t;
109
110 kern_return_t mach_timebase_info(mach_timebase_info_t);
111
112 ulong mach_absolute_time();
113
114 }
115
116 }
117
118 /++
119 What type of clock to use with $(LREF MonoTime) / $(LREF MonoTimeImpl) or
120 $(D std.datetime.Clock.currTime). They default to $(D ClockType.normal),
121 and most programs do not need to ever deal with the others.
122
123 The other $(D ClockType)s are provided so that other clocks provided by the
124 underlying C, system calls can be used with $(LREF MonoTimeImpl) or
125 $(D std.datetime.Clock.currTime) without having to use the C API directly.
126
127 In the case of the monotonic time, $(LREF MonoTimeImpl) is templatized on
128 $(D ClockType), whereas with $(D std.datetime.Clock.currTime), its a runtime
129 argument, since in the case of the monotonic time, the type of the clock
130 affects the resolution of a $(LREF MonoTimeImpl) object, whereas with
131 $(REF SysTime, std,datetime), its resolution is always hecto-nanoseconds
132 regardless of the source of the time.
133
134 $(D ClockType.normal), $(D ClockType.coarse), and $(D ClockType.precise)
135 work with both $(D Clock.currTime) and $(LREF MonoTimeImpl).
136 $(D ClockType.second) only works with $(D Clock.currTime). The others only
137 work with $(LREF MonoTimeImpl).
138 +/
139 version (CoreDdoc) enum ClockType
140 {
141 /++
142 Use the normal clock.
143 +/
144 normal = 0,
145
146 /++
147 $(BLUE Linux,OpenBSD-Only)
148
149 Uses $(D CLOCK_BOOTTIME).
150 +/
151 bootTime = 1,
152
153 /++
154 Use the coarse clock, not the normal one (e.g. on Linux, that would be
155 $(D CLOCK_REALTIME_COARSE) instead of $(D CLOCK_REALTIME) for
156 $(D clock_gettime) if a function is using the realtime clock). It's
157 generally faster to get the time with the coarse clock than the normal
158 clock, but it's less precise (e.g. 1 msec instead of 1 usec or 1 nsec).
159 Howeover, it $(I is) guaranteed to still have sub-second precision
160 (just not as high as with $(D ClockType.normal)).
161
162 On systems which do not support a coarser clock,
163 $(D MonoTimeImpl!(ClockType.coarse)) will internally use the same clock
164 as $(D MonoTime) does, and $(D Clock.currTime!(ClockType.coarse)) will
165 use the same clock as $(D Clock.currTime). This is because the coarse
166 clock is doing the same thing as the normal clock (just at lower
167 precision), whereas some of the other clock types
168 (e.g. $(D ClockType.processCPUTime)) mean something fundamentally
169 different. So, treating those as $(D ClockType.normal) on systems where
170 they weren't natively supported would give misleading results.
171
172 Most programs should not use the coarse clock, exactly because it's
173 less precise, and most programs don't need to get the time often
174 enough to care, but for those rare programs that need to get the time
175 extremely frequently (e.g. hundreds of thousands of times a second) but
176 don't care about high precision, the coarse clock might be appropriate.
177
178 Currently, only Linux and FreeBSD/DragonFlyBSD support a coarser clock, and on other
179 platforms, it's treated as $(D ClockType.normal).
180 +/
181 coarse = 2,
182
183 /++
184 Uses a more precise clock than the normal one (which is already very
185 precise), but it takes longer to get the time. Similarly to
186 $(D ClockType.coarse), if it's used on a system that does not support a
187 more precise clock than the normal one, it's treated as equivalent to
188 $(D ClockType.normal).
189
190 Currently, only FreeBSD/DragonFlyBSD supports a more precise clock, where it uses
191 $(D CLOCK_MONOTONIC_PRECISE) for the monotonic time and
192 $(D CLOCK_REALTIME_PRECISE) for the wall clock time.
193 +/
194 precise = 3,
195
196 /++
197 $(BLUE Linux,OpenBSD,Solaris-Only)
198
199 Uses $(D CLOCK_PROCESS_CPUTIME_ID).
200 +/
201 processCPUTime = 4,
202
203 /++
204 $(BLUE Linux-Only)
205
206 Uses $(D CLOCK_MONOTONIC_RAW).
207 +/
208 raw = 5,
209
210 /++
211 Uses a clock that has a precision of one second (contrast to the coarse
212 clock, which has sub-second precision like the normal clock does).
213
214 FreeBSD/DragonFlyBSD are the only systems which specifically have a clock set up for
215 this (it has $(D CLOCK_SECOND) to use with $(D clock_gettime) which
216 takes advantage of an in-kernel cached value), but on other systems, the
217 fastest function available will be used, and the resulting $(D SysTime)
218 will be rounded down to the second if the clock that was used gave the
219 time at a more precise resolution. So, it's guaranteed that the time
220 will be given at a precision of one second and it's likely the case that
221 will be faster than $(D ClockType.normal), since there tend to be
222 several options on a system to get the time at low resolutions, and they
223 tend to be faster than getting the time at high resolutions.
224
225 So, the primary difference between $(D ClockType.coarse) and
226 $(D ClockType.second) is that $(D ClockType.coarse) sacrifices some
227 precision in order to get speed but is still fairly precise, whereas
228 $(D ClockType.second) tries to be as fast as possible at the expense of
229 all sub-second precision.
230 +/
231 second = 6,
232
233 /++
234 $(BLUE Linux,OpenBSD,Solaris-Only)
235
236 Uses $(D CLOCK_THREAD_CPUTIME_ID).
237 +/
238 threadCPUTime = 7,
239
240 /++
241 $(BLUE DragonFlyBSD,FreeBSD,OpenBSD-Only)
242
243 Uses $(D CLOCK_UPTIME).
244 +/
245 uptime = 8,
246
247 /++
248 $(BLUE FreeBSD-Only)
249
250 Uses $(D CLOCK_UPTIME_FAST).
251 +/
252 uptimeCoarse = 9,
253
254 /++
255 $(BLUE FreeBSD-Only)
256
257 Uses $(D CLOCK_UPTIME_PRECISE).
258 +/
259 uptimePrecise = 10,
260 }
261 else version (Windows) enum ClockType
262 {
263 normal = 0,
264 coarse = 2,
265 precise = 3,
266 second = 6,
267 }
268 else version (Darwin) enum ClockType
269 {
270 normal = 0,
271 coarse = 2,
272 precise = 3,
273 second = 6,
274 }
version(linux)275 else version (linux) enum ClockType
276 {
277 normal = 0,
278 bootTime = 1,
279 coarse = 2,
280 precise = 3,
281 processCPUTime = 4,
282 raw = 5,
283 second = 6,
284 threadCPUTime = 7,
285 }
286 else version (FreeBSD) enum ClockType
287 {
288 normal = 0,
289 coarse = 2,
290 precise = 3,
291 second = 6,
292 uptime = 8,
293 uptimeCoarse = 9,
294 uptimePrecise = 10,
295 }
version(NetBSD)296 else version (NetBSD) enum ClockType
297 {
298 normal = 0,
299 coarse = 2,
300 precise = 3,
301 second = 6,
302 }
303 else version (OpenBSD) enum ClockType
304 {
305 normal = 0,
306 bootTime = 1,
307 coarse = 2,
308 precise = 3,
309 processCPUTime = 4,
310 second = 6,
311 threadCPUTime = 7,
312 uptime = 8,
313 }
version(DragonFlyBSD)314 else version (DragonFlyBSD) enum ClockType
315 {
316 normal = 0,
317 coarse = 2,
318 precise = 3,
319 second = 6,
320 uptime = 8,
321 uptimeCoarse = 9,
322 uptimePrecise = 10,
323 }
324 else version (Solaris) enum ClockType
325 {
326 normal = 0,
327 coarse = 2,
328 precise = 3,
329 processCPUTime = 4,
330 second = 6,
331 threadCPUTime = 7,
332 }
333 else
334 {
335 // It needs to be decided (and implemented in an appropriate version branch
336 // here) which clock types new platforms are going to support. At minimum,
337 // the ones _not_ marked with $(D Blue Foo-Only) should be supported.
338 static assert(0, "What are the clock types supported by this system?");
339 }
340
341 // private, used to translate clock type to proper argument to clock_xxx
342 // functions on posix systems
version(CoreDdoc)343 version (CoreDdoc)
344 private int _posixClock(ClockType clockType) { return 0; }
345 else
version(Posix)346 version (Posix)
347 {
348 private auto _posixClock(ClockType clockType)
349 {
350 version (linux)
351 {
352 import core.sys.linux.time;
353 with(ClockType) final switch (clockType)
354 {
355 case bootTime: return CLOCK_BOOTTIME;
356 case coarse: return CLOCK_MONOTONIC_COARSE;
357 case normal: return CLOCK_MONOTONIC;
358 case precise: return CLOCK_MONOTONIC;
359 case processCPUTime: return CLOCK_PROCESS_CPUTIME_ID;
360 case raw: return CLOCK_MONOTONIC_RAW;
361 case threadCPUTime: return CLOCK_THREAD_CPUTIME_ID;
362 case second: assert(0);
363 }
364 }
365 else version (FreeBSD)
366 {
367 import core.sys.freebsd.time;
368 with(ClockType) final switch (clockType)
369 {
370 case coarse: return CLOCK_MONOTONIC_FAST;
371 case normal: return CLOCK_MONOTONIC;
372 case precise: return CLOCK_MONOTONIC_PRECISE;
373 case uptime: return CLOCK_UPTIME;
374 case uptimeCoarse: return CLOCK_UPTIME_FAST;
375 case uptimePrecise: return CLOCK_UPTIME_PRECISE;
376 case second: assert(0);
377 }
378 }
379 else version (NetBSD)
380 {
381 import core.sys.netbsd.time;
382 with(ClockType) final switch (clockType)
383 {
384 case coarse: return CLOCK_MONOTONIC;
385 case normal: return CLOCK_MONOTONIC;
386 case precise: return CLOCK_MONOTONIC;
387 case second: assert(0);
388 }
389 }
390 else version (OpenBSD)
391 {
392 import core.sys.openbsd.time;
393 with(ClockType) final switch (clockType)
394 {
395 case bootTime: return CLOCK_BOOTTIME;
396 case coarse: return CLOCK_MONOTONIC;
397 case normal: return CLOCK_MONOTONIC;
398 case precise: return CLOCK_MONOTONIC;
399 case processCPUTime: return CLOCK_PROCESS_CPUTIME_ID;
400 case threadCPUTime: return CLOCK_THREAD_CPUTIME_ID;
401 case uptime: return CLOCK_UPTIME;
402 case second: assert(0);
403 }
404 }
405 else version (DragonFlyBSD)
406 {
407 import core.sys.dragonflybsd.time;
408 with(ClockType) final switch (clockType)
409 {
410 case coarse: return CLOCK_MONOTONIC_FAST;
411 case normal: return CLOCK_MONOTONIC;
412 case precise: return CLOCK_MONOTONIC_PRECISE;
413 case uptime: return CLOCK_UPTIME;
414 case uptimeCoarse: return CLOCK_UPTIME_FAST;
415 case uptimePrecise: return CLOCK_UPTIME_PRECISE;
416 case second: assert(0);
417 }
418 }
419 else version (Solaris)
420 {
421 import core.sys.solaris.time;
422 with(ClockType) final switch (clockType)
423 {
424 case coarse: return CLOCK_MONOTONIC;
425 case normal: return CLOCK_MONOTONIC;
426 case precise: return CLOCK_MONOTONIC;
427 case processCPUTime: return CLOCK_PROCESS_CPUTIME_ID;
428 case threadCPUTime: return CLOCK_THREAD_CPUTIME_ID;
429 case second: assert(0);
430 }
431 }
432 else
433 // It needs to be decided (and implemented in an appropriate
434 // version branch here) which clock types new platforms are going
435 // to support. Also, ClockType's documentation should be updated to
436 // mention it if a new platform uses anything that's not supported
437 // on all platforms..
438 assert(0, "What are the monotonic clock types supported by this system?");
439 }
440 }
441
442 unittest
443 {
444 // Make sure that the values are the same across platforms.
445 static if (is(typeof(ClockType.normal))) static assert(ClockType.normal == 0);
446 static if (is(typeof(ClockType.bootTime))) static assert(ClockType.bootTime == 1);
447 static if (is(typeof(ClockType.coarse))) static assert(ClockType.coarse == 2);
448 static if (is(typeof(ClockType.precise))) static assert(ClockType.precise == 3);
449 static if (is(typeof(ClockType.processCPUTime))) static assert(ClockType.processCPUTime == 4);
450 static if (is(typeof(ClockType.raw))) static assert(ClockType.raw == 5);
451 static if (is(typeof(ClockType.second))) static assert(ClockType.second == 6);
452 static if (is(typeof(ClockType.threadCPUTime))) static assert(ClockType.threadCPUTime == 7);
453 static if (is(typeof(ClockType.uptime))) static assert(ClockType.uptime == 8);
454 static if (is(typeof(ClockType.uptimeCoarse))) static assert(ClockType.uptimeCoarse == 9);
455 static if (is(typeof(ClockType.uptimePrecise))) static assert(ClockType.uptimePrecise == 10);
456 }
457
458
459 /++
460 Represents a duration of time of weeks or less (kept internally as hnsecs).
461 (e.g. 22 days or 700 seconds).
462
463 It is used when representing a duration of time - such as how long to
464 sleep with $(REF Thread.sleep, core,thread).
465
466 In std.datetime, it is also used as the result of various arithmetic
467 operations on time points.
468
469 Use the $(LREF dur) function or one of its non-generic aliases to create
470 $(D Duration)s.
471
472 It's not possible to create a Duration of months or years, because the
473 variable number of days in a month or year makes it impossible to convert
474 between months or years and smaller units without a specific date. So,
475 nothing uses $(D Duration)s when dealing with months or years. Rather,
476 functions specific to months and years are defined. For instance,
477 $(REF Date, std,datetime) has $(D add!"years") and $(D add!"months") for adding
478 years and months rather than creating a Duration of years or months and
479 adding that to a $(REF Date, std,datetime). But Duration is used when dealing
480 with weeks or smaller.
481
482 Examples:
483 --------------------
484 import std.datetime;
485
486 assert(dur!"days"(12) == dur!"hnsecs"(10_368_000_000_000L));
487 assert(dur!"hnsecs"(27) == dur!"hnsecs"(27));
488 assert(std.datetime.Date(2010, 9, 7) + dur!"days"(5) ==
489 std.datetime.Date(2010, 9, 12));
490
491 assert(days(-12) == dur!"hnsecs"(-10_368_000_000_000L));
492 assert(hnsecs(-27) == dur!"hnsecs"(-27));
493 assert(std.datetime.Date(2010, 9, 7) - std.datetime.Date(2010, 10, 3) ==
494 days(-26));
495 --------------------
496 +/
497 struct Duration
498 {
499 /++
500 Converts this `Duration` to a `string`.
501
502 The string is meant to be human readable, not machine parseable (e.g.
503 whether there is an `'s'` on the end of the unit name usually depends on
504 whether it's plural or not, and empty units are not included unless the
505 Duration is `zero`). Any code needing a specific string format should
506 use `total` or `split` to get the units needed to create the desired
507 string format and create the string itself.
508
509 The format returned by toString may or may not change in the future.
510
511 Params:
512 sink = A sink object, expected to be a delegate or aggregate
513 implementing `opCall` that accepts a `scope const(char)[]`
514 as argument.
515 +/
toStringDuration516 void toString (SinkT) (scope SinkT sink) const scope
517 {
518 static immutable units = [
519 "weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs"
520 ];
521
522 static void appListSep(SinkT sink, uint pos, bool last)
523 {
524 if (pos == 0)
525 return;
526 if (!last)
527 sink(", ");
528 else
529 sink(pos == 1 ? " and " : ", and ");
530 }
531
532 static void appUnitVal(string units)(SinkT sink, long val)
533 {
534 immutable plural = val != 1;
535 string unit;
536 static if (units == "seconds")
537 unit = plural ? "secs" : "sec";
538 else static if (units == "msecs")
539 unit = "ms";
540 else static if (units == "usecs")
541 unit = "μs";
542 else
543 unit = plural ? units : units[0 .. $-1];
544 sink(signedToTempString(val));
545 sink(" ");
546 sink(unit);
547 }
548
549 if (_hnsecs == 0)
550 {
551 sink("0 hnsecs");
552 return;
553 }
554
555 long hnsecs = _hnsecs;
556 uint pos;
557 static foreach (unit; units)
558 {
559 if (auto val = splitUnitsFromHNSecs!unit(hnsecs))
560 {
561 appListSep(sink, pos++, hnsecs == 0);
562 appUnitVal!unit(sink, val);
563 }
564 if (hnsecs == 0)
565 return;
566 }
567 if (hnsecs != 0)
568 {
569 appListSep(sink, pos++, true);
570 appUnitVal!"hnsecs"(sink, hnsecs);
571 }
572 }
573
574 @safe pure:
575
576 public:
577
578 /++
579 A $(D Duration) of $(D 0). It's shorter than doing something like
580 $(D dur!"seconds"(0)) and more explicit than $(D Duration.init).
581 +/
zeroDuration582 static @property nothrow @nogc Duration zero() { return Duration(0); }
583
584 /++
585 Largest $(D Duration) possible.
586 +/
587 static @property nothrow @nogc Duration max() { return Duration(long.max); }
588
589 /++
590 Most negative $(D Duration) possible.
591 +/
592 static @property nothrow @nogc Duration min() { return Duration(long.min); }
593
594 version (CoreUnittest) unittest
595 {
596 assert(zero == dur!"seconds"(0));
597 assert(Duration.max == Duration(long.max));
598 assert(Duration.min == Duration(long.min));
599 assert(Duration.min < Duration.zero);
600 assert(Duration.zero < Duration.max);
601 assert(Duration.min < Duration.max);
602 assert(Duration.min - dur!"hnsecs"(1) == Duration.max);
603 assert(Duration.max + dur!"hnsecs"(1) == Duration.min);
604 }
605
606
607 /++
608 Compares this $(D Duration) with the given $(D Duration).
609
610 Returns:
611 $(TABLE
612 $(TR $(TD this < rhs) $(TD < 0))
613 $(TR $(TD this == rhs) $(TD 0))
614 $(TR $(TD this > rhs) $(TD > 0))
615 )
616 +/
617 int opCmp(Duration rhs) const nothrow @nogc
618 {
619 return (_hnsecs > rhs._hnsecs) - (_hnsecs < rhs._hnsecs);
620 }
621
622 version (CoreUnittest) unittest
623 {
624 import core.internal.traits : rvalueOf;
625 foreach (T; AliasSeq!(Duration, const Duration, immutable Duration))
626 {
627 foreach (U; AliasSeq!(Duration, const Duration, immutable Duration))
628 {
629 T t = 42;
630 // workaround https://issues.dlang.org/show_bug.cgi?id=18296
631 version (D_Coverage)
632 U u = T(t._hnsecs);
633 else
634 U u = t;
635 assert(t == u);
636 assert(rvalueOf(t) == u);
637 assert(t == rvalueOf(u));
638 }
639 }
640
641 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
642 {
643 foreach (E; AliasSeq!(Duration, const Duration, immutable Duration))
644 {
645 assert((cast(D)Duration(12)).opCmp(cast(E)Duration(12)) == 0);
646 assert((cast(D)Duration(-12)).opCmp(cast(E)Duration(-12)) == 0);
647
648 assert((cast(D)Duration(10)).opCmp(cast(E)Duration(12)) < 0);
649 assert((cast(D)Duration(-12)).opCmp(cast(E)Duration(12)) < 0);
650
651 assert((cast(D)Duration(12)).opCmp(cast(E)Duration(10)) > 0);
652 assert((cast(D)Duration(12)).opCmp(cast(E)Duration(-12)) > 0);
653
654 assert(rvalueOf(cast(D)Duration(12)).opCmp(cast(E)Duration(12)) == 0);
655 assert(rvalueOf(cast(D)Duration(-12)).opCmp(cast(E)Duration(-12)) == 0);
656
657 assert(rvalueOf(cast(D)Duration(10)).opCmp(cast(E)Duration(12)) < 0);
658 assert(rvalueOf(cast(D)Duration(-12)).opCmp(cast(E)Duration(12)) < 0);
659
660 assert(rvalueOf(cast(D)Duration(12)).opCmp(cast(E)Duration(10)) > 0);
661 assert(rvalueOf(cast(D)Duration(12)).opCmp(cast(E)Duration(-12)) > 0);
662
663 assert((cast(D)Duration(12)).opCmp(rvalueOf(cast(E)Duration(12))) == 0);
664 assert((cast(D)Duration(-12)).opCmp(rvalueOf(cast(E)Duration(-12))) == 0);
665
666 assert((cast(D)Duration(10)).opCmp(rvalueOf(cast(E)Duration(12))) < 0);
667 assert((cast(D)Duration(-12)).opCmp(rvalueOf(cast(E)Duration(12))) < 0);
668
669 assert((cast(D)Duration(12)).opCmp(rvalueOf(cast(E)Duration(10))) > 0);
670 assert((cast(D)Duration(12)).opCmp(rvalueOf(cast(E)Duration(-12))) > 0);
671 }
672 }
673 }
674
675
676 /++
677 Adds, subtracts or calculates the modulo of two durations.
678
679 The legal types of arithmetic for $(D Duration) using this operator are
680
681 $(TABLE
682 $(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration))
683 $(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration))
684 $(TR $(TD Duration) $(TD %) $(TD Duration) $(TD -->) $(TD Duration))
685 $(TR $(TD Duration) $(TD +) $(TD TickDuration) $(TD -->) $(TD Duration))
686 $(TR $(TD Duration) $(TD -) $(TD TickDuration) $(TD -->) $(TD Duration))
687 )
688
689 Params:
690 rhs = The duration to add to or subtract from this $(D Duration).
691 +/
692 Duration opBinary(string op, D)(D rhs) const nothrow @nogc
693 if (((op == "+" || op == "-" || op == "%") && is(immutable D == immutable Duration)) ||
694 ((op == "+" || op == "-") && is(immutable D == immutable TickDuration)))
695 {
696 static if (is(immutable D == immutable Duration))
697 return Duration(mixin("_hnsecs " ~ op ~ " rhs._hnsecs"));
698 else
699 return Duration(mixin("_hnsecs " ~ op ~ " rhs.hnsecs"));
700 }
701
702 version (CoreUnittest) unittest
703 {
704 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
705 {
706 foreach (E; AliasSeq!(Duration, const Duration, immutable Duration))
707 {
708 assert((cast(D)Duration(5)) + (cast(E)Duration(7)) == Duration(12));
709 assert((cast(D)Duration(5)) - (cast(E)Duration(7)) == Duration(-2));
710 assert((cast(D)Duration(5)) % (cast(E)Duration(7)) == Duration(5));
711 assert((cast(D)Duration(7)) + (cast(E)Duration(5)) == Duration(12));
712 assert((cast(D)Duration(7)) - (cast(E)Duration(5)) == Duration(2));
713 assert((cast(D)Duration(7)) % (cast(E)Duration(5)) == Duration(2));
714
715 assert((cast(D)Duration(5)) + (cast(E)Duration(-7)) == Duration(-2));
716 assert((cast(D)Duration(5)) - (cast(E)Duration(-7)) == Duration(12));
717 assert((cast(D)Duration(5)) % (cast(E)Duration(-7)) == Duration(5));
718 assert((cast(D)Duration(7)) + (cast(E)Duration(-5)) == Duration(2));
719 assert((cast(D)Duration(7)) - (cast(E)Duration(-5)) == Duration(12));
720 assert((cast(D)Duration(7)) % (cast(E)Duration(-5)) == Duration(2));
721
722 assert((cast(D)Duration(-5)) + (cast(E)Duration(7)) == Duration(2));
723 assert((cast(D)Duration(-5)) - (cast(E)Duration(7)) == Duration(-12));
724 assert((cast(D)Duration(-5)) % (cast(E)Duration(7)) == Duration(-5));
725 assert((cast(D)Duration(-7)) + (cast(E)Duration(5)) == Duration(-2));
726 assert((cast(D)Duration(-7)) - (cast(E)Duration(5)) == Duration(-12));
727 assert((cast(D)Duration(-7)) % (cast(E)Duration(5)) == Duration(-2));
728
729 assert((cast(D)Duration(-5)) + (cast(E)Duration(-7)) == Duration(-12));
730 assert((cast(D)Duration(-5)) - (cast(E)Duration(-7)) == Duration(2));
731 assert((cast(D)Duration(-5)) % (cast(E)Duration(7)) == Duration(-5));
732 assert((cast(D)Duration(-7)) + (cast(E)Duration(-5)) == Duration(-12));
733 assert((cast(D)Duration(-7)) - (cast(E)Duration(-5)) == Duration(-2));
734 assert((cast(D)Duration(-7)) % (cast(E)Duration(5)) == Duration(-2));
735 }
736
737 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
738 {
739 assertApprox((cast(D)Duration(5)) + cast(T)TickDuration.from!"usecs"(7), Duration(70), Duration(80));
740 assertApprox((cast(D)Duration(5)) - cast(T)TickDuration.from!"usecs"(7), Duration(-70), Duration(-60));
741 assertApprox((cast(D)Duration(7)) + cast(T)TickDuration.from!"usecs"(5), Duration(52), Duration(62));
742 assertApprox((cast(D)Duration(7)) - cast(T)TickDuration.from!"usecs"(5), Duration(-48), Duration(-38));
743
744 assertApprox((cast(D)Duration(5)) + cast(T)TickDuration.from!"usecs"(-7), Duration(-70), Duration(-60));
745 assertApprox((cast(D)Duration(5)) - cast(T)TickDuration.from!"usecs"(-7), Duration(70), Duration(80));
746 assertApprox((cast(D)Duration(7)) + cast(T)TickDuration.from!"usecs"(-5), Duration(-48), Duration(-38));
747 assertApprox((cast(D)Duration(7)) - cast(T)TickDuration.from!"usecs"(-5), Duration(52), Duration(62));
748
749 assertApprox((cast(D)Duration(-5)) + cast(T)TickDuration.from!"usecs"(7), Duration(60), Duration(70));
750 assertApprox((cast(D)Duration(-5)) - cast(T)TickDuration.from!"usecs"(7), Duration(-80), Duration(-70));
751 assertApprox((cast(D)Duration(-7)) + cast(T)TickDuration.from!"usecs"(5), Duration(38), Duration(48));
752 assertApprox((cast(D)Duration(-7)) - cast(T)TickDuration.from!"usecs"(5), Duration(-62), Duration(-52));
753
754 assertApprox((cast(D)Duration(-5)) + cast(T)TickDuration.from!"usecs"(-7), Duration(-80), Duration(-70));
755 assertApprox((cast(D)Duration(-5)) - cast(T)TickDuration.from!"usecs"(-7), Duration(60), Duration(70));
756 assertApprox((cast(D)Duration(-7)) + cast(T)TickDuration.from!"usecs"(-5), Duration(-62), Duration(-52));
757 assertApprox((cast(D)Duration(-7)) - cast(T)TickDuration.from!"usecs"(-5), Duration(38), Duration(48));
758 }
759 }
760 }
761
762
763 /++
764 Adds or subtracts two durations.
765
766 The legal types of arithmetic for $(D Duration) using this operator are
767
768 $(TABLE
769 $(TR $(TD TickDuration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration))
770 $(TR $(TD TickDuration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration))
771 )
772
773 Params:
774 lhs = The $(D TickDuration) to add to this $(D Duration) or to
775 subtract this $(D Duration) from.
776 +/
777 Duration opBinaryRight(string op, D)(D lhs) const nothrow @nogc
778 if ((op == "+" || op == "-") &&
779 is(immutable D == immutable TickDuration))
780 {
781 return Duration(mixin("lhs.hnsecs " ~ op ~ " _hnsecs"));
782 }
783
784 version (CoreUnittest) unittest
785 {
786 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
787 {
788 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
789 {
790 assertApprox((cast(T)TickDuration.from!"usecs"(7)) + cast(D)Duration(5), Duration(70), Duration(80));
791 assertApprox((cast(T)TickDuration.from!"usecs"(7)) - cast(D)Duration(5), Duration(60), Duration(70));
792 assertApprox((cast(T)TickDuration.from!"usecs"(5)) + cast(D)Duration(7), Duration(52), Duration(62));
793 assertApprox((cast(T)TickDuration.from!"usecs"(5)) - cast(D)Duration(7), Duration(38), Duration(48));
794
795 assertApprox((cast(T)TickDuration.from!"usecs"(-7)) + cast(D)Duration(5), Duration(-70), Duration(-60));
796 assertApprox((cast(T)TickDuration.from!"usecs"(-7)) - cast(D)Duration(5), Duration(-80), Duration(-70));
797 assertApprox((cast(T)TickDuration.from!"usecs"(-5)) + cast(D)Duration(7), Duration(-48), Duration(-38));
798 assertApprox((cast(T)TickDuration.from!"usecs"(-5)) - cast(D)Duration(7), Duration(-62), Duration(-52));
799
800 assertApprox((cast(T)TickDuration.from!"usecs"(7)) + (cast(D)Duration(-5)), Duration(60), Duration(70));
801 assertApprox((cast(T)TickDuration.from!"usecs"(7)) - (cast(D)Duration(-5)), Duration(70), Duration(80));
802 assertApprox((cast(T)TickDuration.from!"usecs"(5)) + (cast(D)Duration(-7)), Duration(38), Duration(48));
803 assertApprox((cast(T)TickDuration.from!"usecs"(5)) - (cast(D)Duration(-7)), Duration(52), Duration(62));
804
805 assertApprox((cast(T)TickDuration.from!"usecs"(-7)) + cast(D)Duration(-5), Duration(-80), Duration(-70));
806 assertApprox((cast(T)TickDuration.from!"usecs"(-7)) - cast(D)Duration(-5), Duration(-70), Duration(-60));
807 assertApprox((cast(T)TickDuration.from!"usecs"(-5)) + cast(D)Duration(-7), Duration(-62), Duration(-52));
808 assertApprox((cast(T)TickDuration.from!"usecs"(-5)) - cast(D)Duration(-7), Duration(-48), Duration(-38));
809 }
810 }
811 }
812
813
814 /++
815 Adds, subtracts or calculates the modulo of two durations as well as
816 assigning the result to this $(D Duration).
817
818 The legal types of arithmetic for $(D Duration) using this operator are
819
820 $(TABLE
821 $(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration))
822 $(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration))
823 $(TR $(TD Duration) $(TD %) $(TD Duration) $(TD -->) $(TD Duration))
824 $(TR $(TD Duration) $(TD +) $(TD TickDuration) $(TD -->) $(TD Duration))
825 $(TR $(TD Duration) $(TD -) $(TD TickDuration) $(TD -->) $(TD Duration))
826 )
827
828 Params:
829 rhs = The duration to add to or subtract from this $(D Duration).
830 +/
831 ref Duration opOpAssign(string op, D)(const scope D rhs) nothrow @nogc
832 if (((op == "+" || op == "-" || op == "%") && is(immutable D == immutable Duration)) ||
833 ((op == "+" || op == "-") && is(immutable D == immutable TickDuration)))
834 {
835 static if (is(immutable D == immutable Duration))
836 mixin("_hnsecs " ~ op ~ "= rhs._hnsecs;");
837 else
838 mixin("_hnsecs " ~ op ~ "= rhs.hnsecs;");
839 return this;
840 }
841
842 version (CoreUnittest) unittest
843 {
844 static void test1(string op, E)(Duration actual, in E rhs, Duration expected, size_t line = __LINE__)
845 {
846 if (mixin("actual " ~ op ~ " rhs") != expected)
847 throw new AssertError("op failed", __FILE__, line);
848
849 if (actual != expected)
850 throw new AssertError("op assign failed", __FILE__, line);
851 }
852
853 static void test2(string op, E)
854 (Duration actual, in E rhs, Duration lower, Duration upper, size_t line = __LINE__)
855 {
856 assertApprox(mixin("actual " ~ op ~ " rhs"), lower, upper, "op failed", line);
857 assertApprox(actual, lower, upper, "op assign failed", line);
858 }
859
860 foreach (E; AliasSeq!(Duration, const Duration, immutable Duration))
861 {
862 test1!"+="(Duration(5), (cast(E)Duration(7)), Duration(12));
863 test1!"-="(Duration(5), (cast(E)Duration(7)), Duration(-2));
864 test1!"%="(Duration(5), (cast(E)Duration(7)), Duration(5));
865 test1!"+="(Duration(7), (cast(E)Duration(5)), Duration(12));
866 test1!"-="(Duration(7), (cast(E)Duration(5)), Duration(2));
867 test1!"%="(Duration(7), (cast(E)Duration(5)), Duration(2));
868
869 test1!"+="(Duration(5), (cast(E)Duration(-7)), Duration(-2));
870 test1!"-="(Duration(5), (cast(E)Duration(-7)), Duration(12));
871 test1!"%="(Duration(5), (cast(E)Duration(-7)), Duration(5));
872 test1!"+="(Duration(7), (cast(E)Duration(-5)), Duration(2));
873 test1!"-="(Duration(7), (cast(E)Duration(-5)), Duration(12));
874 test1!"%="(Duration(7), (cast(E)Duration(-5)), Duration(2));
875
876 test1!"+="(Duration(-5), (cast(E)Duration(7)), Duration(2));
877 test1!"-="(Duration(-5), (cast(E)Duration(7)), Duration(-12));
878 test1!"%="(Duration(-5), (cast(E)Duration(7)), Duration(-5));
879 test1!"+="(Duration(-7), (cast(E)Duration(5)), Duration(-2));
880 test1!"-="(Duration(-7), (cast(E)Duration(5)), Duration(-12));
881 test1!"%="(Duration(-7), (cast(E)Duration(5)), Duration(-2));
882
883 test1!"+="(Duration(-5), (cast(E)Duration(-7)), Duration(-12));
884 test1!"-="(Duration(-5), (cast(E)Duration(-7)), Duration(2));
885 test1!"%="(Duration(-5), (cast(E)Duration(-7)), Duration(-5));
886 test1!"+="(Duration(-7), (cast(E)Duration(-5)), Duration(-12));
887 test1!"-="(Duration(-7), (cast(E)Duration(-5)), Duration(-2));
888 test1!"%="(Duration(-7), (cast(E)Duration(-5)), Duration(-2));
889 }
890
891 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
892 {
893 test2!"+="(Duration(5), cast(T)TickDuration.from!"usecs"(7), Duration(70), Duration(80));
894 test2!"-="(Duration(5), cast(T)TickDuration.from!"usecs"(7), Duration(-70), Duration(-60));
895 test2!"+="(Duration(7), cast(T)TickDuration.from!"usecs"(5), Duration(52), Duration(62));
896 test2!"-="(Duration(7), cast(T)TickDuration.from!"usecs"(5), Duration(-48), Duration(-38));
897
898 test2!"+="(Duration(5), cast(T)TickDuration.from!"usecs"(-7), Duration(-70), Duration(-60));
899 test2!"-="(Duration(5), cast(T)TickDuration.from!"usecs"(-7), Duration(70), Duration(80));
900 test2!"+="(Duration(7), cast(T)TickDuration.from!"usecs"(-5), Duration(-48), Duration(-38));
901 test2!"-="(Duration(7), cast(T)TickDuration.from!"usecs"(-5), Duration(52), Duration(62));
902
903 test2!"+="(Duration(-5), cast(T)TickDuration.from!"usecs"(7), Duration(60), Duration(70));
904 test2!"-="(Duration(-5), cast(T)TickDuration.from!"usecs"(7), Duration(-80), Duration(-70));
905 test2!"+="(Duration(-7), cast(T)TickDuration.from!"usecs"(5), Duration(38), Duration(48));
906 test2!"-="(Duration(-7), cast(T)TickDuration.from!"usecs"(5), Duration(-62), Duration(-52));
907
908 test2!"+="(Duration(-5), cast(T)TickDuration.from!"usecs"(-7), Duration(-80), Duration(-70));
909 test2!"-="(Duration(-5), cast(T)TickDuration.from!"usecs"(-7), Duration(60), Duration(70));
910 test2!"+="(Duration(-7), cast(T)TickDuration.from!"usecs"(-5), Duration(-62), Duration(-52));
911 test2!"-="(Duration(-7), cast(T)TickDuration.from!"usecs"(-5), Duration(38), Duration(48));
912 }
913
914 foreach (D; AliasSeq!(const Duration, immutable Duration))
915 {
916 foreach (E; AliasSeq!(Duration, const Duration, immutable Duration,
917 TickDuration, const TickDuration, immutable TickDuration))
918 {
919 D lhs = D(120);
920 E rhs = E(120);
921 static assert(!__traits(compiles, lhs += rhs), D.stringof ~ " " ~ E.stringof);
922 }
923 }
924 }
925
926
927 /++
928 Multiplies or divides the duration by an integer value.
929
930 The legal types of arithmetic for $(D Duration) using this operator
931 overload are
932
933 $(TABLE
934 $(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration))
935 $(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration))
936 )
937
938 Params:
939 value = The value to multiply this $(D Duration) by.
940 +/
941 Duration opBinary(string op)(long value) const nothrow @nogc
942 if (op == "*" || op == "/")
943 {
944 mixin("return Duration(_hnsecs " ~ op ~ " value);");
945 }
946
947 version (CoreUnittest) unittest
948 {
949 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
950 {
951 assert((cast(D)Duration(5)) * 7 == Duration(35));
952 assert((cast(D)Duration(7)) * 5 == Duration(35));
953
954 assert((cast(D)Duration(5)) * -7 == Duration(-35));
955 assert((cast(D)Duration(7)) * -5 == Duration(-35));
956
957 assert((cast(D)Duration(-5)) * 7 == Duration(-35));
958 assert((cast(D)Duration(-7)) * 5 == Duration(-35));
959
960 assert((cast(D)Duration(-5)) * -7 == Duration(35));
961 assert((cast(D)Duration(-7)) * -5 == Duration(35));
962
963 assert((cast(D)Duration(5)) * 0 == Duration(0));
964 assert((cast(D)Duration(-5)) * 0 == Duration(0));
965 }
966 }
967
968 version (CoreUnittest) unittest
969 {
970 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
971 {
972 assert((cast(D)Duration(5)) / 7 == Duration(0));
973 assert((cast(D)Duration(7)) / 5 == Duration(1));
974
975 assert((cast(D)Duration(5)) / -7 == Duration(0));
976 assert((cast(D)Duration(7)) / -5 == Duration(-1));
977
978 assert((cast(D)Duration(-5)) / 7 == Duration(0));
979 assert((cast(D)Duration(-7)) / 5 == Duration(-1));
980
981 assert((cast(D)Duration(-5)) / -7 == Duration(0));
982 assert((cast(D)Duration(-7)) / -5 == Duration(1));
983 }
984 }
985
986
987 /++
988 Multiplies/Divides the duration by an integer value as well as
989 assigning the result to this $(D Duration).
990
991 The legal types of arithmetic for $(D Duration) using this operator
992 overload are
993
994 $(TABLE
995 $(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration))
996 $(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration))
997 )
998
999 Params:
1000 value = The value to multiply/divide this $(D Duration) by.
1001 +/
1002 ref Duration opOpAssign(string op)(long value) nothrow @nogc
1003 if (op == "*" || op == "/")
1004 {
1005 mixin("_hnsecs " ~ op ~ "= value;");
1006 return this;
1007 }
1008
1009 version (CoreUnittest) unittest
1010 {
1011 static void test(D)(D actual, long value, Duration expected, size_t line = __LINE__)
1012 {
1013 if ((actual *= value) != expected)
1014 throw new AssertError("op failed", __FILE__, line);
1015
1016 if (actual != expected)
1017 throw new AssertError("op assign failed", __FILE__, line);
1018 }
1019
1020 test(Duration(5), 7, Duration(35));
1021 test(Duration(7), 5, Duration(35));
1022
1023 test(Duration(5), -7, Duration(-35));
1024 test(Duration(7), -5, Duration(-35));
1025
1026 test(Duration(-5), 7, Duration(-35));
1027 test(Duration(-7), 5, Duration(-35));
1028
1029 test(Duration(-5), -7, Duration(35));
1030 test(Duration(-7), -5, Duration(35));
1031
1032 test(Duration(5), 0, Duration(0));
1033 test(Duration(-5), 0, Duration(0));
1034
1035 const cdur = Duration(12);
1036 immutable idur = Duration(12);
1037 static assert(!__traits(compiles, cdur *= 12));
1038 static assert(!__traits(compiles, idur *= 12));
1039 }
1040
1041 version (CoreUnittest) unittest
1042 {
1043 static void test(Duration actual, long value, Duration expected, size_t line = __LINE__)
1044 {
1045 if ((actual /= value) != expected)
1046 throw new AssertError("op failed", __FILE__, line);
1047
1048 if (actual != expected)
1049 throw new AssertError("op assign failed", __FILE__, line);
1050 }
1051
1052 test(Duration(5), 7, Duration(0));
1053 test(Duration(7), 5, Duration(1));
1054
1055 test(Duration(5), -7, Duration(0));
1056 test(Duration(7), -5, Duration(-1));
1057
1058 test(Duration(-5), 7, Duration(0));
1059 test(Duration(-7), 5, Duration(-1));
1060
1061 test(Duration(-5), -7, Duration(0));
1062 test(Duration(-7), -5, Duration(1));
1063
1064 const cdur = Duration(12);
1065 immutable idur = Duration(12);
1066 static assert(!__traits(compiles, cdur /= 12));
1067 static assert(!__traits(compiles, idur /= 12));
1068 }
1069
1070
1071 /++
1072 Divides two durations.
1073
1074 The legal types of arithmetic for $(D Duration) using this operator are
1075
1076 $(TABLE
1077 $(TR $(TD Duration) $(TD /) $(TD Duration) $(TD -->) $(TD long))
1078 )
1079
1080 Params:
1081 rhs = The duration to divide this $(D Duration) by.
1082 +/
1083 long opBinary(string op)(Duration rhs) const nothrow @nogc
1084 if (op == "/")
1085 {
1086 return _hnsecs / rhs._hnsecs;
1087 }
1088
1089 version (CoreUnittest) unittest
1090 {
1091 assert(Duration(5) / Duration(7) == 0);
1092 assert(Duration(7) / Duration(5) == 1);
1093 assert(Duration(8) / Duration(4) == 2);
1094
1095 assert(Duration(5) / Duration(-7) == 0);
1096 assert(Duration(7) / Duration(-5) == -1);
1097 assert(Duration(8) / Duration(-4) == -2);
1098
1099 assert(Duration(-5) / Duration(7) == 0);
1100 assert(Duration(-7) / Duration(5) == -1);
1101 assert(Duration(-8) / Duration(4) == -2);
1102
1103 assert(Duration(-5) / Duration(-7) == 0);
1104 assert(Duration(-7) / Duration(-5) == 1);
1105 assert(Duration(-8) / Duration(-4) == 2);
1106 }
1107
1108
1109 /++
1110 Multiplies an integral value and a $(D Duration).
1111
1112 The legal types of arithmetic for $(D Duration) using this operator
1113 overload are
1114
1115 $(TABLE
1116 $(TR $(TD long) $(TD *) $(TD Duration) $(TD -->) $(TD Duration))
1117 )
1118
1119 Params:
1120 value = The number of units to multiply this $(D Duration) by.
1121 +/
1122 Duration opBinaryRight(string op)(long value) const nothrow @nogc
1123 if (op == "*")
1124 {
1125 return opBinary!op(value);
1126 }
1127
1128 version (CoreUnittest) unittest
1129 {
1130 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
1131 {
1132 assert(5 * cast(D)Duration(7) == Duration(35));
1133 assert(7 * cast(D)Duration(5) == Duration(35));
1134
1135 assert(5 * cast(D)Duration(-7) == Duration(-35));
1136 assert(7 * cast(D)Duration(-5) == Duration(-35));
1137
1138 assert(-5 * cast(D)Duration(7) == Duration(-35));
1139 assert(-7 * cast(D)Duration(5) == Duration(-35));
1140
1141 assert(-5 * cast(D)Duration(-7) == Duration(35));
1142 assert(-7 * cast(D)Duration(-5) == Duration(35));
1143
1144 assert(0 * cast(D)Duration(-5) == Duration(0));
1145 assert(0 * cast(D)Duration(5) == Duration(0));
1146 }
1147 }
1148
1149
1150 /++
1151 Returns the negation of this $(D Duration).
1152 +/
1153 Duration opUnary(string op)() const nothrow @nogc
1154 if (op == "-")
1155 {
1156 return Duration(-_hnsecs);
1157 }
1158
1159 version (CoreUnittest) unittest
1160 {
1161 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
1162 {
1163 assert(-(cast(D)Duration(7)) == Duration(-7));
1164 assert(-(cast(D)Duration(5)) == Duration(-5));
1165 assert(-(cast(D)Duration(-7)) == Duration(7));
1166 assert(-(cast(D)Duration(-5)) == Duration(5));
1167 assert(-(cast(D)Duration(0)) == Duration(0));
1168 }
1169 }
1170
1171
1172 /++
1173 Returns a $(LREF TickDuration) with the same number of hnsecs as this
1174 $(D Duration).
1175 Note that the conventional way to convert between $(D Duration) and
1176 $(D TickDuration) is using $(REF to, std,conv), e.g.:
1177 $(D duration.to!TickDuration())
1178 +/
1179 TickDuration opCast(T)() const nothrow @nogc
1180 if (is(immutable T == immutable TickDuration))
1181 {
1182 return TickDuration.from!"hnsecs"(_hnsecs);
1183 }
1184
1185 version (CoreUnittest) unittest
1186 {
1187 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
1188 {
1189 foreach (units; AliasSeq!("seconds", "msecs", "usecs", "hnsecs"))
1190 {
1191 enum unitsPerSec = convert!("seconds", units)(1);
1192
1193 if (TickDuration.ticksPerSec >= unitsPerSec)
1194 {
1195 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
1196 {
1197 auto t = TickDuration.from!units(1);
1198 assertApprox(cast(T)cast(D)dur!units(1), t - TickDuration(1), t + TickDuration(1), units);
1199 t = TickDuration.from!units(2);
1200 assertApprox(cast(T)cast(D)dur!units(2), t - TickDuration(1), t + TickDuration(1), units);
1201 }
1202 }
1203 else
1204 {
1205 auto t = TickDuration.from!units(1);
1206 assert(t.to!(units, long)() == 0, units);
1207 t = TickDuration.from!units(1_000_000);
1208 assert(t.to!(units, long)() >= 900_000, units);
1209 assert(t.to!(units, long)() <= 1_100_000, units);
1210 }
1211 }
1212 }
1213 }
1214
1215 /++
1216 Allow Duration to be used as a boolean.
1217 Returns: `true` if this duration is non-zero.
1218 +/
1219 bool opCast(T : bool)() const nothrow @nogc
1220 {
1221 return _hnsecs != 0;
1222 }
1223
1224 version (CoreUnittest) unittest
1225 {
1226 auto d = 10.minutes;
1227 assert(d);
1228 assert(!(d - d));
1229 assert(d + d);
1230 }
1231
1232 //Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=5747 is fixed.
1233 Duration opCast(T)() const nothrow @nogc
1234 if (is(immutable T == immutable Duration))
1235 {
1236 return this;
1237 }
1238
1239
1240 /++
1241 Splits out the Duration into the given units.
1242
1243 split takes the list of time units to split out as template arguments.
1244 The time unit strings must be given in decreasing order. How it returns
1245 the values for those units depends on the overload used.
1246
1247 The overload which accepts function arguments takes integral types in
1248 the order that the time unit strings were given, and those integers are
1249 passed by $(D ref). split assigns the values for the units to each
1250 corresponding integer. Any integral type may be used, but no attempt is
1251 made to prevent integer overflow, so don't use small integral types in
1252 circumstances where the values for those units aren't likely to fit in
1253 an integral type that small.
1254
1255 The overload with no arguments returns the values for the units in a
1256 struct with members whose names are the same as the given time unit
1257 strings. The members are all $(D long)s. This overload will also work
1258 with no time strings being given, in which case $(I all) of the time
1259 units from weeks through hnsecs will be provided (but no nsecs, since it
1260 would always be $(D 0)).
1261
1262 For both overloads, the entire value of the Duration is split among the
1263 units (rather than splitting the Duration across all units and then only
1264 providing the values for the requested units), so if only one unit is
1265 given, the result is equivalent to $(LREF total).
1266
1267 $(D "nsecs") is accepted by split, but $(D "years") and $(D "months")
1268 are not.
1269
1270 For negative durations, all of the split values will be negative.
1271 +/
1272 template split(units...)
1273 if (allAreAcceptedUnits!("weeks", "days", "hours", "minutes", "seconds",
1274 "msecs", "usecs", "hnsecs", "nsecs")([units]) &&
1275 unitsAreInDescendingOrder([units]))
1276 {
1277 /++ Ditto +/
1278 void split(Args...)(out Args args) const nothrow @nogc
1279 if (units.length != 0 && args.length == units.length && allAreMutableIntegralTypes!Args)
1280 {
1281 long hnsecs = _hnsecs;
1282 foreach (i, unit; units)
1283 {
1284 static if (unit == "nsecs")
1285 args[i] = cast(Args[i])convert!("hnsecs", "nsecs")(hnsecs);
1286 else
1287 args[i] = cast(Args[i])splitUnitsFromHNSecs!unit(hnsecs);
1288 }
1289 }
1290
1291 /++ Ditto +/
1292 auto split() const nothrow @nogc
1293 {
1294 static if (units.length == 0)
1295 return split!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs")();
1296 else
1297 {
1298 static string genMemberDecls()
1299 {
1300 string retval;
1301 foreach (unit; units)
1302 {
1303 retval ~= "long ";
1304 retval ~= unit;
1305 retval ~= "; ";
1306 }
1307 return retval;
1308 }
1309
1310 static struct SplitUnits
1311 {
1312 mixin(genMemberDecls());
1313 }
1314
1315 static string genSplitCall()
1316 {
1317 auto retval = "split(";
1318 foreach (i, unit; units)
1319 {
1320 retval ~= "su.";
1321 retval ~= unit;
1322 if (i < units.length - 1)
1323 retval ~= ", ";
1324 else
1325 retval ~= ");";
1326 }
1327 return retval;
1328 }
1329
1330 SplitUnits su = void;
1331 mixin(genSplitCall());
1332 return su;
1333 }
1334 }
1335
1336 /+
1337 Whether all of the given arguments are integral types.
1338 +/
1339 private template allAreMutableIntegralTypes(Args...)
1340 {
1341 static if (Args.length == 0)
1342 enum allAreMutableIntegralTypes = true;
1343 else static if (!is(Args[0] == long) &&
1344 !is(Args[0] == int) &&
1345 !is(Args[0] == short) &&
1346 !is(Args[0] == byte) &&
1347 !is(Args[0] == ulong) &&
1348 !is(Args[0] == uint) &&
1349 !is(Args[0] == ushort) &&
1350 !is(Args[0] == ubyte))
1351 {
1352 enum allAreMutableIntegralTypes = false;
1353 }
1354 else
1355 enum allAreMutableIntegralTypes = allAreMutableIntegralTypes!(Args[1 .. $]);
1356 }
1357
1358 version (CoreUnittest) unittest
1359 {
1360 foreach (T; AliasSeq!(long, int, short, byte, ulong, uint, ushort, ubyte))
1361 static assert(allAreMutableIntegralTypes!T);
1362 foreach (T; AliasSeq!(long, int, short, byte, ulong, uint, ushort, ubyte))
1363 static assert(!allAreMutableIntegralTypes!(const T));
1364 foreach (T; AliasSeq!(char, wchar, dchar, float, double, real, string))
1365 static assert(!allAreMutableIntegralTypes!T);
1366 static assert(allAreMutableIntegralTypes!(long, int, short, byte));
1367 static assert(!allAreMutableIntegralTypes!(long, int, short, char, byte));
1368 static assert(!allAreMutableIntegralTypes!(long, int*, short));
1369 }
1370 }
1371
1372 ///
1373 unittest
1374 {
1375 {
1376 auto d = dur!"days"(12) + dur!"minutes"(7) + dur!"usecs"(501223);
1377 long days;
1378 int seconds;
1379 short msecs;
1380 d.split!("days", "seconds", "msecs")(days, seconds, msecs);
1381 assert(days == 12);
1382 assert(seconds == 7 * 60);
1383 assert(msecs == 501);
1384
1385 auto splitStruct = d.split!("days", "seconds", "msecs")();
1386 assert(splitStruct.days == 12);
1387 assert(splitStruct.seconds == 7 * 60);
1388 assert(splitStruct.msecs == 501);
1389
1390 auto fullSplitStruct = d.split();
1391 assert(fullSplitStruct.weeks == 1);
1392 assert(fullSplitStruct.days == 5);
1393 assert(fullSplitStruct.hours == 0);
1394 assert(fullSplitStruct.minutes == 7);
1395 assert(fullSplitStruct.seconds == 0);
1396 assert(fullSplitStruct.msecs == 501);
1397 assert(fullSplitStruct.usecs == 223);
1398 assert(fullSplitStruct.hnsecs == 0);
1399
1400 assert(d.split!"minutes"().minutes == d.total!"minutes");
1401 }
1402
1403 {
1404 auto d = dur!"days"(12);
1405 assert(d.split!"weeks"().weeks == 1);
1406 assert(d.split!"days"().days == 12);
1407
1408 assert(d.split().weeks == 1);
1409 assert(d.split().days == 5);
1410 }
1411
1412 {
1413 auto d = dur!"days"(7) + dur!"hnsecs"(42);
1414 assert(d.split!("seconds", "nsecs")().nsecs == 4200);
1415 }
1416
1417 {
1418 auto d = dur!"days"(-7) + dur!"hours"(-9);
1419 auto result = d.split!("days", "hours")();
1420 assert(result.days == -7);
1421 assert(result.hours == -9);
1422 }
1423 }
1424
1425 version (CoreUnittest) pure nothrow unittest
1426 {
1427 foreach (D; AliasSeq!(const Duration, immutable Duration))
1428 {
1429 D d = dur!"weeks"(3) + dur!"days"(5) + dur!"hours"(19) + dur!"minutes"(7) +
1430 dur!"seconds"(2) + dur!"hnsecs"(1234567);
1431 byte weeks;
1432 ubyte days;
1433 short hours;
1434 ushort minutes;
1435 int seconds;
1436 uint msecs;
1437 long usecs;
1438 ulong hnsecs;
1439 long nsecs;
1440
1441 d.split!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs", "nsecs")
1442 (weeks, days, hours, minutes, seconds, msecs, usecs, hnsecs, nsecs);
1443 assert(weeks == 3);
1444 assert(days == 5);
1445 assert(hours == 19);
1446 assert(minutes == 7);
1447 assert(seconds == 2);
1448 assert(msecs == 123);
1449 assert(usecs == 456);
1450 assert(hnsecs == 7);
1451 assert(nsecs == 0);
1452
1453 d.split!("weeks", "days", "hours", "seconds", "usecs")(weeks, days, hours, seconds, usecs);
1454 assert(weeks == 3);
1455 assert(days == 5);
1456 assert(hours == 19);
1457 assert(seconds == 422);
1458 assert(usecs == 123456);
1459
1460 d.split!("days", "minutes", "seconds", "nsecs")(days, minutes, seconds, nsecs);
1461 assert(days == 26);
1462 assert(minutes == 1147);
1463 assert(seconds == 2);
1464 assert(nsecs == 123456700);
1465
1466 d.split!("minutes", "msecs", "usecs", "hnsecs")(minutes, msecs, usecs, hnsecs);
1467 assert(minutes == 38587);
1468 assert(msecs == 2123);
1469 assert(usecs == 456);
1470 assert(hnsecs == 7);
1471
1472 {
1473 auto result = d.split!("weeks", "days", "hours", "minutes", "seconds",
1474 "msecs", "usecs", "hnsecs", "nsecs");
1475 assert(result.weeks == 3);
1476 assert(result.days == 5);
1477 assert(result.hours == 19);
1478 assert(result.minutes == 7);
1479 assert(result.seconds == 2);
1480 assert(result.msecs == 123);
1481 assert(result.usecs == 456);
1482 assert(result.hnsecs == 7);
1483 assert(result.nsecs == 0);
1484 }
1485
1486 {
1487 auto result = d.split!("weeks", "days", "hours", "seconds", "usecs");
1488 assert(result.weeks == 3);
1489 assert(result.days == 5);
1490 assert(result.hours == 19);
1491 assert(result.seconds == 422);
1492 assert(result.usecs == 123456);
1493 }
1494
1495 {
1496 auto result = d.split!("days", "minutes", "seconds", "nsecs")();
1497 assert(result.days == 26);
1498 assert(result.minutes == 1147);
1499 assert(result.seconds == 2);
1500 assert(result.nsecs == 123456700);
1501 }
1502
1503 {
1504 auto result = d.split!("minutes", "msecs", "usecs", "hnsecs")();
1505 assert(result.minutes == 38587);
1506 assert(result.msecs == 2123);
1507 assert(result.usecs == 456);
1508 assert(result.hnsecs == 7);
1509 }
1510
1511 {
1512 auto result = d.split();
1513 assert(result.weeks == 3);
1514 assert(result.days == 5);
1515 assert(result.hours == 19);
1516 assert(result.minutes == 7);
1517 assert(result.seconds == 2);
1518 assert(result.msecs == 123);
1519 assert(result.usecs == 456);
1520 assert(result.hnsecs == 7);
1521 static assert(!is(typeof(result.nsecs)));
1522 }
1523
1524 static assert(!is(typeof(d.split("seconds", "hnsecs")(seconds))));
1525 static assert(!is(typeof(d.split("hnsecs", "seconds", "minutes")(hnsecs, seconds, minutes))));
1526 static assert(!is(typeof(d.split("hnsecs", "seconds", "msecs")(hnsecs, seconds, msecs))));
1527 static assert(!is(typeof(d.split("seconds", "hnecs", "msecs")(seconds, hnsecs, msecs))));
1528 static assert(!is(typeof(d.split("seconds", "msecs", "msecs")(seconds, msecs, msecs))));
1529 static assert(!is(typeof(d.split("hnsecs", "seconds", "minutes")())));
1530 static assert(!is(typeof(d.split("hnsecs", "seconds", "msecs")())));
1531 static assert(!is(typeof(d.split("seconds", "hnecs", "msecs")())));
1532 static assert(!is(typeof(d.split("seconds", "msecs", "msecs")())));
1533 alias AliasSeq!("nsecs", "hnsecs", "usecs", "msecs", "seconds",
1534 "minutes", "hours", "days", "weeks") timeStrs;
1535 foreach (i, str; timeStrs[1 .. $])
1536 static assert(!is(typeof(d.split!(timeStrs[i - 1], str)())));
1537
1538 D nd = -d;
1539
1540 {
1541 auto result = nd.split();
1542 assert(result.weeks == -3);
1543 assert(result.days == -5);
1544 assert(result.hours == -19);
1545 assert(result.minutes == -7);
1546 assert(result.seconds == -2);
1547 assert(result.msecs == -123);
1548 assert(result.usecs == -456);
1549 assert(result.hnsecs == -7);
1550 }
1551
1552 {
1553 auto result = nd.split!("weeks", "days", "hours", "minutes", "seconds", "nsecs")();
1554 assert(result.weeks == -3);
1555 assert(result.days == -5);
1556 assert(result.hours == -19);
1557 assert(result.minutes == -7);
1558 assert(result.seconds == -2);
1559 assert(result.nsecs == -123456700);
1560 }
1561 }
1562 }
1563
1564
1565 /++
1566 Returns the total number of the given units in this $(D Duration).
1567 So, unlike $(D split), it does not strip out the larger units.
1568 +/
1569 @property long total(string units)() const nothrow @nogc
1570 if (units == "weeks" ||
1571 units == "days" ||
1572 units == "hours" ||
1573 units == "minutes" ||
1574 units == "seconds" ||
1575 units == "msecs" ||
1576 units == "usecs" ||
1577 units == "hnsecs" ||
1578 units == "nsecs")
1579 {
1580 return convert!("hnsecs", units)(_hnsecs);
1581 }
1582
1583 ///
1584 unittest
1585 {
1586 assert(dur!"weeks"(12).total!"weeks" == 12);
1587 assert(dur!"weeks"(12).total!"days" == 84);
1588
1589 assert(dur!"days"(13).total!"weeks" == 1);
1590 assert(dur!"days"(13).total!"days" == 13);
1591
1592 assert(dur!"hours"(49).total!"days" == 2);
1593 assert(dur!"hours"(49).total!"hours" == 49);
1594
1595 assert(dur!"nsecs"(2007).total!"hnsecs" == 20);
1596 assert(dur!"nsecs"(2007).total!"nsecs" == 2000);
1597 }
1598
1599 version (CoreUnittest) unittest
1600 {
1601 foreach (D; AliasSeq!(const Duration, immutable Duration))
1602 {
1603 assert((cast(D)dur!"weeks"(12)).total!"weeks" == 12);
1604 assert((cast(D)dur!"weeks"(12)).total!"days" == 84);
1605
1606 assert((cast(D)dur!"days"(13)).total!"weeks" == 1);
1607 assert((cast(D)dur!"days"(13)).total!"days" == 13);
1608
1609 assert((cast(D)dur!"hours"(49)).total!"days" == 2);
1610 assert((cast(D)dur!"hours"(49)).total!"hours" == 49);
1611
1612 assert((cast(D)dur!"nsecs"(2007)).total!"hnsecs" == 20);
1613 assert((cast(D)dur!"nsecs"(2007)).total!"nsecs" == 2000);
1614 }
1615 }
1616
1617 /// Ditto
1618 string toString() const scope nothrow
1619 {
1620 string result;
1621 this.toString((in char[] data) { result ~= data; });
1622 return result;
1623 }
1624
1625 ///
1626 unittest
1627 {
1628 assert(Duration.zero.toString() == "0 hnsecs");
1629 assert(weeks(5).toString() == "5 weeks");
1630 assert(days(2).toString() == "2 days");
1631 assert(hours(1).toString() == "1 hour");
1632 assert(minutes(19).toString() == "19 minutes");
1633 assert(seconds(42).toString() == "42 secs");
1634 assert(msecs(42).toString() == "42 ms");
1635 assert(usecs(27).toString() == "27 μs");
1636 assert(hnsecs(5).toString() == "5 hnsecs");
1637
1638 assert(seconds(121).toString() == "2 minutes and 1 sec");
1639 assert((minutes(5) + seconds(3) + usecs(4)).toString() ==
1640 "5 minutes, 3 secs, and 4 μs");
1641
1642 assert(seconds(-42).toString() == "-42 secs");
1643 assert(usecs(-5239492).toString() == "-5 secs, -239 ms, and -492 μs");
1644 }
1645
1646 version (CoreUnittest) unittest
1647 {
1648 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
1649 {
1650 assert((cast(D)Duration(0)).toString() == "0 hnsecs");
1651 assert((cast(D)Duration(1)).toString() == "1 hnsec");
1652 assert((cast(D)Duration(7)).toString() == "7 hnsecs");
1653 assert((cast(D)Duration(10)).toString() == "1 μs");
1654 assert((cast(D)Duration(20)).toString() == "2 μs");
1655 assert((cast(D)Duration(10_000)).toString() == "1 ms");
1656 assert((cast(D)Duration(20_000)).toString() == "2 ms");
1657 assert((cast(D)Duration(10_000_000)).toString() == "1 sec");
1658 assert((cast(D)Duration(20_000_000)).toString() == "2 secs");
1659 assert((cast(D)Duration(600_000_000)).toString() == "1 minute");
1660 assert((cast(D)Duration(1_200_000_000)).toString() == "2 minutes");
1661 assert((cast(D)Duration(36_000_000_000)).toString() == "1 hour");
1662 assert((cast(D)Duration(72_000_000_000)).toString() == "2 hours");
1663 assert((cast(D)Duration(864_000_000_000)).toString() == "1 day");
1664 assert((cast(D)Duration(1_728_000_000_000)).toString() == "2 days");
1665 assert((cast(D)Duration(6_048_000_000_000)).toString() == "1 week");
1666 assert((cast(D)Duration(12_096_000_000_000)).toString() == "2 weeks");
1667
1668 assert((cast(D)Duration(12)).toString() == "1 μs and 2 hnsecs");
1669 assert((cast(D)Duration(120_795)).toString() == "12 ms, 79 μs, and 5 hnsecs");
1670 assert((cast(D)Duration(12_096_020_900_003)).toString() == "2 weeks, 2 secs, 90 ms, and 3 hnsecs");
1671
1672 assert((cast(D)Duration(-1)).toString() == "-1 hnsecs");
1673 assert((cast(D)Duration(-7)).toString() == "-7 hnsecs");
1674 assert((cast(D)Duration(-10)).toString() == "-1 μs");
1675 assert((cast(D)Duration(-20)).toString() == "-2 μs");
1676 assert((cast(D)Duration(-10_000)).toString() == "-1 ms");
1677 assert((cast(D)Duration(-20_000)).toString() == "-2 ms");
1678 assert((cast(D)Duration(-10_000_000)).toString() == "-1 secs");
1679 assert((cast(D)Duration(-20_000_000)).toString() == "-2 secs");
1680 assert((cast(D)Duration(-600_000_000)).toString() == "-1 minutes");
1681 assert((cast(D)Duration(-1_200_000_000)).toString() == "-2 minutes");
1682 assert((cast(D)Duration(-36_000_000_000)).toString() == "-1 hours");
1683 assert((cast(D)Duration(-72_000_000_000)).toString() == "-2 hours");
1684 assert((cast(D)Duration(-864_000_000_000)).toString() == "-1 days");
1685 assert((cast(D)Duration(-1_728_000_000_000)).toString() == "-2 days");
1686 assert((cast(D)Duration(-6_048_000_000_000)).toString() == "-1 weeks");
1687 assert((cast(D)Duration(-12_096_000_000_000)).toString() == "-2 weeks");
1688
1689 assert((cast(D)Duration(-12)).toString() == "-1 μs and -2 hnsecs");
1690 assert((cast(D)Duration(-120_795)).toString() == "-12 ms, -79 μs, and -5 hnsecs");
1691 assert((cast(D)Duration(-12_096_020_900_003)).toString() == "-2 weeks, -2 secs, -90 ms, and -3 hnsecs");
1692 }
1693 }
1694
1695
1696 /++
1697 Returns whether this $(D Duration) is negative.
1698 +/
1699 @property bool isNegative() const nothrow @nogc
1700 {
1701 return _hnsecs < 0;
1702 }
1703
1704 version (CoreUnittest) unittest
1705 {
1706 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
1707 {
1708 assert(!(cast(D)Duration(100)).isNegative);
1709 assert(!(cast(D)Duration(1)).isNegative);
1710 assert(!(cast(D)Duration(0)).isNegative);
1711 assert((cast(D)Duration(-1)).isNegative);
1712 assert((cast(D)Duration(-100)).isNegative);
1713 }
1714 }
1715
1716
1717 private:
1718
1719 /+
1720 Params:
1721 hnsecs = The total number of hecto-nanoseconds in this $(D Duration).
1722 +/
1723 this(long hnsecs) nothrow @nogc
1724 {
1725 _hnsecs = hnsecs;
1726 }
1727
1728
1729 long _hnsecs;
1730 }
1731
1732 ///
1733 unittest
1734 {
1735 import core.time;
1736
1737 // using the dur template
1738 auto numDays = dur!"days"(12);
1739
1740 // using the days function
1741 numDays = days(12);
1742
1743 // alternatively using UFCS syntax
1744 numDays = 12.days;
1745
1746 auto myTime = 100.msecs + 20_000.usecs + 30_000.hnsecs;
1747 assert(myTime == 123.msecs);
1748 }
1749
1750 // Ensure `toString` doesn't allocate if the sink doesn't
1751 version (CoreUnittest) @safe pure nothrow @nogc unittest
1752 {
1753 char[256] buffer; size_t len;
1754 scope sink = (in char[] data) {
1755 assert(data.length + len <= buffer.length);
1756 buffer[len .. len + data.length] = data[];
1757 len += data.length;
1758 };
1759 auto dur = Duration(-12_096_020_900_003);
1760 dur.toString(sink);
1761 assert(buffer[0 .. len] == "-2 weeks, -2 secs, -90 ms, and -3 hnsecs");
1762 }
1763
1764 /++
1765 Converts a $(D TickDuration) to the given units as either an integral
1766 value or a floating point value.
1767
1768 Params:
1769 units = The units to convert to. Accepts $(D "seconds") and smaller
1770 only.
1771 T = The type to convert to (either an integral type or a
1772 floating point type).
1773
1774 td = The TickDuration to convert
1775 +/
1776 T to(string units, T, D)(D td) @safe pure nothrow @nogc
1777 if (is(immutable D == immutable TickDuration) &&
1778 (units == "seconds" ||
1779 units == "msecs" ||
1780 units == "usecs" ||
1781 units == "hnsecs" ||
1782 units == "nsecs"))
1783 {
1784 static if (__traits(isIntegral, T) && T.sizeof >= 4)
1785 {
1786 enum unitsPerSec = convert!("seconds", units)(1);
1787
1788 return cast(T) (td.length / (TickDuration.ticksPerSec / cast(real) unitsPerSec));
1789 }
1790 else static if (__traits(isFloating, T))
1791 {
1792 static if (units == "seconds")
1793 return td.length / cast(T)TickDuration.ticksPerSec;
1794 else
1795 {
1796 enum unitsPerSec = convert!("seconds", units)(1);
1797
1798 return cast(T) (td.length /
1799 (TickDuration.ticksPerSec / cast(real) unitsPerSec));
1800 }
1801 }
1802 else
1803 static assert(0, "Incorrect template constraint.");
1804 }
1805
1806 ///
1807 unittest
1808 {
1809 auto t = TickDuration.from!"seconds"(1000);
1810
1811 long tl = to!("seconds",long)(t);
1812 assert(tl == 1000);
1813
1814 import core.stdc.math : fabs;
1815 double td = to!("seconds",double)(t);
1816 assert(fabs(td - 1000) < 0.001);
1817 }
1818
1819 unittest
1820 {
1821 void testFun(string U)() {
1822 auto t1v = 1000;
1823 auto t2v = 333;
1824
1825 auto t1 = TickDuration.from!U(t1v);
1826 auto t2 = TickDuration.from!U(t2v);
1827
1828 auto _str(F)(F val)
1829 {
1830 static if (is(F == int) || is(F == long))
1831 return signedToTempString(val);
1832 else
1833 return unsignedToTempString(val);
1834 }
1835
1836 foreach (F; AliasSeq!(int,uint,long,ulong,float,double,real))
1837 {
1838 F t1f = to!(U,F)(t1);
1839 F t2f = to!(U,F)(t2);
1840 auto t12d = t1 / t2v;
1841 auto t12m = t1 - t2;
1842 F t3f = to!(U,F)(t12d);
1843 F t4f = to!(U,F)(t12m);
1844
1845
1846 static if (is(F == float) || is(F == double) || is(F == real))
1847 {
1848 assert((t1f - cast(F)t1v) <= 3.0,
1849 F.stringof ~ " " ~ U ~ " " ~ doubleToString(t1f) ~ " " ~
1850 doubleToString(cast(F)t1v)
1851 );
1852 assert((t2f - cast(F)t2v) <= 3.0,
1853 F.stringof ~ " " ~ U ~ " " ~ doubleToString(t2f) ~ " " ~
1854 doubleToString(cast(F)t2v)
1855 );
1856 assert(t3f - (cast(F)t1v) / (cast(F)t2v) <= 3.0,
1857 F.stringof ~ " " ~ U ~ " " ~ doubleToString(t3f) ~ " " ~
1858 doubleToString((cast(F)t1v)/(cast(F)t2v))
1859 );
1860 assert(t4f - (cast(F)(t1v - t2v)) <= 3.0,
1861 F.stringof ~ " " ~ U ~ " " ~ doubleToString(t4f) ~ " " ~
1862 doubleToString(cast(F)(t1v - t2v))
1863 );
1864 }
1865 else
1866 {
1867 // even though this should be exact math it is not as internal
1868 // in "to" floating point is used
1869 assert(_abs(t1f) - _abs(cast(F)t1v) <= 3,
1870 F.stringof ~ " " ~ U ~ " " ~ _str(t1f) ~ " " ~
1871 _str(cast(F)t1v)
1872 );
1873 assert(_abs(t2f) - _abs(cast(F)t2v) <= 3,
1874 F.stringof ~ " " ~ U ~ " " ~ _str(t2f) ~ " " ~
1875 _str(cast(F)t2v)
1876 );
1877 assert(_abs(t3f) - _abs((cast(F)t1v) / (cast(F)t2v)) <= 3,
1878 F.stringof ~ " " ~ U ~ " " ~ _str(t3f) ~ " " ~
1879 _str((cast(F)t1v) / (cast(F)t2v))
1880 );
1881 assert(_abs(t4f) - _abs((cast(F)t1v) - (cast(F)t2v)) <= 3,
1882 F.stringof ~ " " ~ U ~ " " ~ _str(t4f) ~ " " ~
1883 _str((cast(F)t1v) - (cast(F)t2v))
1884 );
1885 }
1886 }
1887 }
1888
1889 testFun!"seconds"();
1890 testFun!"msecs"();
1891 testFun!"usecs"();
1892 }
1893
1894 /++
1895 These allow you to construct a $(D Duration) from the given time units
1896 with the given length.
1897
1898 You can either use the generic function $(D dur) and give it the units as
1899 a $(D string) or use the named aliases.
1900
1901 The possible values for units are $(D "weeks"), $(D "days"), $(D "hours"),
1902 $(D "minutes"), $(D "seconds"), $(D "msecs") (milliseconds), $(D "usecs"),
1903 (microseconds), $(D "hnsecs") (hecto-nanoseconds, i.e. 100 ns), and
1904 $(D "nsecs").
1905
1906 Params:
1907 units = The time units of the $(D Duration) (e.g. $(D "days")).
1908 length = The number of units in the $(D Duration).
1909 +/
1910 Duration dur(string units)(long length) @safe pure nothrow @nogc
1911 if (units == "weeks" ||
1912 units == "days" ||
1913 units == "hours" ||
1914 units == "minutes" ||
1915 units == "seconds" ||
1916 units == "msecs" ||
1917 units == "usecs" ||
1918 units == "hnsecs" ||
1919 units == "nsecs")
1920 {
1921 return Duration(convert!(units, "hnsecs")(length));
1922 }
1923
1924 alias weeks = dur!"weeks"; /// Ditto
1925 alias days = dur!"days"; /// Ditto
1926 alias hours = dur!"hours"; /// Ditto
1927 alias minutes = dur!"minutes"; /// Ditto
1928 alias seconds = dur!"seconds"; /// Ditto
1929 alias msecs = dur!"msecs"; /// Ditto
1930 alias usecs = dur!"usecs"; /// Ditto
1931 alias hnsecs = dur!"hnsecs"; /// Ditto
1932 alias nsecs = dur!"nsecs"; /// Ditto
1933
1934 ///
1935 unittest
1936 {
1937 // Generic
1938 assert(dur!"weeks"(142).total!"weeks" == 142);
1939 assert(dur!"days"(142).total!"days" == 142);
1940 assert(dur!"hours"(142).total!"hours" == 142);
1941 assert(dur!"minutes"(142).total!"minutes" == 142);
1942 assert(dur!"seconds"(142).total!"seconds" == 142);
1943 assert(dur!"msecs"(142).total!"msecs" == 142);
1944 assert(dur!"usecs"(142).total!"usecs" == 142);
1945 assert(dur!"hnsecs"(142).total!"hnsecs" == 142);
1946 assert(dur!"nsecs"(142).total!"nsecs" == 100);
1947
1948 // Non-generic
1949 assert(weeks(142).total!"weeks" == 142);
1950 assert(days(142).total!"days" == 142);
1951 assert(hours(142).total!"hours" == 142);
1952 assert(minutes(142).total!"minutes" == 142);
1953 assert(seconds(142).total!"seconds" == 142);
1954 assert(msecs(142).total!"msecs" == 142);
1955 assert(usecs(142).total!"usecs" == 142);
1956 assert(hnsecs(142).total!"hnsecs" == 142);
1957 assert(nsecs(142).total!"nsecs" == 100);
1958 }
1959
1960 unittest
1961 {
1962 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
1963 {
1964 assert(dur!"weeks"(7).total!"weeks" == 7);
1965 assert(dur!"days"(7).total!"days" == 7);
1966 assert(dur!"hours"(7).total!"hours" == 7);
1967 assert(dur!"minutes"(7).total!"minutes" == 7);
1968 assert(dur!"seconds"(7).total!"seconds" == 7);
1969 assert(dur!"msecs"(7).total!"msecs" == 7);
1970 assert(dur!"usecs"(7).total!"usecs" == 7);
1971 assert(dur!"hnsecs"(7).total!"hnsecs" == 7);
1972 assert(dur!"nsecs"(7).total!"nsecs" == 0);
1973
1974 assert(dur!"weeks"(1007) == weeks(1007));
1975 assert(dur!"days"(1007) == days(1007));
1976 assert(dur!"hours"(1007) == hours(1007));
1977 assert(dur!"minutes"(1007) == minutes(1007));
1978 assert(dur!"seconds"(1007) == seconds(1007));
1979 assert(dur!"msecs"(1007) == msecs(1007));
1980 assert(dur!"usecs"(1007) == usecs(1007));
1981 assert(dur!"hnsecs"(1007) == hnsecs(1007));
1982 assert(dur!"nsecs"(10) == nsecs(10));
1983 }
1984 }
1985
1986 // used in MonoTimeImpl
1987 private string _clockTypeName(ClockType clockType)
1988 {
1989 final switch (clockType)
1990 {
1991 foreach (name; __traits(allMembers, ClockType))
1992 {
1993 case __traits(getMember, ClockType, name):
1994 return name;
1995 }
1996 }
1997 assert(0);
1998 }
1999
2000 // used in MonoTimeImpl
2001 private size_t _clockTypeIdx(ClockType clockType)
2002 {
2003 final switch (clockType)
2004 {
2005 foreach (i, name; __traits(allMembers, ClockType))
2006 {
2007 case __traits(getMember, ClockType, name):
2008 return i;
2009 }
2010 }
2011 assert(0);
2012 }
2013
2014
2015 /++
2016 alias for $(D MonoTimeImpl) instantiated with $(D ClockType.normal). This is
2017 what most programs should use. It's also what much of $(D MonoTimeImpl) uses
2018 in its documentation (particularly in the examples), because that's what's
2019 going to be used in most code.
2020 +/
2021 alias MonoTime = MonoTimeImpl!(ClockType.normal);
2022
2023 /++
2024 Represents a timestamp of the system's monotonic clock.
2025
2026 A monotonic clock is one which always goes forward and never moves
2027 backwards, unlike the system's wall clock time (as represented by
2028 $(REF SysTime, std,datetime)). The system's wall clock time can be adjusted
2029 by the user or by the system itself via services such as NTP, so it is
2030 unreliable to use the wall clock time for timing. Timers which use the wall
2031 clock time could easily end up never going off due to changes made to the
2032 wall clock time or otherwise waiting for a different period of time than
2033 that specified by the programmer. However, because the monotonic clock
2034 always increases at a fixed rate and is not affected by adjustments to the
2035 wall clock time, it is ideal for use with timers or anything which requires
2036 high precision timing.
2037
2038 So, MonoTime should be used for anything involving timers and timing,
2039 whereas $(REF SysTime, std,datetime) should be used when the wall clock time
2040 is required.
2041
2042 The monotonic clock has no relation to wall clock time. Rather, it holds
2043 its time as the number of ticks of the clock which have occurred since the
2044 clock started (typically when the system booted up). So, to determine how
2045 much time has passed between two points in time, one monotonic time is
2046 subtracted from the other to determine the number of ticks which occurred
2047 between the two points of time, and those ticks are divided by the number of
2048 ticks that occur every second (as represented by MonoTime.ticksPerSecond)
2049 to get a meaningful duration of time. Normally, MonoTime does these
2050 calculations for the programmer, but the $(D ticks) and $(D ticksPerSecond)
2051 properties are provided for those who require direct access to the system
2052 ticks. The normal way that MonoTime would be used is
2053
2054 --------------------
2055 MonoTime before = MonoTime.currTime;
2056 // do stuff...
2057 MonoTime after = MonoTime.currTime;
2058 Duration timeElapsed = after - before;
2059 --------------------
2060
2061 $(LREF MonoTime) is an alias to $(D MonoTimeImpl!(ClockType.normal)) and is
2062 what most programs should use for the monotonic clock, so that's what is
2063 used in most of $(D MonoTimeImpl)'s documentation. But $(D MonoTimeImpl)
2064 can be instantiated with other clock types for those rare programs that need
2065 it.
2066
2067 See_Also:
2068 $(LREF ClockType)
2069 +/
MonoTimeImpl(ClockType clockType)2070 struct MonoTimeImpl(ClockType clockType)
2071 {
2072 private enum _clockIdx = _clockTypeIdx(clockType);
2073 private enum _clockName = _clockTypeName(clockType);
2074
2075 @safe:
2076
2077 version (Windows)
2078 {
2079 static if (clockType != ClockType.coarse &&
2080 clockType != ClockType.normal &&
2081 clockType != ClockType.precise)
2082 {
2083 static assert(0, "ClockType." ~ _clockName ~
2084 " is not supported by MonoTimeImpl on this system.");
2085 }
2086 }
2087 else version (Darwin)
2088 {
2089 static if (clockType != ClockType.coarse &&
2090 clockType != ClockType.normal &&
2091 clockType != ClockType.precise)
2092 {
2093 static assert(0, "ClockType." ~ _clockName ~
2094 " is not supported by MonoTimeImpl on this system.");
2095 }
2096 }
2097 else version (Posix)
2098 {
2099 enum clockArg = _posixClock(clockType);
2100 }
2101 else
2102 static assert(0, "Unsupported platform");
2103
2104 // POD value, test mutable/const/immutable conversion
2105 version (CoreUnittest) unittest
2106 {
2107 MonoTimeImpl m;
2108 const MonoTimeImpl cm = m;
2109 immutable MonoTimeImpl im = m;
2110 m = cm;
2111 m = im;
2112 }
2113
2114 /++
2115 The current time of the system's monotonic clock. This has no relation
2116 to the wall clock time, as the wall clock time can be adjusted (e.g.
2117 by NTP), whereas the monotonic clock always moves forward. The source
2118 of the monotonic time is system-specific.
2119
2120 On Windows, $(D QueryPerformanceCounter) is used. On Mac OS X,
2121 $(D mach_absolute_time) is used, while on other POSIX systems,
2122 $(D clock_gettime) is used.
2123
2124 $(RED Warning): On some systems, the monotonic clock may stop counting
2125 when the computer goes to sleep or hibernates. So, the
2126 monotonic clock may indicate less time than has actually
2127 passed if that occurs. This is known to happen on
2128 Mac OS X. It has not been tested whether it occurs on
2129 either Windows or Linux.
2130 +/
2131 static @property MonoTimeImpl currTime() @trusted nothrow @nogc
2132 {
2133 if (ticksPerSecond == 0)
2134 {
2135 import core.internal.abort : abort;
2136 abort("MonoTimeImpl!(ClockType." ~ _clockName ~
2137 ") failed to get the frequency of the system's monotonic clock.");
2138 }
2139
2140 version (Windows)
2141 {
2142 long ticks = void;
2143 QueryPerformanceCounter(&ticks);
2144 return MonoTimeImpl(ticks);
2145 }
2146 else version (Darwin)
2147 return MonoTimeImpl(mach_absolute_time());
2148 else version (Posix)
2149 {
2150 timespec ts = void;
2151 immutable error = clock_gettime(clockArg, &ts);
2152 // clockArg is supported and if tv_sec is long or larger
2153 // overflow won't happen before 292 billion years A.D.
2154 static if (ts.tv_sec.max < long.max)
2155 {
2156 if (error)
2157 {
2158 import core.internal.abort : abort;
2159 abort("Call to clock_gettime failed.");
2160 }
2161 }
2162 return MonoTimeImpl(convClockFreq(ts.tv_sec * 1_000_000_000L + ts.tv_nsec,
2163 1_000_000_000L,
2164 ticksPerSecond));
2165 }
2166 }
2167
2168
2169 static @property pure nothrow @nogc
2170 {
2171 /++
2172 A $(D MonoTime) of $(D 0) ticks. It's provided to be consistent with
2173 $(D Duration.zero), and it's more explicit than $(D MonoTime.init).
2174 +/
2175 MonoTimeImpl zero() { return MonoTimeImpl(0); }
2176
2177 /++
2178 Largest $(D MonoTime) possible.
2179 +/
2180 MonoTimeImpl max() { return MonoTimeImpl(long.max); }
2181
2182 /++
2183 Most negative $(D MonoTime) possible.
2184 +/
2185 MonoTimeImpl min() { return MonoTimeImpl(long.min); }
2186 }
2187
2188 version (CoreUnittest) unittest
2189 {
2190 assert(MonoTimeImpl.zero == MonoTimeImpl(0));
2191 assert(MonoTimeImpl.max == MonoTimeImpl(long.max));
2192 assert(MonoTimeImpl.min == MonoTimeImpl(long.min));
2193 assert(MonoTimeImpl.min < MonoTimeImpl.zero);
2194 assert(MonoTimeImpl.zero < MonoTimeImpl.max);
2195 assert(MonoTimeImpl.min < MonoTimeImpl.max);
2196 }
2197
2198
2199 /++
2200 Compares this MonoTime with the given MonoTime.
2201
2202 Returns:
2203 $(BOOKTABLE,
2204 $(TR $(TD this < rhs) $(TD < 0))
2205 $(TR $(TD this == rhs) $(TD 0))
2206 $(TR $(TD this > rhs) $(TD > 0))
2207 )
2208 +/
2209 int opCmp(MonoTimeImpl rhs) const pure nothrow @nogc
2210 {
2211 return (_ticks > rhs._ticks) - (_ticks < rhs._ticks);
2212 }
2213
2214 version (CoreUnittest) unittest
2215 {
2216 import core.internal.traits : rvalueOf;
2217 const t = MonoTimeImpl.currTime;
2218 assert(t == rvalueOf(t));
2219 }
2220
2221 version (CoreUnittest) unittest
2222 {
2223 import core.internal.traits : rvalueOf;
2224 const before = MonoTimeImpl.currTime;
2225 auto after = MonoTimeImpl(before._ticks + 42);
2226 assert(before < after);
2227 assert(rvalueOf(before) <= before);
2228 assert(rvalueOf(after) > before);
2229 assert(after >= rvalueOf(after));
2230 }
2231
2232 version (CoreUnittest) unittest
2233 {
2234 const currTime = MonoTimeImpl.currTime;
2235 assert(MonoTimeImpl(long.max) > MonoTimeImpl(0));
2236 assert(MonoTimeImpl(0) > MonoTimeImpl(long.min));
2237 assert(MonoTimeImpl(long.max) > currTime);
2238 assert(currTime > MonoTimeImpl(0));
2239 assert(MonoTimeImpl(0) < currTime);
2240 assert(MonoTimeImpl(0) < MonoTimeImpl(long.max));
2241 assert(MonoTimeImpl(long.min) < MonoTimeImpl(0));
2242 }
2243
2244
2245 /++
2246 Subtracting two MonoTimes results in a $(LREF Duration) representing
2247 the amount of time which elapsed between them.
2248
2249 The primary way that programs should time how long something takes is to
2250 do
2251 --------------------
2252 MonoTime before = MonoTime.currTime;
2253 // do stuff
2254 MonoTime after = MonoTime.currTime;
2255
2256 // How long it took.
2257 Duration timeElapsed = after - before;
2258 --------------------
2259 or to use a wrapper (such as a stop watch type) which does that.
2260
2261 $(RED Warning):
2262 Because $(LREF Duration) is in hnsecs, whereas MonoTime is in system
2263 ticks, it's usually the case that this assertion will fail
2264 --------------------
2265 auto before = MonoTime.currTime;
2266 // do stuff
2267 auto after = MonoTime.currTime;
2268 auto timeElapsed = after - before;
2269 assert(before + timeElapsed == after);
2270 --------------------
2271
2272 This is generally fine, and by its very nature, converting from
2273 system ticks to any type of seconds (hnsecs, nsecs, etc.) will
2274 introduce rounding errors, but if code needs to avoid any of the
2275 small rounding errors introduced by conversion, then it needs to use
2276 MonoTime's $(D ticks) property and keep all calculations in ticks
2277 rather than using $(LREF Duration).
2278 +/
2279 Duration opBinary(string op)(MonoTimeImpl rhs) const pure nothrow @nogc
2280 if (op == "-")
2281 {
2282 immutable diff = _ticks - rhs._ticks;
2283 return Duration(convClockFreq(diff , ticksPerSecond, hnsecsPer!"seconds"));
2284 }
2285
2286 version (CoreUnittest) unittest
2287 {
2288 import core.internal.traits : rvalueOf;
2289 const t = MonoTimeImpl.currTime;
2290 assert(t - rvalueOf(t) == Duration.zero);
2291 static assert(!__traits(compiles, t + t));
2292 }
2293
2294 version (CoreUnittest) unittest
2295 {
2296 static void test(const scope MonoTimeImpl before, const scope MonoTimeImpl after, const scope Duration min)
2297 {
2298 immutable diff = after - before;
2299 assert(diff >= min);
2300 auto calcAfter = before + diff;
2301 assertApprox(calcAfter, calcAfter - Duration(1), calcAfter + Duration(1));
2302 assert(before - after == -diff);
2303 }
2304
2305 const before = MonoTimeImpl.currTime;
2306 test(before, MonoTimeImpl(before._ticks + 4202), Duration.zero);
2307 test(before, MonoTimeImpl.currTime, Duration.zero);
2308
2309 const durLargerUnits = dur!"minutes"(7) + dur!"seconds"(22);
2310 test(before, before + durLargerUnits + dur!"msecs"(33) + dur!"hnsecs"(571), durLargerUnits);
2311 }
2312
2313
2314 /++
2315 Adding or subtracting a $(LREF Duration) to/from a MonoTime results in
2316 a MonoTime which is adjusted by that amount.
2317 +/
2318 MonoTimeImpl opBinary(string op)(Duration rhs) const pure nothrow @nogc
2319 if (op == "+" || op == "-")
2320 {
2321 immutable rhsConverted = convClockFreq(rhs._hnsecs, hnsecsPer!"seconds", ticksPerSecond);
2322 mixin("return MonoTimeImpl(_ticks " ~ op ~ " rhsConverted);");
2323 }
2324
2325 version (CoreUnittest) unittest
2326 {
2327 const t = MonoTimeImpl.currTime;
2328 assert(t + Duration(0) == t);
2329 assert(t - Duration(0) == t);
2330 }
2331
2332 version (CoreUnittest) unittest
2333 {
2334 const t = MonoTimeImpl.currTime;
2335
2336 // We reassign ticks in order to get the same rounding errors
2337 // that we should be getting with Duration (e.g. MonoTimeImpl may be
2338 // at a higher precision than hnsecs, meaning that 7333 would be
2339 // truncated when converting to hnsecs).
2340 long ticks = 7333;
2341 auto hnsecs = convClockFreq(ticks, ticksPerSecond, hnsecsPer!"seconds");
2342 ticks = convClockFreq(hnsecs, hnsecsPer!"seconds", ticksPerSecond);
2343
2344 assert(t - Duration(hnsecs) == MonoTimeImpl(t._ticks - ticks));
2345 assert(t + Duration(hnsecs) == MonoTimeImpl(t._ticks + ticks));
2346 }
2347
2348
2349 /++ Ditto +/
2350 ref MonoTimeImpl opOpAssign(string op)(Duration rhs) pure nothrow @nogc
2351 if (op == "+" || op == "-")
2352 {
2353 immutable rhsConverted = convClockFreq(rhs._hnsecs, hnsecsPer!"seconds", ticksPerSecond);
2354 mixin("_ticks " ~ op ~ "= rhsConverted;");
2355 return this;
2356 }
2357
2358 version (CoreUnittest) unittest
2359 {
2360 auto mt = MonoTimeImpl.currTime;
2361 const initial = mt;
2362 mt += Duration(0);
2363 assert(mt == initial);
2364 mt -= Duration(0);
2365 assert(mt == initial);
2366
2367 // We reassign ticks in order to get the same rounding errors
2368 // that we should be getting with Duration (e.g. MonoTimeImpl may be
2369 // at a higher precision than hnsecs, meaning that 7333 would be
2370 // truncated when converting to hnsecs).
2371 long ticks = 7333;
2372 auto hnsecs = convClockFreq(ticks, ticksPerSecond, hnsecsPer!"seconds");
2373 ticks = convClockFreq(hnsecs, hnsecsPer!"seconds", ticksPerSecond);
2374 auto before = MonoTimeImpl(initial._ticks - ticks);
2375
2376 assert((mt -= Duration(hnsecs)) == before);
2377 assert(mt == before);
2378 assert((mt += Duration(hnsecs)) == initial);
2379 assert(mt == initial);
2380 }
2381
2382
2383 /++
2384 The number of ticks in the monotonic time.
2385
2386 Most programs should not use this directly, but it's exposed for those
2387 few programs that need it.
2388
2389 The main reasons that a program might need to use ticks directly is if
2390 the system clock has higher precision than hnsecs, and the program needs
2391 that higher precision, or if the program needs to avoid the rounding
2392 errors caused by converting to hnsecs.
2393 +/
2394 @property long ticks() const pure nothrow @nogc
2395 {
2396 return _ticks;
2397 }
2398
2399 version (CoreUnittest) unittest
2400 {
2401 const mt = MonoTimeImpl.currTime;
2402 assert(mt.ticks == mt._ticks);
2403 }
2404
2405
2406 /++
2407 The number of ticks that MonoTime has per second - i.e. the resolution
2408 or frequency of the system's monotonic clock.
2409
2410 e.g. if the system clock had a resolution of microseconds, then
2411 ticksPerSecond would be $(D 1_000_000).
2412 +/
2413 static @property long ticksPerSecond() pure nothrow @nogc
2414 {
2415 return _ticksPerSecond[_clockIdx];
2416 }
2417
2418 version (CoreUnittest) unittest
2419 {
2420 assert(MonoTimeImpl.ticksPerSecond == _ticksPerSecond[_clockIdx]);
2421 }
2422
2423
2424 ///
2425 string toString() const pure nothrow
2426 {
2427 static if (clockType == ClockType.normal)
2428 return "MonoTime(" ~ signedToTempString(_ticks) ~ " ticks, " ~ signedToTempString(ticksPerSecond) ~ " ticks per second)";
2429 else
2430 return "MonoTimeImpl!(ClockType." ~ _clockName ~ ")(" ~ signedToTempString(_ticks) ~ " ticks, " ~
2431 signedToTempString(ticksPerSecond) ~ " ticks per second)";
2432 }
2433
2434 version (CoreUnittest) unittest
2435 {
2436 import core.internal.util.math : min;
2437
2438 static void eat(ref string s, const(char)[] exp)
2439 {
2440 assert(s[0 .. min($, exp.length)] == exp, s~" != "~exp);
2441 s = s[exp.length .. $];
2442 }
2443
2444 immutable mt = MonoTimeImpl.currTime;
2445 auto str = mt.toString();
2446 static if (is(typeof(this) == MonoTime))
2447 eat(str, "MonoTime(");
2448 else
2449 eat(str, "MonoTimeImpl!(ClockType."~_clockName~")(");
2450
2451 eat(str, signedToTempString(mt._ticks));
2452 eat(str, " ticks, ");
2453 eat(str, signedToTempString(ticksPerSecond));
2454 eat(str, " ticks per second)");
2455 }
2456
2457 private:
2458
2459 // static immutable long _ticksPerSecond;
2460
2461 version (CoreUnittest) unittest
2462 {
2463 assert(_ticksPerSecond[_clockIdx]);
2464 }
2465
2466
2467 long _ticks;
2468 }
2469
2470 // This is supposed to be a static variable in MonoTimeImpl with the static
2471 // constructor being in there, but https://issues.dlang.org/show_bug.cgi?id=14517
2472 // prevents that from working. However, moving it back to a static ctor will
2473 // reraise issues with other systems using MonoTime, so we should leave this
2474 // here even when that bug is fixed.
2475 private immutable long[__traits(allMembers, ClockType).length] _ticksPerSecond;
2476
2477 // This is called directly from the runtime initilization function (rt_init),
2478 // instead of using a static constructor. Other subsystems inside the runtime
2479 // (namely, the GC) may need time functionality, but cannot wait until the
2480 // static ctors have run. Therefore, we initialize these specially. Because
2481 // it's a normal function, we need to do some dangerous casting PLEASE take
2482 // care when modifying this function, and it should NOT be called except from
2483 // the runtime init.
2484 //
2485 // NOTE: the code below SPECIFICALLY does not assert when it cannot initialize
2486 // the ticks per second array. This allows cases where a clock is never used on
2487 // a system that doesn't support it. See bugzilla issue
2488 // https://issues.dlang.org/show_bug.cgi?id=14863
2489 // The assert will occur when someone attempts to use _ticksPerSecond for that
2490 // value.
_d_initMonoTime()2491 extern(C) void _d_initMonoTime()
2492 {
2493 // We need a mutable pointer to the ticksPerSecond array. Although this
2494 // would appear to break immutability, it is logically the same as a static
2495 // ctor. So we should ONLY write these values once (we will check for 0
2496 // values when setting to ensure this is truly only called once).
2497 auto tps = cast(long[])_ticksPerSecond[];
2498
2499 // If we try to do anything with ClockType in the documentation build, it'll
2500 // trigger the static assertions related to ClockType, since the
2501 // documentation build defines all of the possible ClockTypes, which won't
2502 // work when they're used in the static ifs, because no system supports them
2503 // all.
2504 version (CoreDdoc)
2505 {}
2506 else version (Windows)
2507 {
2508 long ticksPerSecond;
2509 if (QueryPerformanceFrequency(&ticksPerSecond) != 0)
2510 {
2511 foreach (i, typeStr; __traits(allMembers, ClockType))
2512 {
2513 // ensure we are only writing immutable data once
2514 if (tps[i] != 0)
2515 // should only be called once
2516 assert(0);
2517 tps[i] = ticksPerSecond;
2518 }
2519 }
2520 }
2521 else version (Darwin)
2522 {
2523 immutable long ticksPerSecond = machTicksPerSecond();
2524 foreach (i, typeStr; __traits(allMembers, ClockType))
2525 {
2526 // ensure we are only writing immutable data once
2527 if (tps[i] != 0)
2528 // should only be called once
2529 assert(0);
2530 tps[i] = ticksPerSecond;
2531 }
2532 }
2533 else version (Posix)
2534 {
2535 timespec ts;
2536 foreach (i, typeStr; __traits(allMembers, ClockType))
2537 {
2538 static if (typeStr != "second")
2539 {
2540 enum clockArg = _posixClock(__traits(getMember, ClockType, typeStr));
2541 if (clock_getres(clockArg, &ts) == 0)
2542 {
2543 // ensure we are only writing immutable data once
2544 if (tps[i] != 0)
2545 // should only be called once
2546 assert(0);
2547
2548 // For some reason, on some systems, clock_getres returns
2549 // a resolution which is clearly wrong:
2550 // - it's a millisecond or worse, but the time is updated
2551 // much more frequently than that.
2552 // - it's negative
2553 // - it's zero
2554 // In such cases, we'll just use nanosecond resolution.
2555 tps[i] = ts.tv_sec != 0 || ts.tv_nsec <= 0 || ts.tv_nsec >= 1000
2556 ? 1_000_000_000L : 1_000_000_000L / ts.tv_nsec;
2557 }
2558 }
2559 }
2560 }
2561 }
2562
2563
2564 // Tests for MonoTimeImpl.currTime. It has to be outside, because MonoTimeImpl
2565 // is a template. This unittest block also makes sure that MonoTimeImpl actually
2566 // is instantiated with all of the various ClockTypes so that those types and
2567 // their tests are compiled and run.
2568 unittest
2569 {
2570 // This test is separate so that it can be tested with MonoTime and not just
2571 // MonoTimeImpl.
2572 auto norm1 = MonoTime.currTime;
2573 auto norm2 = MonoTimeImpl!(ClockType.normal).currTime;
2574 assert(norm1 <= norm2);
2575
clockSupported(ClockType c)2576 static bool clockSupported(ClockType c)
2577 {
2578 // Skip unsupported clocks on older linux kernels, assume that only
2579 // CLOCK_MONOTONIC and CLOCK_REALTIME exist, as that is the lowest
2580 // common denominator supported by all versions of Linux pre-2.6.12.
2581 version (Linux_Pre_2639)
2582 return c == ClockType.normal || c == ClockType.precise;
2583 else
2584 return c != ClockType.second; // second doesn't work with MonoTimeImpl
2585
2586 }
2587
foreach(typeStr;__traits (allMembers,ClockType))2588 foreach (typeStr; __traits(allMembers, ClockType))
2589 {
2590 mixin("alias type = ClockType." ~ typeStr ~ ";");
2591 static if (clockSupported(type))
2592 {
2593 auto v1 = MonoTimeImpl!type.currTime;
2594 auto v2 = MonoTimeImpl!type.currTime;
2595 scope(failure)
2596 {
2597 printf("%s: v1 %s, v2 %s, tps %s\n",
2598 (type.stringof ~ "\0").ptr,
2599 numToStringz(v1._ticks),
2600 numToStringz(v2._ticks),
2601 numToStringz(typeof(v1).ticksPerSecond));
2602 }
2603 assert(v1 <= v2);
2604
2605 foreach (otherStr; __traits(allMembers, ClockType))
2606 {
2607 mixin("alias other = ClockType." ~ otherStr ~ ";");
2608 static if (clockSupported(other))
2609 {
2610 static assert(is(typeof({auto o1 = MonTimeImpl!other.currTime; auto b = v1 <= o1;})) ==
2611 is(type == other));
2612 }
2613 }
2614 }
2615 }
2616 }
2617
2618
2619 /++
2620 Converts the given time from one clock frequency/resolution to another.
2621
2622 See_Also:
2623 $(LREF ticksToNSecs)
2624 +/
convClockFreq(long ticks,long srcTicksPerSecond,long dstTicksPerSecond)2625 long convClockFreq(long ticks, long srcTicksPerSecond, long dstTicksPerSecond) @safe pure nothrow @nogc
2626 {
2627 // This would be more straightforward with floating point arithmetic,
2628 // but we avoid it here in order to avoid the rounding errors that that
2629 // introduces. Also, by splitting out the units in this way, we're able
2630 // to deal with much larger values before running into problems with
2631 // integer overflow.
2632 return ticks / srcTicksPerSecond * dstTicksPerSecond +
2633 ticks % srcTicksPerSecond * dstTicksPerSecond / srcTicksPerSecond;
2634 }
2635
2636 ///
2637 unittest
2638 {
2639 // one tick is one second -> one tick is a hecto-nanosecond
2640 assert(convClockFreq(45, 1, 10_000_000) == 450_000_000);
2641
2642 // one tick is one microsecond -> one tick is a millisecond
2643 assert(convClockFreq(9029, 1_000_000, 1_000) == 9);
2644
2645 // one tick is 1/3_515_654 of a second -> 1/1_001_010 of a second
2646 assert(convClockFreq(912_319, 3_515_654, 1_001_010) == 259_764);
2647
2648 // one tick is 1/MonoTime.ticksPerSecond -> one tick is a nanosecond
2649 // Equivalent to ticksToNSecs
2650 auto nsecs = convClockFreq(1982, MonoTime.ticksPerSecond, 1_000_000_000);
2651 }
2652
2653 unittest
2654 {
2655 assert(convClockFreq(99, 43, 57) == 131);
2656 assert(convClockFreq(131, 57, 43) == 98);
2657 assert(convClockFreq(1234567890, 10_000_000, 1_000_000_000) == 123456789000);
2658 assert(convClockFreq(1234567890, 1_000_000_000, 10_000_000) == 12345678);
2659 assert(convClockFreq(123456789000, 1_000_000_000, 10_000_000) == 1234567890);
2660 assert(convClockFreq(12345678, 10_000_000, 1_000_000_000) == 1234567800);
2661 assert(convClockFreq(13131, 3_515_654, 10_000_000) == 37350);
2662 assert(convClockFreq(37350, 10_000_000, 3_515_654) == 13130);
2663 assert(convClockFreq(37350, 3_515_654, 10_000_000) == 106239);
2664 assert(convClockFreq(106239, 10_000_000, 3_515_654) == 37349);
2665
2666 // It would be too expensive to cover a large range of possible values for
2667 // ticks, so we use random values in an attempt to get reasonable coverage.
2668 import core.stdc.stdlib;
2669 immutable seed = cast(int)time(null);
2670 srand(seed);
2671 scope(failure) printf("seed %d\n", seed);
2672 enum freq1 = 5_527_551L;
2673 enum freq2 = 10_000_000L;
2674 enum freq3 = 1_000_000_000L;
2675 enum freq4 = 98_123_320L;
2676 immutable freq5 = MonoTime.ticksPerSecond;
2677
2678 // This makes it so that freq6 is the first multiple of 10 which is greater
2679 // than or equal to freq5, which at one point was considered for MonoTime's
2680 // ticksPerSecond rather than using the system's actual clock frequency, so
2681 // it seemed like a good test case to have.
2682 import core.stdc.math;
2683 immutable numDigitsMinus1 = cast(int)floor(log10(freq5));
2684 auto freq6 = cast(long)pow(10, numDigitsMinus1);
2685 if (freq5 > freq6)
2686 freq6 *= 10;
2687
2688 foreach (_; 0 .. 10_000)
2689 {
2690 long[2] values = [rand(), cast(long)rand() * (rand() % 16)];
foreach(i;values)2691 foreach (i; values)
2692 {
2693 scope(failure) printf("i %s\n", numToStringz(i));
2694 assertApprox(convClockFreq(convClockFreq(i, freq1, freq2), freq2, freq1), i - 10, i + 10);
2695 assertApprox(convClockFreq(convClockFreq(i, freq2, freq1), freq1, freq2), i - 10, i + 10);
2696
2697 assertApprox(convClockFreq(convClockFreq(i, freq3, freq4), freq4, freq3), i - 100, i + 100);
2698 assertApprox(convClockFreq(convClockFreq(i, freq4, freq3), freq3, freq4), i - 100, i + 100);
2699
2700 scope(failure) printf("sys %s mt %s\n", numToStringz(freq5), numToStringz(freq6));
2701 assertApprox(convClockFreq(convClockFreq(i, freq5, freq6), freq6, freq5), i - 10, i + 10);
2702 assertApprox(convClockFreq(convClockFreq(i, freq6, freq5), freq5, freq6), i - 10, i + 10);
2703
2704 // This is here rather than in a unittest block immediately after
2705 // ticksToNSecs in order to avoid code duplication in the unit tests.
2706 assert(convClockFreq(i, MonoTime.ticksPerSecond, 1_000_000_000) == ticksToNSecs(i));
2707 }
2708 }
2709 }
2710
2711
2712 /++
2713 Convenience wrapper around $(LREF convClockFreq) which converts ticks at
2714 a clock frequency of $(D MonoTime.ticksPerSecond) to nanoseconds.
2715
2716 It's primarily of use when $(D MonoTime.ticksPerSecond) is greater than
2717 hecto-nanosecond resolution, and an application needs a higher precision
2718 than hecto-nanoceconds.
2719
2720 See_Also:
2721 $(LREF convClockFreq)
2722 +/
ticksToNSecs(long ticks)2723 long ticksToNSecs(long ticks) @safe pure nothrow @nogc
2724 {
2725 return convClockFreq(ticks, MonoTime.ticksPerSecond, 1_000_000_000);
2726 }
2727
2728 ///
2729 unittest
2730 {
2731 auto before = MonoTime.currTime;
2732 // do stuff
2733 auto after = MonoTime.currTime;
2734 auto diffInTicks = after.ticks - before.ticks;
2735 auto diffInNSecs = ticksToNSecs(diffInTicks);
2736 assert(diffInNSecs == convClockFreq(diffInTicks, MonoTime.ticksPerSecond, 1_000_000_000));
2737 }
2738
2739
2740 /++
2741 The reverse of $(LREF ticksToNSecs).
2742 +/
2743 long nsecsToTicks(long ticks) @safe pure nothrow @nogc
2744 {
2745 return convClockFreq(ticks, 1_000_000_000, MonoTime.ticksPerSecond);
2746 }
2747
2748 unittest
2749 {
2750 long ticks = 123409832717333;
2751 auto nsecs = convClockFreq(ticks, MonoTime.ticksPerSecond, 1_000_000_000);
2752 ticks = convClockFreq(nsecs, 1_000_000_000, MonoTime.ticksPerSecond);
2753 assert(nsecsToTicks(nsecs) == ticks);
2754 }
2755
2756
2757
2758 /++
2759 $(RED Warning: TickDuration will be deprecated in the near future (once all
2760 uses of it in Phobos have been deprecated). Please use
2761 $(LREF MonoTime) for the cases where a monotonic timestamp is needed
2762 and $(LREF Duration) when a duration is needed, rather than using
2763 TickDuration. It has been decided that TickDuration is too confusing
2764 (e.g. it conflates a monotonic timestamp and a duration in monotonic
2765 clock ticks) and that having multiple duration types is too awkward
2766 and confusing.)
2767
2768 Represents a duration of time in system clock ticks.
2769
2770 The system clock ticks are the ticks of the system clock at the highest
2771 precision that the system provides.
2772 +/
2773 struct TickDuration
2774 {
2775 /++
2776 The number of ticks that the system clock has in one second.
2777
2778 If $(D ticksPerSec) is $(D 0), then then $(D TickDuration) failed to
2779 get the value of $(D ticksPerSec) on the current system, and
2780 $(D TickDuration) is not going to work. That would be highly abnormal
2781 though.
2782 +/
2783 static immutable long ticksPerSec;
2784
2785
2786 /++
2787 The tick of the system clock (as a $(D TickDuration)) when the
2788 application started.
2789 +/
2790 static immutable TickDuration appOrigin;
2791
2792
2793 static @property @safe pure nothrow @nogc
2794 {
2795 /++
2796 It's the same as $(D TickDuration(0)), but it's provided to be
2797 consistent with $(D Duration), which provides a $(D zero) property.
2798 +/
2799 TickDuration zero() { return TickDuration(0); }
2800
2801 /++
2802 Largest $(D TickDuration) possible.
2803 +/
2804 TickDuration max() { return TickDuration(long.max); }
2805
2806 /++
2807 Most negative $(D TickDuration) possible.
2808 +/
2809 TickDuration min() { return TickDuration(long.min); }
2810 }
2811
2812 version (CoreUnittest) unittest
2813 {
2814 assert(zero == TickDuration(0));
2815 assert(TickDuration.max == TickDuration(long.max));
2816 assert(TickDuration.min == TickDuration(long.min));
2817 assert(TickDuration.min < TickDuration.zero);
2818 assert(TickDuration.zero < TickDuration.max);
2819 assert(TickDuration.min < TickDuration.max);
2820 assert(TickDuration.min - TickDuration(1) == TickDuration.max);
2821 assert(TickDuration.max + TickDuration(1) == TickDuration.min);
2822 }
2823
2824
2825 @trusted shared static this()
2826 {
2827 version (Windows)
2828 {
2829 if (QueryPerformanceFrequency(cast(long*)&ticksPerSec) == 0)
2830 ticksPerSec = 0;
2831 }
2832 else version (Darwin)
2833 {
2834 ticksPerSec = machTicksPerSecond();
2835 }
2836 else version (Posix)
2837 {
2838 static if (is(typeof(clock_gettime)))
2839 {
2840 timespec ts;
2841
2842 if (clock_getres(CLOCK_MONOTONIC, &ts) != 0)
2843 ticksPerSec = 0;
2844 else
2845 {
2846 //For some reason, on some systems, clock_getres returns
2847 //a resolution which is clearly wrong (it's a millisecond
2848 //or worse, but the time is updated much more frequently
2849 //than that). In such cases, we'll just use nanosecond
2850 //resolution.
2851 ticksPerSec = ts.tv_nsec >= 1000 ? 1_000_000_000
2852 : 1_000_000_000 / ts.tv_nsec;
2853 }
2854 }
2855 else
2856 ticksPerSec = 1_000_000;
2857 }
2858
2859 if (ticksPerSec != 0)
2860 appOrigin = TickDuration.currSystemTick;
2861 }
2862
versionTickDuration2863 version (CoreUnittest) unittest
2864 {
2865 assert(ticksPerSec);
2866 }
2867
2868
2869 /++
2870 The number of system ticks in this $(D TickDuration).
2871
2872 You can convert this $(D length) into the number of seconds by dividing
2873 it by $(D ticksPerSec) (or using one the appropriate property function
2874 to do it).
2875 +/
2876 long length;
2877
2878 /++
2879 Returns the total number of seconds in this $(D TickDuration).
2880 +/
secondsTickDuration2881 @property long seconds() @safe const pure nothrow @nogc
2882 {
2883 return this.to!("seconds", long)();
2884 }
2885
versionTickDuration2886 version (CoreUnittest) unittest
2887 {
2888 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
2889 {
2890 assert((cast(T)TickDuration(ticksPerSec)).seconds == 1);
2891 assert((cast(T)TickDuration(ticksPerSec - 1)).seconds == 0);
2892 assert((cast(T)TickDuration(ticksPerSec * 2)).seconds == 2);
2893 assert((cast(T)TickDuration(ticksPerSec * 2 - 1)).seconds == 1);
2894 assert((cast(T)TickDuration(-1)).seconds == 0);
2895 assert((cast(T)TickDuration(-ticksPerSec - 1)).seconds == -1);
2896 assert((cast(T)TickDuration(-ticksPerSec)).seconds == -1);
2897 }
2898 }
2899
2900
2901 /++
2902 Returns the total number of milliseconds in this $(D TickDuration).
2903 +/
msecsTickDuration2904 @property long msecs() @safe const pure nothrow @nogc
2905 {
2906 return this.to!("msecs", long)();
2907 }
2908
2909
2910 /++
2911 Returns the total number of microseconds in this $(D TickDuration).
2912 +/
usecsTickDuration2913 @property long usecs() @safe const pure nothrow @nogc
2914 {
2915 return this.to!("usecs", long)();
2916 }
2917
2918
2919 /++
2920 Returns the total number of hecto-nanoseconds in this $(D TickDuration).
2921 +/
hnsecsTickDuration2922 @property long hnsecs() @safe const pure nothrow @nogc
2923 {
2924 return this.to!("hnsecs", long)();
2925 }
2926
2927
2928 /++
2929 Returns the total number of nanoseconds in this $(D TickDuration).
2930 +/
nsecsTickDuration2931 @property long nsecs() @safe const pure nothrow @nogc
2932 {
2933 return this.to!("nsecs", long)();
2934 }
2935
2936
2937 /++
2938 This allows you to construct a $(D TickDuration) from the given time
2939 units with the given length.
2940
2941 Params:
2942 units = The time units of the $(D TickDuration) (e.g. $(D "msecs")).
2943 length = The number of units in the $(D TickDuration).
2944 +/
2945 static TickDuration from(string units)(long length) @safe pure nothrow @nogc
2946 if (units == "seconds" ||
2947 units == "msecs" ||
2948 units == "usecs" ||
2949 units == "hnsecs" ||
2950 units == "nsecs")
2951 {
2952 enum unitsPerSec = convert!("seconds", units)(1);
2953
2954 return TickDuration(cast(long)(length * (ticksPerSec / cast(real)unitsPerSec)));
2955 }
2956
versionTickDuration2957 version (CoreUnittest) unittest
2958 {
2959 foreach (units; AliasSeq!("seconds", "msecs", "usecs", "nsecs"))
2960 {
2961 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
2962 {
2963 assertApprox((cast(T)TickDuration.from!units(1000)).to!(units, long)(),
2964 500, 1500, units);
2965 assertApprox((cast(T)TickDuration.from!units(1_000_000)).to!(units, long)(),
2966 900_000, 1_100_000, units);
2967 assertApprox((cast(T)TickDuration.from!units(2_000_000)).to!(units, long)(),
2968 1_900_000, 2_100_000, units);
2969 }
2970 }
2971 }
2972
2973
2974 /++
2975 Returns a $(LREF Duration) with the same number of hnsecs as this
2976 $(D TickDuration).
2977 Note that the conventional way to convert between $(D TickDuration)
2978 and $(D Duration) is using $(REF to, std,conv), e.g.:
2979 $(D tickDuration.to!Duration())
2980 +/
2981 Duration opCast(T)() @safe const pure nothrow @nogc
2982 if (is(immutable T == immutable Duration))
2983 {
2984 return Duration(hnsecs);
2985 }
2986
versionTickDuration2987 version (CoreUnittest) unittest
2988 {
2989 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
2990 {
2991 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
2992 {
2993 auto expected = dur!"seconds"(1);
2994 assert(cast(D)cast(T)TickDuration.from!"seconds"(1) == expected);
2995
2996 foreach (units; AliasSeq!("msecs", "usecs", "hnsecs"))
2997 {
2998 D actual = cast(D)cast(T)TickDuration.from!units(1_000_000);
2999 assertApprox(actual, dur!units(900_000), dur!units(1_100_000));
3000 }
3001 }
3002 }
3003 }
3004
3005
3006 //Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=5747 is fixed.
3007 TickDuration opCast(T)() @safe const pure nothrow @nogc
3008 if (is(immutable T == immutable TickDuration))
3009 {
3010 return this;
3011 }
3012
3013
3014 /++
3015 Adds or subtracts two $(D TickDuration)s as well as assigning the result
3016 to this $(D TickDuration).
3017
3018 The legal types of arithmetic for $(D TickDuration) using this operator
3019 are
3020
3021 $(TABLE
3022 $(TR $(TD TickDuration) $(TD +=) $(TD TickDuration) $(TD -->) $(TD TickDuration))
3023 $(TR $(TD TickDuration) $(TD -=) $(TD TickDuration) $(TD -->) $(TD TickDuration))
3024 )
3025
3026 Params:
3027 rhs = The $(D TickDuration) to add to or subtract from this
3028 $(D $(D TickDuration)).
3029 +/
3030 ref TickDuration opOpAssign(string op)(TickDuration rhs) @safe pure nothrow @nogc
3031 if (op == "+" || op == "-")
3032 {
3033 mixin("length " ~ op ~ "= rhs.length;");
3034 return this;
3035 }
3036
versionTickDuration3037 version (CoreUnittest) unittest
3038 {
3039 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
3040 {
3041 auto a = TickDuration.currSystemTick;
3042 auto result = a += cast(T)TickDuration.currSystemTick;
3043 assert(a == result);
3044 assert(a.to!("seconds", real)() >= 0);
3045
3046 auto b = TickDuration.currSystemTick;
3047 result = b -= cast(T)TickDuration.currSystemTick;
3048 assert(b == result);
3049 assert(b.to!("seconds", real)() <= 0);
3050
3051 foreach (U; AliasSeq!(const TickDuration, immutable TickDuration))
3052 {
3053 U u = TickDuration(12);
3054 static assert(!__traits(compiles, u += cast(T)TickDuration.currSystemTick));
3055 static assert(!__traits(compiles, u -= cast(T)TickDuration.currSystemTick));
3056 }
3057 }
3058 }
3059
3060
3061 /++
3062 Adds or subtracts two $(D TickDuration)s.
3063
3064 The legal types of arithmetic for $(D TickDuration) using this operator
3065 are
3066
3067 $(TABLE
3068 $(TR $(TD TickDuration) $(TD +) $(TD TickDuration) $(TD -->) $(TD TickDuration))
3069 $(TR $(TD TickDuration) $(TD -) $(TD TickDuration) $(TD -->) $(TD TickDuration))
3070 )
3071
3072 Params:
3073 rhs = The $(D TickDuration) to add to or subtract from this
3074 $(D TickDuration).
3075 +/
3076 TickDuration opBinary(string op)(TickDuration rhs) @safe const pure nothrow @nogc
3077 if (op == "+" || op == "-")
3078 {
3079 return TickDuration(mixin("length " ~ op ~ " rhs.length"));
3080 }
3081
versionTickDuration3082 version (CoreUnittest) unittest
3083 {
3084 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
3085 {
3086 T a = TickDuration.currSystemTick;
3087 T b = TickDuration.currSystemTick;
3088 assert((a + b).usecs > 0);
3089 assert((a - b).seconds <= 0);
3090 }
3091 }
3092
3093
3094 /++
3095 Returns the negation of this $(D TickDuration).
3096 +/
3097 TickDuration opUnary(string op)() @safe const pure nothrow @nogc
3098 if (op == "-")
3099 {
3100 return TickDuration(-length);
3101 }
3102
versionTickDuration3103 version (CoreUnittest) unittest
3104 {
3105 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
3106 {
3107 assert(-(cast(T)TickDuration(7)) == TickDuration(-7));
3108 assert(-(cast(T)TickDuration(5)) == TickDuration(-5));
3109 assert(-(cast(T)TickDuration(-7)) == TickDuration(7));
3110 assert(-(cast(T)TickDuration(-5)) == TickDuration(5));
3111 assert(-(cast(T)TickDuration(0)) == TickDuration(0));
3112 }
3113 }
3114
3115
3116 /++
3117 operator overloading "<, >, <=, >="
3118 +/
opCmpTickDuration3119 int opCmp(TickDuration rhs) @safe const pure nothrow @nogc
3120 {
3121 return (length > rhs.length) - (length < rhs.length);
3122 }
3123
versionTickDuration3124 version (CoreUnittest) unittest
3125 {
3126 import core.internal.traits : rvalueOf;
3127 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
3128 {
3129 foreach (U; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
3130 {
3131 T t = TickDuration.currSystemTick;
3132 U u = t;
3133 assert(t == u);
3134 assert(rvalueOf(t) == u);
3135 assert(t == rvalueOf(u));
3136 }
3137 }
3138
3139 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
3140 {
3141 foreach (U; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
3142 {
3143 T t = TickDuration.currSystemTick;
3144 U u = t + t;
3145 assert(t < u);
3146 assert(t <= t);
3147 assert(u > t);
3148 assert(u >= u);
3149
3150 assert(rvalueOf(t) < u);
3151 assert(rvalueOf(t) <= t);
3152 assert(rvalueOf(u) > t);
3153 assert(rvalueOf(u) >= u);
3154
3155 assert(t < rvalueOf(u));
3156 assert(t <= rvalueOf(t));
3157 assert(u > rvalueOf(t));
3158 assert(u >= rvalueOf(u));
3159 }
3160 }
3161 }
3162
3163
3164 /++
3165 The legal types of arithmetic for $(D TickDuration) using this operator
3166 overload are
3167
3168 $(TABLE
3169 $(TR $(TD TickDuration) $(TD *) $(TD long) $(TD -->) $(TD TickDuration))
3170 $(TR $(TD TickDuration) $(TD *) $(TD floating point) $(TD -->) $(TD TickDuration))
3171 )
3172
3173 Params:
3174 value = The value to divide from this duration.
3175 +/
3176 void opOpAssign(string op, T)(T value) @safe pure nothrow @nogc
3177 if (op == "*" &&
3178 (__traits(isIntegral, T) || __traits(isFloating, T)))
3179 {
3180 length = cast(long)(length * value);
3181 }
3182
versionTickDuration3183 version (CoreUnittest) unittest
3184 {
3185 immutable curr = TickDuration.currSystemTick;
3186 TickDuration t1 = curr;
3187 immutable t2 = curr + curr;
3188 t1 *= 2;
3189 assert(t1 == t2);
3190
3191 t1 = curr;
3192 t1 *= 2.0;
3193 immutable tol = TickDuration(cast(long)(_abs(t1.length) * double.epsilon * 2.0));
3194 assertApprox(t1, t2 - tol, t2 + tol);
3195
3196 t1 = curr;
3197 t1 *= 2.1;
3198 assert(t1 > t2);
3199
3200 foreach (T; AliasSeq!(const TickDuration, immutable TickDuration))
3201 {
3202 T t = TickDuration.currSystemTick;
3203 assert(!__traits(compiles, t *= 12));
3204 assert(!__traits(compiles, t *= 12.0));
3205 }
3206 }
3207
3208
3209 /++
3210 The legal types of arithmetic for $(D TickDuration) using this operator
3211 overload are
3212
3213 $(TABLE
3214 $(TR $(TD TickDuration) $(TD /) $(TD long) $(TD -->) $(TD TickDuration))
3215 $(TR $(TD TickDuration) $(TD /) $(TD floating point) $(TD -->) $(TD TickDuration))
3216 )
3217
3218 Params:
3219 value = The value to divide from this $(D TickDuration).
3220
3221 Throws:
3222 $(D TimeException) if an attempt to divide by $(D 0) is made.
3223 +/
3224 void opOpAssign(string op, T)(T value) @safe pure
3225 if (op == "/" &&
3226 (__traits(isIntegral, T) || __traits(isFloating, T)))
3227 {
3228 if (value == 0)
3229 throw new TimeException("Attempted division by 0.");
3230
3231 length = cast(long)(length / value);
3232 }
3233
versionTickDuration3234 version (CoreUnittest) unittest
3235 {
3236 immutable curr = TickDuration.currSystemTick;
3237 immutable t1 = curr;
3238 TickDuration t2 = curr + curr;
3239 t2 /= 2;
3240 assert(t1 == t2);
3241
3242 t2 = curr + curr;
3243 t2 /= 2.0;
3244 immutable tol = TickDuration(cast(long)(_abs(t2.length) * double.epsilon / 2.0));
3245 assertApprox(t1, t2 - tol, t2 + tol);
3246
3247 t2 = curr + curr;
3248 t2 /= 2.1;
3249 assert(t1 > t2);
3250
3251 _assertThrown!TimeException(t2 /= 0);
3252
3253 foreach (T; AliasSeq!(const TickDuration, immutable TickDuration))
3254 {
3255 T t = TickDuration.currSystemTick;
3256 assert(!__traits(compiles, t /= 12));
3257 assert(!__traits(compiles, t /= 12.0));
3258 }
3259 }
3260
3261
3262 /++
3263 The legal types of arithmetic for $(D TickDuration) using this operator
3264 overload are
3265
3266 $(TABLE
3267 $(TR $(TD TickDuration) $(TD *) $(TD long) $(TD -->) $(TD TickDuration))
3268 $(TR $(TD TickDuration) $(TD *) $(TD floating point) $(TD -->) $(TD TickDuration))
3269 )
3270
3271 Params:
3272 value = The value to divide from this $(D TickDuration).
3273 +/
3274 TickDuration opBinary(string op, T)(T value) @safe const pure nothrow @nogc
3275 if (op == "*" &&
3276 (__traits(isIntegral, T) || __traits(isFloating, T)))
3277 {
3278 return TickDuration(cast(long)(length * value));
3279 }
3280
versionTickDuration3281 version (CoreUnittest) unittest
3282 {
3283 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
3284 {
3285 T t1 = TickDuration.currSystemTick;
3286 T t2 = t1 + t1;
3287 assert(t1 * 2 == t2);
3288 immutable tol = TickDuration(cast(long)(_abs(t1.length) * double.epsilon * 2.0));
3289 assertApprox(t1 * 2.0, t2 - tol, t2 + tol);
3290 assert(t1 * 2.1 > t2);
3291 }
3292 }
3293
3294
3295 /++
3296 The legal types of arithmetic for $(D TickDuration) using this operator
3297 overload are
3298
3299 $(TABLE
3300 $(TR $(TD TickDuration) $(TD /) $(TD long) $(TD -->) $(TD TickDuration))
3301 $(TR $(TD TickDuration) $(TD /) $(TD floating point) $(TD -->) $(TD TickDuration))
3302 )
3303
3304 Params:
3305 value = The value to divide from this $(D TickDuration).
3306
3307 Throws:
3308 $(D TimeException) if an attempt to divide by $(D 0) is made.
3309 +/
3310 TickDuration opBinary(string op, T)(T value) @safe const pure
3311 if (op == "/" &&
3312 (__traits(isIntegral, T) || __traits(isFloating, T)))
3313 {
3314 if (value == 0)
3315 throw new TimeException("Attempted division by 0.");
3316
3317 return TickDuration(cast(long)(length / value));
3318 }
3319
versionTickDuration3320 version (CoreUnittest) unittest
3321 {
3322 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
3323 {
3324 T t1 = TickDuration.currSystemTick;
3325 T t2 = t1 + t1;
3326 assert(t2 / 2 == t1);
3327 immutable tol = TickDuration(cast(long)(_abs(t2.length) * double.epsilon / 2.0));
3328 assertApprox(t2 / 2.0, t1 - tol, t1 + tol);
3329 assert(t2 / 2.1 < t1);
3330
3331 _assertThrown!TimeException(t2 / 0);
3332 }
3333 }
3334
3335
3336 /++
3337 Params:
3338 ticks = The number of ticks in the TickDuration.
3339 +/
thisTickDuration3340 @safe pure nothrow @nogc this(long ticks)
3341 {
3342 this.length = ticks;
3343 }
3344
versionTickDuration3345 version (CoreUnittest) unittest
3346 {
3347 foreach (i; [-42, 0, 42])
3348 assert(TickDuration(i).length == i);
3349 }
3350
3351
3352 /++
3353 The current system tick. The number of ticks per second varies from
3354 system to system. $(D currSystemTick) uses a monotonic clock, so it's
3355 intended for precision timing by comparing relative time values, not for
3356 getting the current system time.
3357
3358 On Windows, $(D QueryPerformanceCounter) is used. On Mac OS X,
3359 $(D mach_absolute_time) is used, while on other Posix systems,
3360 $(D clock_gettime) is used. If $(D mach_absolute_time) or
3361 $(D clock_gettime) is unavailable, then Posix systems use
3362 $(D gettimeofday) (the decision is made when $(D TickDuration) is
3363 compiled), which unfortunately, is not monotonic, but if
3364 $(D mach_absolute_time) and $(D clock_gettime) aren't available, then
3365 $(D gettimeofday) is the the best that there is.
3366
3367 $(RED Warning):
3368 On some systems, the monotonic clock may stop counting when
3369 the computer goes to sleep or hibernates. So, the monotonic
3370 clock could be off if that occurs. This is known to happen
3371 on Mac OS X. It has not been tested whether it occurs on
3372 either Windows or on Linux.
3373
3374 Throws:
3375 $(D TimeException) if it fails to get the time.
3376 +/
currSystemTickTickDuration3377 static @property TickDuration currSystemTick() @trusted nothrow @nogc
3378 {
3379 import core.internal.abort : abort;
3380 version (Windows)
3381 {
3382 ulong ticks = void;
3383 QueryPerformanceCounter(cast(long*)&ticks);
3384 return TickDuration(ticks);
3385 }
3386 else version (Darwin)
3387 {
3388 static if (is(typeof(mach_absolute_time)))
3389 return TickDuration(cast(long)mach_absolute_time());
3390 else
3391 {
3392 timeval tv = void;
3393 gettimeofday(&tv, null);
3394 return TickDuration(tv.tv_sec * TickDuration.ticksPerSec +
3395 tv.tv_usec * TickDuration.ticksPerSec / 1000 / 1000);
3396 }
3397 }
3398 else version (Posix)
3399 {
3400 static if (is(typeof(clock_gettime)))
3401 {
3402 timespec ts = void;
3403 immutable error = clock_gettime(CLOCK_MONOTONIC, &ts);
3404 // CLOCK_MONOTONIC is supported and if tv_sec is long or larger
3405 // overflow won't happen before 292 billion years A.D.
3406 static if (ts.tv_sec.max < long.max)
3407 {
3408 if (error)
3409 {
3410 import core.internal.abort : abort;
3411 abort("Call to clock_gettime failed.");
3412 }
3413 }
3414 return TickDuration(ts.tv_sec * TickDuration.ticksPerSec +
3415 ts.tv_nsec * TickDuration.ticksPerSec / 1000 / 1000 / 1000);
3416 }
3417 else
3418 {
3419 timeval tv = void;
3420 gettimeofday(&tv, null);
3421 return TickDuration(tv.tv_sec * TickDuration.ticksPerSec +
3422 tv.tv_usec * TickDuration.ticksPerSec / 1000 / 1000);
3423 }
3424 }
3425 }
3426
versionTickDuration3427 version (CoreUnittest) @safe nothrow unittest
3428 {
3429 assert(TickDuration.currSystemTick.length > 0);
3430 }
3431 }
3432
3433
3434 /++
3435 Generic way of converting between two time units. Conversions to smaller
3436 units use truncating division. Years and months can be converted to each
3437 other, small units can be converted to each other, but years and months
3438 cannot be converted to or from smaller units (due to the varying number
3439 of days in a month or year).
3440
3441 Params:
3442 from = The units of time to convert from.
3443 to = The units of time to convert to.
3444 value = The value to convert.
3445 +/
convert(string from,string to)3446 long convert(string from, string to)(long value) @safe pure nothrow @nogc
3447 if (((from == "weeks" ||
3448 from == "days" ||
3449 from == "hours" ||
3450 from == "minutes" ||
3451 from == "seconds" ||
3452 from == "msecs" ||
3453 from == "usecs" ||
3454 from == "hnsecs" ||
3455 from == "nsecs") &&
3456 (to == "weeks" ||
3457 to == "days" ||
3458 to == "hours" ||
3459 to == "minutes" ||
3460 to == "seconds" ||
3461 to == "msecs" ||
3462 to == "usecs" ||
3463 to == "hnsecs" ||
3464 to == "nsecs")) ||
3465 ((from == "years" || from == "months") && (to == "years" || to == "months")))
3466 {
3467 static if (from == "years")
3468 {
3469 static if (to == "years")
3470 return value;
3471 else static if (to == "months")
3472 return value * 12;
3473 else
3474 static assert(0, "A generic month or year cannot be converted to or from smaller units.");
3475 }
3476 else static if (from == "months")
3477 {
3478 static if (to == "years")
3479 return value / 12;
3480 else static if (to == "months")
3481 return value;
3482 else
3483 static assert(0, "A generic month or year cannot be converted to or from smaller units.");
3484 }
3485 else static if (from == "nsecs" && to == "nsecs")
3486 return value;
3487 else static if (from == "nsecs")
3488 return convert!("hnsecs", to)(value / 100);
3489 else static if (to == "nsecs")
3490 return convert!(from, "hnsecs")(value) * 100;
3491 else
3492 return (hnsecsPer!from * value) / hnsecsPer!to;
3493 }
3494
3495 ///
3496 unittest
3497 {
3498 assert(convert!("years", "months")(1) == 12);
3499 assert(convert!("months", "years")(12) == 1);
3500
3501 assert(convert!("weeks", "days")(1) == 7);
3502 assert(convert!("hours", "seconds")(1) == 3600);
3503 assert(convert!("seconds", "days")(1) == 0);
3504 assert(convert!("seconds", "days")(86_400) == 1);
3505
3506 assert(convert!("nsecs", "nsecs")(1) == 1);
3507 assert(convert!("nsecs", "hnsecs")(1) == 0);
3508 assert(convert!("hnsecs", "nsecs")(1) == 100);
3509 assert(convert!("nsecs", "seconds")(1) == 0);
3510 assert(convert!("seconds", "nsecs")(1) == 1_000_000_000);
3511 }
3512
3513 unittest
3514 {
3515 foreach (units; AliasSeq!("weeks", "days", "hours", "seconds", "msecs", "usecs", "hnsecs", "nsecs"))
3516 {
3517 static assert(!__traits(compiles, convert!("years", units)(12)), units);
3518 static assert(!__traits(compiles, convert!(units, "years")(12)), units);
3519 }
3520
3521 foreach (units; AliasSeq!("years", "months", "weeks", "days",
3522 "hours", "seconds", "msecs", "usecs", "hnsecs", "nsecs"))
3523 {
3524 assert(convert!(units, units)(12) == 12);
3525 }
3526
3527 assert(convert!("weeks", "hnsecs")(1) == 6_048_000_000_000L);
3528 assert(convert!("days", "hnsecs")(1) == 864_000_000_000L);
3529 assert(convert!("hours", "hnsecs")(1) == 36_000_000_000L);
3530 assert(convert!("minutes", "hnsecs")(1) == 600_000_000L);
3531 assert(convert!("seconds", "hnsecs")(1) == 10_000_000L);
3532 assert(convert!("msecs", "hnsecs")(1) == 10_000);
3533 assert(convert!("usecs", "hnsecs")(1) == 10);
3534
3535 assert(convert!("hnsecs", "weeks")(6_048_000_000_000L) == 1);
3536 assert(convert!("hnsecs", "days")(864_000_000_000L) == 1);
3537 assert(convert!("hnsecs", "hours")(36_000_000_000L) == 1);
3538 assert(convert!("hnsecs", "minutes")(600_000_000L) == 1);
3539 assert(convert!("hnsecs", "seconds")(10_000_000L) == 1);
3540 assert(convert!("hnsecs", "msecs")(10_000) == 1);
3541 assert(convert!("hnsecs", "usecs")(10) == 1);
3542
3543 assert(convert!("weeks", "days")(1) == 7);
3544 assert(convert!("days", "weeks")(7) == 1);
3545
3546 assert(convert!("days", "hours")(1) == 24);
3547 assert(convert!("hours", "days")(24) == 1);
3548
3549 assert(convert!("hours", "minutes")(1) == 60);
3550 assert(convert!("minutes", "hours")(60) == 1);
3551
3552 assert(convert!("minutes", "seconds")(1) == 60);
3553 assert(convert!("seconds", "minutes")(60) == 1);
3554
3555 assert(convert!("seconds", "msecs")(1) == 1000);
3556 assert(convert!("msecs", "seconds")(1000) == 1);
3557
3558 assert(convert!("msecs", "usecs")(1) == 1000);
3559 assert(convert!("usecs", "msecs")(1000) == 1);
3560
3561 assert(convert!("usecs", "hnsecs")(1) == 10);
3562 assert(convert!("hnsecs", "usecs")(10) == 1);
3563
3564 assert(convert!("weeks", "nsecs")(1) == 604_800_000_000_000L);
3565 assert(convert!("days", "nsecs")(1) == 86_400_000_000_000L);
3566 assert(convert!("hours", "nsecs")(1) == 3_600_000_000_000L);
3567 assert(convert!("minutes", "nsecs")(1) == 60_000_000_000L);
3568 assert(convert!("seconds", "nsecs")(1) == 1_000_000_000L);
3569 assert(convert!("msecs", "nsecs")(1) == 1_000_000);
3570 assert(convert!("usecs", "nsecs")(1) == 1000);
3571 assert(convert!("hnsecs", "nsecs")(1) == 100);
3572
3573 assert(convert!("nsecs", "weeks")(604_800_000_000_000L) == 1);
3574 assert(convert!("nsecs", "days")(86_400_000_000_000L) == 1);
3575 assert(convert!("nsecs", "hours")(3_600_000_000_000L) == 1);
3576 assert(convert!("nsecs", "minutes")(60_000_000_000L) == 1);
3577 assert(convert!("nsecs", "seconds")(1_000_000_000L) == 1);
3578 assert(convert!("nsecs", "msecs")(1_000_000) == 1);
3579 assert(convert!("nsecs", "usecs")(1000) == 1);
3580 assert(convert!("nsecs", "hnsecs")(100) == 1);
3581 }
3582
3583 /++
3584 Exception type used by core.time.
3585 +/
3586 class TimeException : Exception
3587 {
3588 /++
3589 Params:
3590 msg = The message for the exception.
3591 file = The file where the exception occurred.
3592 line = The line number where the exception occurred.
3593 next = The previous exception in the chain of exceptions, if any.
3594 +/
3595 this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @safe pure nothrow
3596 {
3597 super(msg, file, line, next);
3598 }
3599
3600 /++
3601 Params:
3602 msg = The message for the exception.
3603 next = The previous exception in the chain of exceptions.
3604 file = The file where the exception occurred.
3605 line = The line number where the exception occurred.
3606 +/
3607 this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @safe pure nothrow
3608 {
3609 super(msg, file, line, next);
3610 }
3611 }
3612
3613 unittest
3614 {
3615 {
3616 auto e = new TimeException("hello");
3617 assert(e.msg == "hello");
3618 assert(e.file == __FILE__);
3619 assert(e.line == __LINE__ - 3);
3620 assert(e.next is null);
3621 }
3622
3623 {
3624 auto next = new Exception("foo");
3625 auto e = new TimeException("goodbye", next);
3626 assert(e.msg == "goodbye");
3627 assert(e.file == __FILE__);
3628 assert(e.line == __LINE__ - 3);
3629 assert(e.next is next);
3630 }
3631 }
3632
3633
3634
3635 /++
3636 Returns the absolute value of a duration.
3637 +/
abs(Duration duration)3638 Duration abs(Duration duration) @safe pure nothrow @nogc
3639 {
3640 return Duration(_abs(duration._hnsecs));
3641 }
3642
3643 /++ Ditto +/
abs(TickDuration duration)3644 TickDuration abs(TickDuration duration) @safe pure nothrow @nogc
3645 {
3646 return TickDuration(_abs(duration.length));
3647 }
3648
3649 unittest
3650 {
3651 assert(abs(dur!"msecs"(5)) == dur!"msecs"(5));
3652 assert(abs(dur!"msecs"(-5)) == dur!"msecs"(5));
3653
3654 assert(abs(TickDuration(17)) == TickDuration(17));
3655 assert(abs(TickDuration(-17)) == TickDuration(17));
3656 }
3657
3658
3659 //==============================================================================
3660 // Private Section.
3661 //
3662 // Much of this is a copy or simplified copy of what's in std.datetime.
3663 //==============================================================================
3664 private:
3665
3666
3667 /+
3668 Template to help with converting between time units.
3669 +/
3670 template hnsecsPer(string units)
3671 if (units == "weeks" ||
3672 units == "days" ||
3673 units == "hours" ||
3674 units == "minutes" ||
3675 units == "seconds" ||
3676 units == "msecs" ||
3677 units == "usecs" ||
3678 units == "hnsecs")
3679 {
3680 static if (units == "hnsecs")
3681 enum hnsecsPer = 1L;
3682 else static if (units == "usecs")
3683 enum hnsecsPer = 10L;
3684 else static if (units == "msecs")
3685 enum hnsecsPer = 1000 * hnsecsPer!"usecs";
3686 else static if (units == "seconds")
3687 enum hnsecsPer = 1000 * hnsecsPer!"msecs";
3688 else static if (units == "minutes")
3689 enum hnsecsPer = 60 * hnsecsPer!"seconds";
3690 else static if (units == "hours")
3691 enum hnsecsPer = 60 * hnsecsPer!"minutes";
3692 else static if (units == "days")
3693 enum hnsecsPer = 24 * hnsecsPer!"hours";
3694 else static if (units == "weeks")
3695 enum hnsecsPer = 7 * hnsecsPer!"days";
3696 }
3697
3698 /+
3699 Splits out a particular unit from hnsecs and gives you the value for that
3700 unit and the remaining hnsecs. It really shouldn't be used unless all units
3701 larger than the given units have already been split out.
3702
3703 Params:
3704 units = The units to split out.
3705 hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left
3706 after splitting out the given units.
3707
3708 Returns:
3709 The number of the given units from converting hnsecs to those units.
3710 +/
3711 long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow @nogc
3712 if (units == "weeks" ||
3713 units == "days" ||
3714 units == "hours" ||
3715 units == "minutes" ||
3716 units == "seconds" ||
3717 units == "msecs" ||
3718 units == "usecs" ||
3719 units == "hnsecs")
3720 {
3721 immutable value = convert!("hnsecs", units)(hnsecs);
3722 hnsecs -= convert!(units, "hnsecs")(value);
3723
3724 return value;
3725 }
3726
3727 unittest
3728 {
3729 auto hnsecs = 2595000000007L;
3730 immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
3731 assert(days == 3);
3732 assert(hnsecs == 3000000007);
3733
3734 immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
3735 assert(minutes == 5);
3736 assert(hnsecs == 7);
3737 }
3738
3739 /+
3740 Whether all of the given strings are among the accepted strings.
3741 +/
allAreAcceptedUnits(acceptedUnits...)3742 bool allAreAcceptedUnits(acceptedUnits...)(scope string[] units)
3743 {
3744 foreach (unit; units)
3745 {
3746 bool found = false;
3747 foreach (acceptedUnit; acceptedUnits)
3748 {
3749 if (unit == acceptedUnit)
3750 {
3751 found = true;
3752 break;
3753 }
3754 }
3755 if (!found)
3756 return false;
3757 }
3758 return true;
3759 }
3760
3761 unittest
3762 {
3763 assert(allAreAcceptedUnits!("hours", "seconds")(["seconds", "hours"]));
3764 assert(!allAreAcceptedUnits!("hours", "seconds")(["minutes", "hours"]));
3765 assert(!allAreAcceptedUnits!("hours", "seconds")(["seconds", "minutes"]));
3766 assert(allAreAcceptedUnits!("days", "hours", "minutes", "seconds", "msecs")(["minutes"]));
3767 assert(!allAreAcceptedUnits!("days", "hours", "minutes", "seconds", "msecs")(["usecs"]));
3768 assert(!allAreAcceptedUnits!("days", "hours", "minutes", "seconds", "msecs")(["secs"]));
3769 }
3770
3771
3772 /+
3773 Whether the given time unit strings are arranged in order from largest to
3774 smallest.
3775 +/
3776 bool unitsAreInDescendingOrder(scope string[] units)
3777 {
3778 if (units.length <= 1)
3779 return true;
3780
3781 immutable string[] timeStrings = ["nsecs", "hnsecs", "usecs", "msecs", "seconds",
3782 "minutes", "hours", "days", "weeks", "months", "years"];
3783 size_t currIndex = 42;
3784 foreach (i, timeStr; timeStrings)
3785 {
3786 if (units[0] == timeStr)
3787 {
3788 currIndex = i;
3789 break;
3790 }
3791 }
3792 assert(currIndex != 42);
3793
3794 foreach (unit; units[1 .. $])
3795 {
3796 size_t nextIndex = 42;
3797 foreach (i, timeStr; timeStrings)
3798 {
3799 if (unit == timeStr)
3800 {
3801 nextIndex = i;
3802 break;
3803 }
3804 }
3805 assert(nextIndex != 42);
3806
3807 if (currIndex <= nextIndex)
3808 return false;
3809 currIndex = nextIndex;
3810 }
3811 return true;
3812 }
3813
3814 unittest
3815 {
3816 assert(unitsAreInDescendingOrder(["years", "months", "weeks", "days", "hours", "minutes",
3817 "seconds", "msecs", "usecs", "hnsecs", "nsecs"]));
3818 assert(unitsAreInDescendingOrder(["weeks", "hours", "msecs"]));
3819 assert(unitsAreInDescendingOrder(["days", "hours", "minutes"]));
3820 assert(unitsAreInDescendingOrder(["hnsecs"]));
3821 assert(!unitsAreInDescendingOrder(["days", "hours", "hours"]));
3822 assert(!unitsAreInDescendingOrder(["days", "hours", "days"]));
3823 }
3824
3825 version (Darwin)
3826 long machTicksPerSecond()
3827 {
3828 // Be optimistic that ticksPerSecond (1e9*denom/numer) is integral. So far
3829 // so good on Darwin based platforms OS X, iOS.
3830 import core.internal.abort : abort;
3831 mach_timebase_info_data_t info;
3832 if (mach_timebase_info(&info) != 0)
3833 abort("Failed in mach_timebase_info().");
3834
3835 long scaledDenom = 1_000_000_000L * info.denom;
3836 if (scaledDenom % info.numer != 0)
3837 abort("Non integral ticksPerSecond from mach_timebase_info.");
3838 return scaledDenom / info.numer;
3839 }
3840
3841 /+
3842 Local version of abs, since std.math.abs is in Phobos, not druntime.
3843 +/
3844 long _abs(long val) @safe pure nothrow @nogc
3845 {
3846 return val >= 0 ? val : -val;
3847 }
3848
3849 double _abs(double val) @safe pure nothrow @nogc
3850 {
3851 return val >= 0.0 ? val : -val;
3852 }
3853
3854
3855 version (CoreUnittest)
3856 string doubleToString(double value) @safe pure nothrow
3857 {
3858 string result;
3859 if (value < 0 && cast(long)value == 0)
3860 result = "-0";
3861 else
3862 result = signedToTempString(cast(long)value).idup;
3863 result ~= '.';
3864 result ~= unsignedToTempString(cast(ulong)(_abs((value - cast(long)value) * 1_000_000) + .5));
3865
3866 while (result[$-1] == '0')
3867 result = result[0 .. $-1];
3868 return result;
3869 }
3870
3871 unittest
3872 {
3873 auto a = 1.337;
3874 auto aStr = doubleToString(a);
3875 assert(aStr == "1.337", aStr);
3876
3877 a = 0.337;
3878 aStr = doubleToString(a);
3879 assert(aStr == "0.337", aStr);
3880
3881 a = -0.337;
3882 aStr = doubleToString(a);
3883 assert(aStr == "-0.337", aStr);
3884 }
3885
3886 version (CoreUnittest) const(char)* numToStringz()(long value) @trusted pure nothrow
3887 {
3888 return (signedToTempString(value) ~ "\0").ptr;
3889 }
3890
3891
3892 import core.internal.traits : AliasSeq;
3893
3894
3895 /+ An adjusted copy of std.exception.assertThrown. +/
3896 version (CoreUnittest) void _assertThrown(T : Throwable = Exception, E)
3897 (lazy E expression,
3898 string msg = null,
3899 string file = __FILE__,
3900 size_t line = __LINE__)
3901 {
3902 bool thrown = false;
3903
3904 try
3905 expression();
3906 catch (T t)
3907 thrown = true;
3908
3909 if (!thrown)
3910 {
3911 immutable tail = msg.length == 0 ? "." : ": " ~ msg;
3912
3913 throw new AssertError("assertThrown() failed: No " ~ T.stringof ~ " was thrown" ~ tail, file, line);
3914 }
3915 }
3916
3917 unittest
3918 {
3919
3920 void throwEx(Throwable t)
3921 {
3922 throw t;
3923 }
3924
3925 void nothrowEx()
3926 {}
3927
3928 try
3929 _assertThrown!Exception(throwEx(new Exception("It's an Exception")));
3930 catch (AssertError)
3931 assert(0);
3932
3933 try
3934 _assertThrown!Exception(throwEx(new Exception("It's an Exception")), "It's a message");
3935 catch (AssertError)
3936 assert(0);
3937
3938 try
3939 _assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)));
3940 catch (AssertError)
3941 assert(0);
3942
3943 try
3944 _assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)), "It's a message");
3945 catch (AssertError)
3946 assert(0);
3947
3948
3949 {
3950 bool thrown = false;
3951 try
3952 _assertThrown!Exception(nothrowEx());
3953 catch (AssertError)
3954 thrown = true;
3955
3956 assert(thrown);
3957 }
3958
3959 {
3960 bool thrown = false;
3961 try
3962 _assertThrown!Exception(nothrowEx(), "It's a message");
3963 catch (AssertError)
3964 thrown = true;
3965
3966 assert(thrown);
3967 }
3968
3969 {
3970 bool thrown = false;
3971 try
3972 _assertThrown!AssertError(nothrowEx());
3973 catch (AssertError)
3974 thrown = true;
3975
3976 assert(thrown);
3977 }
3978
3979 {
3980 bool thrown = false;
3981 try
3982 _assertThrown!AssertError(nothrowEx(), "It's a message");
3983 catch (AssertError)
3984 thrown = true;
3985
3986 assert(thrown);
3987 }
3988 }
3989
3990
3991 version (CoreUnittest) void assertApprox(D, E)(D actual,
3992 E lower,
3993 E upper,
3994 string msg = "unittest failure",
3995 size_t line = __LINE__)
3996 if (is(D : const Duration) && is(E : const Duration))
3997 {
3998 if (actual < lower)
3999 throw new AssertError(msg ~ ": lower: " ~ actual.toString(), __FILE__, line);
4000 if (actual > upper)
4001 throw new AssertError(msg ~ ": upper: " ~ actual.toString(), __FILE__, line);
4002 }
4003
4004 version (CoreUnittest) void assertApprox(D, E)(D actual,
4005 E lower,
4006 E upper,
4007 string msg = "unittest failure",
4008 size_t line = __LINE__)
4009 if (is(D : const TickDuration) && is(E : const TickDuration))
4010 {
4011 if (actual.length < lower.length || actual.length > upper.length)
4012 {
4013 throw new AssertError(msg ~ (": [" ~ signedToTempString(lower.length) ~ "] [" ~
4014 signedToTempString(actual.length) ~ "] [" ~
4015 signedToTempString(upper.length) ~ "]").idup,
4016 __FILE__, line);
4017 }
4018 }
4019
4020 version (CoreUnittest) void assertApprox(MT)(MT actual,
4021 MT lower,
4022 MT upper,
4023 string msg = "unittest failure",
4024 size_t line = __LINE__)
4025 if (is(MT == MonoTimeImpl!type, ClockType type))
4026 {
4027 assertApprox(actual._ticks, lower._ticks, upper._ticks, msg, line);
4028 }
4029
4030 version (CoreUnittest) void assertApprox()(long actual,
4031 long lower,
4032 long upper,
4033 string msg = "unittest failure",
4034 size_t line = __LINE__)
4035 {
4036 if (actual < lower)
4037 throw new AssertError(msg ~ ": lower: " ~ signedToTempString(actual).idup, __FILE__, line);
4038 if (actual > upper)
4039 throw new AssertError(msg ~ ": upper: " ~ signedToTempString(actual).idup, __FILE__, line);
4040 }
4041