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) && ((r == y)? r : (r / x) != y))
576 overflow = true;
577 return r;
578 }
579
580 unittest
581 {
582 bool overflow;
583 assert(muls(2L, 3L, overflow) == 6);
584 assert(!overflow);
585 assert(muls(-200L, 300L, overflow) == -60_000);
586 assert(!overflow);
587 assert(muls(1, long.max, overflow) == long.max);
588 assert(!overflow);
589 assert(muls(long.min, 1L, overflow) == long.min);
590 assert(!overflow);
591 assert(muls(long.max, 2L, overflow) == (long.max * 2));
592 assert(overflow);
593 overflow = false;
594 assert(muls(-1L, long.min, overflow) == long.min);
595 assert(overflow);
596 overflow = false;
597 assert(muls(long.min, -1L, overflow) == long.min);
598 assert(overflow);
599 assert(muls(0L, 0L, overflow) == 0);
600 assert(overflow); // sticky
601 }
602
603 static if (is(cent))
604 {
605 /// ditto
pragma(inline,true)606 pragma(inline, true)
607 cent muls(cent x, cent y, ref bool overflow)
608 {
609 immutable cent r = cast(ucent)x * cast(ucent)y;
610 enum not0or1 = ~1L;
611 if ((x & not0or1) && ((r == y)? r : (r / x) != y))
612 overflow = true;
613 return r;
614 }
615
616 unittest
617 {
618 bool overflow;
619 assert(muls(cast(cent)2L, 3L, overflow) == 6);
620 assert(!overflow);
621 assert(muls(cast(cent)-200L, 300L, overflow) == -60_000);
622 assert(!overflow);
623 assert(muls(1, cent.max, overflow) == cent.max);
624 assert(!overflow);
625 assert(muls(cent.min, 1L, overflow) == cent.min);
626 assert(!overflow);
627 assert(muls(cent.max, 2L, overflow) == (cent.max * 2));
628 assert(overflow);
629 overflow = false;
630 assert(muls(-1L, cent.min, overflow) == cent.min);
631 assert(overflow);
632 overflow = false;
633 assert(muls(cent.min, -1L, overflow) == cent.min);
634 assert(overflow);
635 assert(muls(cast(cent)0L, 0L, overflow) == 0);
636 assert(overflow); // sticky
637 }
638 }
639
640
641 /*******************************
642 * Multiply two unsigned integers, checking for overflow (aka carry).
643 *
644 * The overflow is sticky, meaning a sequence of operations can
645 * be done and overflow need only be checked at the end.
646 * Params:
647 * x = left operand
648 * y = right operand
649 * overflow = set if an overflow occurs, is not affected otherwise
650 * Returns:
651 * the product
652 */
653
pragma(inline,true)654 pragma(inline, true)
655 uint mulu(uint x, uint y, ref bool overflow)
656 {
657 immutable ulong r = ulong(x) * ulong(y);
658 if (r >> 32)
659 overflow = true;
660 return cast(uint) r;
661 }
662
663 unittest
664 {
test(uint x,uint y,uint r,bool overflow)665 void test(uint x, uint y, uint r, bool overflow) @nogc nothrow
666 {
667 bool o;
668 assert(mulu(x, y, o) == r);
669 assert(o == overflow);
670 }
671 test(2, 3, 6, false);
672 test(1, uint.max, uint.max, false);
673 test(0, 1, 0, false);
674 test(0, uint.max, 0, false);
675 test(uint.max, 2, 2 * uint.max, true);
676 test(1 << 16, 1U << 16, 0, true);
677
678 bool overflow = true;
679 assert(mulu(0, 0, overflow) == 0);
680 assert(overflow); // sticky
681 }
682
683 /// ditto
pragma(inline,true)684 pragma(inline, true)
685 ulong mulu(ulong x, uint y, ref bool overflow)
686 {
687 ulong r = x * y;
688 if (x >> 32 &&
689 r / x != y)
690 overflow = true;
691 return r;
692 }
693
694 /// ditto
pragma(inline,true)695 pragma(inline, true)
696 ulong mulu(ulong x, ulong y, ref bool overflow)
697 {
698 immutable ulong r = x * y;
699 if ((x | y) >> 32 &&
700 x &&
701 r / x != y)
702 overflow = true;
703 return r;
704 }
705
706 unittest
707 {
test(T,U)708 void test(T, U)(T x, U y, ulong r, bool overflow) @nogc nothrow
709 {
710 bool o;
711 assert(mulu(x, y, o) == r);
712 assert(o == overflow);
713 }
714 // One operand is zero
715 test(0, 3, 0, false);
716 test(0UL, 3, 0, false);
717 test(0UL, 3UL, 0, false);
718 test(3, 0, 0, false);
719 test(3UL, 0, 0, false);
720 test(3UL, 0UL, 0, false);
721 // Small numbers
722 test(2, 3, 6, false);
723 test(2UL, 3, 6, false);
724 test(2UL, 3UL, 6, false);
725 // At the 32/64 border
726 test(1, ulong(uint.max), uint.max, false);
727 test(1UL, ulong(uint.max), uint.max, false);
728 test(ulong(uint.max), 1, uint.max, false);
729 test(ulong(uint.max), 1UL, uint.max, false);
730 test(1, 1 + ulong(uint.max), 1 + ulong(uint.max), false);
731 test(1UL, 1 + ulong(uint.max), 1 + ulong(uint.max), false);
732 test(1 + ulong(uint.max), 1, 1 + ulong(uint.max), false);
733 test(1 + ulong(uint.max), 1UL, 1 + ulong(uint.max), false);
734 // At the limit
735 test(1, ulong.max, ulong.max, false);
736 test(1UL, ulong.max, ulong.max, false);
737 test(ulong.max, 1, ulong.max, false);
738 test(ulong.max, 1UL, ulong.max, false);
739 // Miscellaneous
740 test(0, 1, 0, false);
741 test(0, ulong.max, 0, false);
742 test(ulong.max, 2, 2 * ulong.max, true);
743 test(1UL << 32, 1UL << 32, 0, true);
744 // Must be sticky
745 bool overflow = true;
746 assert(mulu(0UL, 0UL, overflow) == 0);
747 assert(overflow); // sticky
748 }
749
750 static if (is(ucent))
751 {
752 /// ditto
pragma(inline,true)753 pragma(inline, true)
754 ucent mulu(ucent x, ucent y, ref bool overflow)
755 {
756 immutable ucent r = x * y;
757 if (x && (r / x) != y)
758 overflow = true;
759 return r;
760 }
761
762 unittest
763 {
test(ucent x,ucent y,ucent r,bool overflow)764 void test(ucent x, ucent y, ucent r, bool overflow) @nogc nothrow
765 {
766 bool o;
767 assert(mulu(x, y, o) == r);
768 assert(o == overflow);
769 }
770 test(2, 3, 6, false);
771 test(1, ucent.max, ucent.max, false);
772 test(0, 1, 0, false);
773 test(0, ucent.max, 0, false);
774 test(ucent.max, 2, 2 * ucent.max, true);
775 test(cast(ucent)1UL << 64, cast(ucent)1UL << 64, 0, true);
776
777 bool overflow = true;
778 assert(mulu(0UL, 0UL, overflow) == 0);
779 assert(overflow); // sticky
780 }
781 }
782