2222 * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks)
2323 * Copyright: Copyright (c) Walter Bright 2014.
2424 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
25- * Authors: Walter Bright
25+ * Authors: Walter Bright, Denis Shelomovskij
2626 * Source: $(DRUNTIMESRC core/_checkedint.d)
2727 */
2828
@@ -49,10 +49,11 @@ pure:
4949pragma (inline, true )
5050int adds (int x, int y, ref bool overflow)
5151{
52- long r = cast (long )x + cast (long )y;
53- if (r < int .min || r > int .max)
52+ const r = x + y;
53+ if (~ x._differentSign(y) & // x and y has the same sign
54+ x._differentSign(r)) // result has different sign
5455 overflow = true ;
55- return cast ( int ) r;
56+ return r;
5657}
5758
5859unittest
@@ -77,9 +78,9 @@ unittest
7778pragma (inline, true )
7879long adds (long x, long y, ref bool overflow)
7980{
80- long r = cast ( ulong ) x + cast ( ulong ) y;
81- if (x < 0 && y < 0 && r >= 0 ||
82- x >= 0 && y >= 0 && r < 0 )
81+ const r = x + y;
82+ if (~ x._differentSign(y) & // x and y has the same sign
83+ x._differentSign(r)) // result has different sign
8384 overflow = true ;
8485 return r;
8586}
@@ -119,8 +120,8 @@ unittest
119120pragma (inline, true )
120121uint addu (uint x, uint y, ref bool overflow)
121122{
122- uint r = x + y;
123- if (r < x || r < y )
123+ const r = x + y;
124+ if (r < x)
124125 overflow = true ;
125126 return r;
126127}
@@ -147,8 +148,8 @@ unittest
147148pragma (inline, true )
148149ulong addu (ulong x, ulong y, ref bool overflow)
149150{
150- ulong r = x + y;
151- if (r < x || r < y )
151+ const r = x + y;
152+ if (r < x)
152153 overflow = true ;
153154 return r;
154155}
@@ -188,10 +189,11 @@ unittest
188189pragma (inline, true )
189190int subs (int x, int y, ref bool overflow)
190191{
191- long r = cast (long )x - cast (long )y;
192- if (r < int .min || r > int .max)
192+ const r = x - y;
193+ if (x._differentSign(y) & // x and y has different sign
194+ x._differentSign(r)) // result and x has different sign
193195 overflow = true ;
194- return cast ( int ) r;
196+ return r;
195197}
196198
197199unittest
@@ -216,9 +218,9 @@ unittest
216218pragma (inline, true )
217219long subs (long x, long y, ref bool overflow)
218220{
219- long r = cast ( ulong ) x - cast ( ulong ) y;
220- if (x < 0 && y >= 0 && r >= 0 ||
221- x >= 0 && y < 0 && (r < 0 || y == long .min))
221+ const r = x - y;
222+ if (x._differentSign(y) & // x and y has different sign
223+ x._differentSign(r)) // result and x has different sign
222224 overflow = true ;
223225 return r;
224226}
@@ -385,10 +387,10 @@ unittest
385387pragma (inline, true )
386388int muls (int x, int y, ref bool overflow)
387389{
388- long r = cast (long )x * cast ( long ) y;
390+ const r = cast (long ) x * y;
389391 if (r < int .min || r > int .max)
390392 overflow = true ;
391- return cast (int )r;
393+ return cast (int ) r;
392394}
393395
394396unittest
@@ -415,9 +417,10 @@ unittest
415417pragma (inline, true )
416418long muls (long x, long y, ref bool overflow)
417419{
418- long r = cast (ulong )x * cast (ulong )y;
419- enum not0or1 = ~ 1L ;
420- if ((x & not0or1) && ((r == y)? r : (r / x) != y))
420+ const r = x * y;
421+ if (~ x._differentSign(y) & // x and y has the same sign
422+ r._signBits || // and result is negative (covers min * -1)
423+ x && r / x != y) // or perform simple check for x != 0
421424 overflow = true ;
422425 return r;
423426}
@@ -462,10 +465,10 @@ unittest
462465pragma (inline, true )
463466uint mulu (uint x, uint y, ref bool overflow)
464467{
465- ulong r = ulong (x) * ulong (y) ;
468+ const r = cast ( ulong ) x * y ;
466469 if (r > uint .max)
467470 overflow = true ;
468- return cast (uint )r;
471+ return cast (uint ) r;
469472}
470473
471474unittest
@@ -492,7 +495,7 @@ unittest
492495pragma (inline, true )
493496ulong mulu (ulong x, ulong y, ref bool overflow)
494497{
495- ulong r = x * y;
498+ const r = x * y;
496499 if (x && (r / x) != y)
497500 overflow = true ;
498501 return r;
@@ -517,3 +520,20 @@ unittest
517520 assert (mulu(0UL , 0UL , overflow) == 0 );
518521 assert (overflow); // sticky
519522}
523+
524+
525+ private :
526+
527+ pragma (inline, true )
528+ @property size_t _signBits(T)(in T n)
529+ if (is (T == int ) || is (T == long ))
530+ {
531+ return cast (size_t ) (n >> T.sizeof * 8 - 1 );
532+ }
533+
534+ pragma (inline, true )
535+ size_t _differentSign (T)(in T a, in T b)
536+ if (is (T == int ) || is (T == long ))
537+ {
538+ return (a ^ b)._signBits;
539+ }
0 commit comments