1 2 /********************************************** 3 * This module implements integral arithmetic primitives that check 4 * for out-of-range results. 5 * 6 * Integral arithmetic operators operate on fixed width types. 7 * Results that are not representable in those fixed widths are silently 8 * truncated to fit. 9 * This module offers integral arithmetic primitives that produce the 10 * same results, but set an 'overflow' flag when such truncation occurs. 11 * The setting is sticky, meaning that numerous operations can be cascaded 12 * and then the flag need only be checked at the end. 13 * Whether the operation is signed or unsigned is indicated by an 's' or 'u' 14 * suffix, respectively. While this could be achieved without such suffixes by 15 * using overloading on the signedness of the types, the suffix makes it clear 16 * which is happening without needing to examine the types. 17 * 18 * While the generic versions of these functions are computationally expensive 19 * relative to the cost of the operation itself, compiler implementations are free 20 * to recognize them and generate equivalent and faster code. 21 * 22 * The functions here are templates so they can be used with -betterC, 23 * as betterC does not link with this library. 24 * 25 * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks) 26 * Copyright: Copyright (c) Walter Bright 2014. 27 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 28 * Authors: Walter Bright 29 * Source: $(DRUNTIMESRC core/_checkedint.d) 30 */ 31 32 module core.checkedint; 33 34 import core.internal.attributes : betterC; 35 36 nothrow: 37 @safe: 38 @nogc: 39 pure: 40 41 /******************************* 42 * Add two signed integers, checking for overflow. 43 * 44 * The overflow is sticky, meaning a sequence of operations can 45 * be done and overflow need only be checked at the end. 46 * Params: 47 * x = left operand 48 * y = right operand 49 * overflow = set if an overflow occurs, is not affected otherwise 50 * Returns: 51 * the sum 52 */ 53 54 pragma(inline, true) 55 int adds()(int x, int y, ref bool overflow) 56 { 57 long r = cast(long)x + cast(long)y; 58 if (r < int.min || r > int.max) 59 overflow = true; 60 return cast(int)r; 61 } 62 63 /// 64 @betterC 65 unittest 66 { 67 bool overflow; 68 assert(adds(2, 3, overflow) == 5); 69 assert(!overflow); 70 71 assert(adds(1, int.max - 1, overflow) == int.max); 72 assert(!overflow); 73 74 assert(adds(int.min + 1, -1, overflow) == int.min); 75 assert(!overflow); 76 77 assert(adds(int.max, 1, overflow) == int.min); 78 assert(overflow); 79 80 overflow = false; 81 assert(adds(int.min, -1, overflow) == int.max); 82 assert(overflow); 83 84 assert(adds(0, 0, overflow) == 0); 85 assert(overflow); // sticky 86 } 87 88 /// ditto 89 pragma(inline, true) 90 long adds()(long x, long y, ref bool overflow) 91 { 92 long r = cast(ulong)x + cast(ulong)y; 93 if (x < 0 && y < 0 && r >= 0 || 94 x >= 0 && y >= 0 && r < 0) 95 overflow = true; 96 return r; 97 } 98 99 /// 100 @betterC 101 unittest 102 { 103 bool overflow; 104 assert(adds(2L, 3L, overflow) == 5); 105 assert(!overflow); 106 107 assert(adds(1L, long.max - 1, overflow) == long.max); 108 assert(!overflow); 109 110 assert(adds(long.min + 1, -1, overflow) == long.min); 111 assert(!overflow); 112 113 assert(adds(long.max, 1, overflow) == long.min); 114 assert(overflow); 115 116 overflow = false; 117 assert(adds(long.min, -1, overflow) == long.max); 118 assert(overflow); 119 120 assert(adds(0L, 0L, overflow) == 0); 121 assert(overflow); // sticky 122 } 123 124 static if (is(cent)) 125 { 126 /// ditto 127 pragma(inline, true) 128 cent adds()(cent x, cent y, ref bool overflow) 129 { 130 cent r = cast(ucent)x + cast(ucent)y; 131 if (x < 0 && y < 0 && r >= 0 || 132 x >= 0 && y >= 0 && r < 0) 133 overflow = true; 134 return r; 135 } 136 137 unittest 138 { 139 bool overflow; 140 assert(adds(cast(cent)2L, 3L, overflow) == 5); 141 assert(!overflow); 142 assert(adds(1L, cent.max - 1, overflow) == cent.max); 143 assert(!overflow); 144 assert(adds(cent.min + 1, -1, overflow) == cent.min); 145 assert(!overflow); 146 assert(adds(cent.max, 1, overflow) == cent.min); 147 assert(overflow); 148 overflow = false; 149 assert(adds(cent.min, -1, overflow) == cent.max); 150 assert(overflow); 151 assert(adds(cast(cent)0L, 0L, overflow) == 0); 152 assert(overflow); // sticky 153 } 154 } 155 156 157 /******************************* 158 * Add two unsigned integers, checking for overflow (aka carry). 159 * 160 * The overflow is sticky, meaning a sequence of operations can 161 * be done and overflow need only be checked at the end. 162 * Params: 163 * x = left operand 164 * y = right operand 165 * overflow = set if an overflow occurs, is not affected otherwise 166 * Returns: 167 * the sum 168 */ 169 170 pragma(inline, true) 171 uint addu()(uint x, uint y, ref bool overflow) 172 { 173 immutable uint r = x + y; 174 immutable bool o = r < x; 175 assert(o == (r < y)); 176 if (o) 177 overflow = true; 178 return r; 179 } 180 181 /// 182 @betterC 183 unittest 184 { 185 for (uint i = 0; i < 10; ++i) 186 { 187 bool overflow; 188 immutable uint r = addu (uint.max - i, uint.max - i, overflow); 189 assert (r == 2 * (uint.max - i)); 190 assert (overflow); 191 } 192 193 bool overflow; 194 assert(addu(2, 3, overflow) == 5); 195 assert(!overflow); 196 197 assert(addu(1, uint.max - 1, overflow) == uint.max); 198 assert(!overflow); 199 200 assert(addu(uint.min, -1, overflow) == uint.max); 201 assert(!overflow); 202 203 assert(addu(uint.max, 1, overflow) == uint.min); 204 assert(overflow); 205 206 overflow = false; 207 assert(addu(uint.min + 1, -1, overflow) == uint.min); 208 assert(overflow); 209 210 assert(addu(0, 0, overflow) == 0); 211 assert(overflow); // sticky 212 } 213 214 /// ditto 215 pragma(inline, true) 216 ulong addu()(ulong x, ulong y, ref bool overflow) 217 { 218 immutable ulong r = x + y; 219 immutable bool o = r < x; 220 assert(o == (r < y)); 221 if (o) 222 overflow = true; 223 return r; 224 } 225 226 /// 227 @betterC 228 unittest 229 { 230 bool overflow; 231 assert(addu(2L, 3L, overflow) == 5); 232 assert(!overflow); 233 234 assert(addu(1, ulong.max - 1, overflow) == ulong.max); 235 assert(!overflow); 236 237 assert(addu(ulong.min, -1L, overflow) == ulong.max); 238 assert(!overflow); 239 240 assert(addu(ulong.max, 1, overflow) == ulong.min); 241 assert(overflow); 242 243 overflow = false; 244 assert(addu(ulong.min + 1, -1L, overflow) == ulong.min); 245 assert(overflow); 246 247 assert(addu(0L, 0L, overflow) == 0); 248 assert(overflow); // sticky 249 } 250 251 static if (is(ucent)) 252 { 253 /// ditto 254 pragma(inline, true) 255 ucent addu()(ucent x, ucent y, ref bool overflow) 256 { 257 immutable ucent r = x + y; 258 immutable bool o = r < x; 259 assert(o == (r < y)); 260 if (o) 261 overflow = true; 262 return r; 263 } 264 265 unittest 266 { 267 bool overflow; 268 assert(addu(cast(ucent)2L, 3L, overflow) == 5); 269 assert(!overflow); 270 assert(addu(1, ucent.max - 1, overflow) == ucent.max); 271 assert(!overflow); 272 assert(addu(ucent.min, -1L, overflow) == ucent.max); 273 assert(!overflow); 274 assert(addu(ucent.max, 1, overflow) == ucent.min); 275 assert(overflow); 276 overflow = false; 277 assert(addu(ucent.min + 1, -1L, overflow) == ucent.min); 278 assert(overflow); 279 assert(addu(cast(ucent)0L, 0L, overflow) == 0); 280 assert(overflow); // sticky 281 } 282 } 283 284 285 /******************************* 286 * Subtract two signed integers, checking for overflow. 287 * 288 * The overflow is sticky, meaning a sequence of operations can 289 * be done and overflow need only be checked at the end. 290 * Params: 291 * x = left operand 292 * y = right operand 293 * overflow = set if an overflow occurs, is not affected otherwise 294 * Returns: 295 * the difference 296 */ 297 298 pragma(inline, true) 299 int subs()(int x, int y, ref bool overflow) 300 { 301 immutable long r = cast(long)x - cast(long)y; 302 if (r < int.min || r > int.max) 303 overflow = true; 304 return cast(int)r; 305 } 306 307 /// 308 @betterC 309 unittest 310 { 311 bool overflow; 312 assert(subs(2, -3, overflow) == 5); 313 assert(!overflow); 314 315 assert(subs(1, -int.max + 1, overflow) == int.max); 316 assert(!overflow); 317 318 assert(subs(int.min + 1, 1, overflow) == int.min); 319 assert(!overflow); 320 321 assert(subs(int.max, -1, overflow) == int.min); 322 assert(overflow); 323 324 overflow = false; 325 assert(subs(int.min, 1, overflow) == int.max); 326 assert(overflow); 327 328 assert(subs(0, 0, overflow) == 0); 329 assert(overflow); // sticky 330 } 331 332 /// ditto 333 pragma(inline, true) 334 long subs()(long x, long y, ref bool overflow) 335 { 336 immutable long r = cast(ulong)x - cast(ulong)y; 337 if (x < 0 && y >= 0 && r >= 0 || 338 x >= 0 && y < 0 && (r < 0 || y == long.min)) 339 overflow = true; 340 return r; 341 } 342 343 /// 344 @betterC 345 unittest 346 { 347 bool overflow; 348 assert(subs(2L, -3L, overflow) == 5); 349 assert(!overflow); 350 351 assert(subs(1L, -long.max + 1, overflow) == long.max); 352 assert(!overflow); 353 354 assert(subs(long.min + 1, 1, overflow) == long.min); 355 assert(!overflow); 356 357 assert(subs(-1L, long.min, overflow) == long.max); 358 assert(!overflow); 359 360 assert(subs(long.max, -1, overflow) == long.min); 361 assert(overflow); 362 363 overflow = false; 364 assert(subs(long.min, 1, overflow) == long.max); 365 assert(overflow); 366 367 assert(subs(0L, 0L, overflow) == 0); 368 assert(overflow); // sticky 369 } 370 371 static if (is(cent)) 372 { 373 /// ditto 374 pragma(inline, true) 375 cent subs()(cent x, cent y, ref bool overflow) 376 { 377 immutable cent r = cast(ucent)x - cast(ucent)y; 378 if (x < 0 && y >= 0 && r >= 0 || 379 x >= 0 && y < 0 && (r < 0 || y == long.min)) 380 overflow = true; 381 return r; 382 } 383 384 unittest 385 { 386 bool overflow; 387 assert(subs(cast(cent)2L, -3L, overflow) == 5); 388 assert(!overflow); 389 assert(subs(1L, -cent.max + 1, overflow) == cent.max); 390 assert(!overflow); 391 assert(subs(cent.min + 1, 1, overflow) == cent.min); 392 assert(!overflow); 393 assert(subs(-1L, cent.min, overflow) == cent.max); 394 assert(!overflow); 395 assert(subs(cent.max, -1, overflow) == cent.min); 396 assert(overflow); 397 overflow = false; 398 assert(subs(cent.min, 1, overflow) == cent.max); 399 assert(overflow); 400 assert(subs(cast(cent)0L, 0L, overflow) == 0); 401 assert(overflow); // sticky 402 } 403 } 404 405 406 /******************************* 407 * Subtract two unsigned integers, checking for overflow (aka borrow). 408 * 409 * The overflow is sticky, meaning a sequence of operations can 410 * be done and overflow need only be checked at the end. 411 * Params: 412 * x = left operand 413 * y = right operand 414 * overflow = set if an overflow occurs, is not affected otherwise 415 * Returns: 416 * the difference 417 */ 418 419 pragma(inline, true) 420 uint subu()(uint x, uint y, ref bool overflow) 421 { 422 if (x < y) 423 overflow = true; 424 return x - y; 425 } 426 427 /// 428 @betterC 429 unittest 430 { 431 bool overflow; 432 assert(subu(3, 2, overflow) == 1); 433 assert(!overflow); 434 435 assert(subu(uint.max, 1, overflow) == uint.max - 1); 436 assert(!overflow); 437 438 assert(subu(1, 1, overflow) == uint.min); 439 assert(!overflow); 440 441 assert(subu(0, 1, overflow) == uint.max); 442 assert(overflow); 443 444 overflow = false; 445 assert(subu(uint.max - 1, uint.max, overflow) == uint.max); 446 assert(overflow); 447 448 assert(subu(0, 0, overflow) == 0); 449 assert(overflow); // sticky 450 } 451 452 453 /// ditto 454 pragma(inline, true) 455 ulong subu()(ulong x, ulong y, ref bool overflow) 456 { 457 if (x < y) 458 overflow = true; 459 return x - y; 460 } 461 462 /// 463 @betterC 464 unittest 465 { 466 bool overflow; 467 assert(subu(3UL, 2UL, overflow) == 1); 468 assert(!overflow); 469 470 assert(subu(ulong.max, 1, overflow) == ulong.max - 1); 471 assert(!overflow); 472 473 assert(subu(1UL, 1UL, overflow) == ulong.min); 474 assert(!overflow); 475 476 assert(subu(0UL, 1UL, overflow) == ulong.max); 477 assert(overflow); 478 479 overflow = false; 480 assert(subu(ulong.max - 1, ulong.max, overflow) == ulong.max); 481 assert(overflow); 482 483 assert(subu(0UL, 0UL, overflow) == 0); 484 assert(overflow); // sticky 485 } 486 487 static if (is(ucent)) 488 { 489 /// ditto 490 pragma(inline, true) 491 ucent subu()(ucent x, ucent y, ref bool overflow) 492 { 493 if (x < y) 494 overflow = true; 495 return x - y; 496 } 497 498 unittest 499 { 500 bool overflow; 501 assert(subu(cast(ucent)3UL, 2UL, overflow) == 1); 502 assert(!overflow); 503 assert(subu(ucent.max, 1, overflow) == ucent.max - 1); 504 assert(!overflow); 505 assert(subu(1UL, 1UL, overflow) == ucent.min); 506 assert(!overflow); 507 assert(subu(cast(ucent)0UL, 1UL, overflow) == ucent.max); 508 assert(overflow); 509 overflow = false; 510 assert(subu(ucent.max - 1, ucent.max, overflow) == ucent.max); 511 assert(overflow); 512 assert(subu(cast(ucent)0UL, 0UL, overflow) == 0); 513 assert(overflow); // sticky 514 } 515 } 516 517 518 /*********************************************** 519 * Negate an integer. 520 * 521 * Params: 522 * x = operand 523 * overflow = set if x cannot be negated, is not affected otherwise 524 * Returns: 525 * the negation of x 526 */ 527 528 pragma(inline, true) 529 int negs()(int x, ref bool overflow) 530 { 531 if (x == int.min) 532 overflow = true; 533 return -x; 534 } 535 536 /// 537 @betterC 538 unittest 539 { 540 bool overflow; 541 assert(negs(0, overflow) == -0); 542 assert(!overflow); 543 544 assert(negs(1234, overflow) == -1234); 545 assert(!overflow); 546 547 assert(negs(-5678, overflow) == 5678); 548 assert(!overflow); 549 550 assert(negs(int.min, overflow) == -int.min); 551 assert(overflow); 552 553 assert(negs(0, overflow) == -0); 554 assert(overflow); // sticky 555 } 556 557 /// ditto 558 pragma(inline, true) 559 long negs()(long x, ref bool overflow) 560 { 561 if (x == long.min) 562 overflow = true; 563 return -x; 564 } 565 566 /// 567 @betterC 568 unittest 569 { 570 bool overflow; 571 assert(negs(0L, overflow) == -0); 572 assert(!overflow); 573 574 assert(negs(1234L, overflow) == -1234); 575 assert(!overflow); 576 577 assert(negs(-5678L, overflow) == 5678); 578 assert(!overflow); 579 580 assert(negs(long.min, overflow) == -long.min); 581 assert(overflow); 582 583 assert(negs(0L, overflow) == -0); 584 assert(overflow); // sticky 585 } 586 587 static if (is(cent)) 588 { 589 /// ditto 590 pragma(inline, true) 591 cent negs()(cent x, ref bool overflow) 592 { 593 if (x == cent.min) 594 overflow = true; 595 return -x; 596 } 597 598 unittest 599 { 600 bool overflow; 601 assert(negs(cast(cent)0L, overflow) == -0); 602 assert(!overflow); 603 assert(negs(cast(cent)1234L, overflow) == -1234); 604 assert(!overflow); 605 assert(negs(cast(cent)-5678L, overflow) == 5678); 606 assert(!overflow); 607 assert(negs(cent.min, overflow) == -cent.min); 608 assert(overflow); 609 assert(negs(cast(cent)0L, overflow) == -0); 610 assert(overflow); // sticky 611 } 612 } 613 614 615 /******************************* 616 * Multiply two signed integers, checking for overflow. 617 * 618 * The overflow is sticky, meaning a sequence of operations can 619 * be done and overflow need only be checked at the end. 620 * Params: 621 * x = left operand 622 * y = right operand 623 * overflow = set if an overflow occurs, is not affected otherwise 624 * Returns: 625 * the product 626 */ 627 628 pragma(inline, true) 629 int muls()(int x, int y, ref bool overflow) 630 { 631 long r = cast(long)x * cast(long)y; 632 if (r < int.min || r > int.max) 633 overflow = true; 634 return cast(int)r; 635 } 636 637 /// 638 @betterC 639 unittest 640 { 641 bool overflow; 642 assert(muls(2, 3, overflow) == 6); 643 assert(!overflow); 644 645 assert(muls(-200, 300, overflow) == -60_000); 646 assert(!overflow); 647 648 assert(muls(1, int.max, overflow) == int.max); 649 assert(!overflow); 650 651 assert(muls(int.min, 1, overflow) == int.min); 652 assert(!overflow); 653 654 assert(muls(int.max, 2, overflow) == (int.max * 2)); 655 assert(overflow); 656 657 overflow = false; 658 assert(muls(int.min, -1, overflow) == int.min); 659 assert(overflow); 660 661 assert(muls(0, 0, overflow) == 0); 662 assert(overflow); // sticky 663 } 664 665 /// ditto 666 pragma(inline, true) 667 long muls()(long x, long y, ref bool overflow) 668 { 669 immutable long r = cast(ulong)x * cast(ulong)y; 670 enum not0or1 = ~1L; 671 if ((x & not0or1) && 672 ((r == y) ? r != 0 673 : (r == 0x8000_0000_0000_0000 && x == -1L) || ((r / x) != y))) 674 overflow = true; 675 return r; 676 } 677 678 /// 679 @betterC 680 unittest 681 { 682 bool overflow; 683 assert(muls(2L, 3L, overflow) == 6); 684 assert(!overflow); 685 686 assert(muls(-200L, 300L, overflow) == -60_000); 687 assert(!overflow); 688 689 assert(muls(1, long.max, overflow) == long.max); 690 assert(!overflow); 691 692 assert(muls(long.min, 1L, overflow) == long.min); 693 assert(!overflow); 694 695 assert(muls(long.max, 2L, overflow) == (long.max * 2)); 696 assert(overflow); 697 overflow = false; 698 699 assert(muls(-1L, long.min, overflow) == long.min); 700 assert(overflow); 701 702 overflow = false; 703 assert(muls(long.min, -1L, overflow) == long.min); 704 assert(overflow); 705 706 assert(muls(0L, 0L, overflow) == 0); 707 assert(overflow); // sticky 708 } 709 710 static if (is(cent)) 711 { 712 /// ditto 713 pragma(inline, true) 714 cent muls()(cent x, cent y, ref bool overflow) 715 { 716 immutable cent r = cast(ucent)x * cast(ucent)y; 717 enum not0or1 = ~1L; 718 if ((x & not0or1) && ((r == y)? r : (r / x) != y)) 719 overflow = true; 720 return r; 721 } 722 723 unittest 724 { 725 bool overflow; 726 assert(muls(cast(cent)2L, 3L, overflow) == 6); 727 assert(!overflow); 728 assert(muls(cast(cent)-200L, 300L, overflow) == -60_000); 729 assert(!overflow); 730 assert(muls(1, cent.max, overflow) == cent.max); 731 assert(!overflow); 732 assert(muls(cent.min, 1L, overflow) == cent.min); 733 assert(!overflow); 734 assert(muls(cent.max, 2L, overflow) == (cent.max * 2)); 735 assert(overflow); 736 overflow = false; 737 assert(muls(-1L, cent.min, overflow) == cent.min); 738 assert(overflow); 739 overflow = false; 740 assert(muls(cent.min, -1L, overflow) == cent.min); 741 assert(overflow); 742 assert(muls(cast(cent)0L, 0L, overflow) == 0); 743 assert(overflow); // sticky 744 } 745 } 746 747 748 /******************************* 749 * Multiply two unsigned integers, checking for overflow (aka carry). 750 * 751 * The overflow is sticky, meaning a sequence of operations can 752 * be done and overflow need only be checked at the end. 753 * Params: 754 * x = left operand 755 * y = right operand 756 * overflow = set if an overflow occurs, is not affected otherwise 757 * Returns: 758 * the product 759 */ 760 pragma(inline, true) 761 uint mulu()(uint x, uint y, ref bool overflow) 762 { 763 immutable ulong r = ulong(x) * ulong(y); 764 if (r >> 32) 765 overflow = true; 766 return cast(uint) r; 767 } 768 769 @betterC 770 unittest 771 { 772 void test(uint x, uint y, uint r, bool overflow) @nogc nothrow 773 { 774 bool o; 775 assert(mulu(x, y, o) == r); 776 assert(o == overflow); 777 } 778 test(2, 3, 6, false); 779 test(1, uint.max, uint.max, false); 780 test(0, 1, 0, false); 781 test(0, uint.max, 0, false); 782 test(uint.max, 2, 2 * uint.max, true); 783 test(1 << 16, 1U << 16, 0, true); 784 785 bool overflow = true; 786 assert(mulu(0, 0, overflow) == 0); 787 assert(overflow); // sticky 788 } 789 790 /// ditto 791 pragma(inline, true) 792 ulong mulu()(ulong x, uint y, ref bool overflow) 793 { 794 ulong r = x * y; 795 if (x >> 32 && 796 r / x != y) 797 overflow = true; 798 return r; 799 } 800 801 /// ditto 802 pragma(inline, true) 803 ulong mulu()(ulong x, ulong y, ref bool overflow) 804 { 805 immutable ulong r = x * y; 806 if ((x | y) >> 32 && 807 x && 808 r / x != y) 809 overflow = true; 810 return r; 811 } 812 813 @betterC 814 unittest 815 { 816 void test(T, U)(T x, U y, ulong r, bool overflow) @nogc nothrow 817 { 818 bool o; 819 assert(mulu(x, y, o) == r); 820 assert(o == overflow); 821 } 822 // One operand is zero 823 test(0, 3, 0, false); 824 test(0UL, 3, 0, false); 825 test(0UL, 3UL, 0, false); 826 test(3, 0, 0, false); 827 test(3UL, 0, 0, false); 828 test(3UL, 0UL, 0, false); 829 // Small numbers 830 test(2, 3, 6, false); 831 test(2UL, 3, 6, false); 832 test(2UL, 3UL, 6, false); 833 // At the 32/64 border 834 test(1, ulong(uint.max), uint.max, false); 835 test(1UL, ulong(uint.max), uint.max, false); 836 test(ulong(uint.max), 1, uint.max, false); 837 test(ulong(uint.max), 1UL, uint.max, false); 838 test(1, 1 + ulong(uint.max), 1 + ulong(uint.max), false); 839 test(1UL, 1 + ulong(uint.max), 1 + ulong(uint.max), false); 840 test(1 + ulong(uint.max), 1, 1 + ulong(uint.max), false); 841 test(1 + ulong(uint.max), 1UL, 1 + ulong(uint.max), false); 842 // At the limit 843 test(1, ulong.max, ulong.max, false); 844 test(1UL, ulong.max, ulong.max, false); 845 test(ulong.max, 1, ulong.max, false); 846 test(ulong.max, 1UL, ulong.max, false); 847 // Miscellaneous 848 test(0, 1, 0, false); 849 test(0, ulong.max, 0, false); 850 test(ulong.max, 2, 2 * ulong.max, true); 851 test(1UL << 32, 1UL << 32, 0, true); 852 // Must be sticky 853 bool overflow = true; 854 assert(mulu(0UL, 0UL, overflow) == 0); 855 assert(overflow); // sticky 856 } 857 858 static if (is(ucent)) 859 { 860 /// ditto 861 pragma(inline, true) 862 ucent mulu()(ucent x, ucent y, ref bool overflow) 863 { 864 immutable ucent r = x * y; 865 if (x && (r / x) != y) 866 overflow = true; 867 return r; 868 } 869 870 unittest 871 { 872 void test(ucent x, ucent y, ucent r, bool overflow) @nogc nothrow 873 { 874 bool o; 875 assert(mulu(x, y, o) == r); 876 assert(o == overflow); 877 } 878 test(2, 3, 6, false); 879 test(1, ucent.max, ucent.max, false); 880 test(0, 1, 0, false); 881 test(0, ucent.max, 0, false); 882 test(ucent.max, 2, 2 * ucent.max, true); 883 test(cast(ucent)1UL << 64, cast(ucent)1UL << 64, 0, true); 884 885 bool overflow = true; 886 assert(mulu(0UL, 0UL, overflow) == 0); 887 assert(overflow); // sticky 888 } 889 }