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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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
pragma(inline,true)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 */
pragma(inline,true)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 {
test(uint x,uint y,uint r,bool overflow)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
pragma(inline,true)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
pragma(inline,true)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 {
test(T,U)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
pragma(inline,true)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 {
test(ucent x,ucent y,ucent r,bool overflow)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 }
890