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