Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit a675dcb

Browse files
committed
Rewrite core.checkedint functions.
Use fast and simple sign comparison instead of long, slow and complicated value comparisons. Also remove reference as it doesn't apply anymore.
1 parent 6f931f1 commit a675dcb

File tree

1 file changed

+45
-25
lines changed

1 file changed

+45
-25
lines changed

src/core/checkedint.d

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
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:
4949
pragma(inline, true)
5050
int 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

5859
unittest
@@ -77,9 +78,9 @@ unittest
7778
pragma(inline, true)
7879
long 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
119120
pragma(inline, true)
120121
uint 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
147148
pragma(inline, true)
148149
ulong 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
188189
pragma(inline, true)
189190
int 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

197199
unittest
@@ -216,9 +218,9 @@ unittest
216218
pragma(inline, true)
217219
long 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
385387
pragma(inline, true)
386388
int 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

394396
unittest
@@ -415,9 +417,10 @@ unittest
415417
pragma(inline, true)
416418
long 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
462465
pragma(inline, true)
463466
uint 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

471474
unittest
@@ -492,7 +495,7 @@ unittest
492495
pragma(inline, true)
493496
ulong 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

Comments
 (0)