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