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 }