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