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