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

Commit 83ec881

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 83ec881

File tree

1 file changed

+46
-27
lines changed

1 file changed

+46
-27
lines changed

src/core/checkedint.d

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@
1919
* relative to the cost of the operation itself, compiler implementations are free
2020
* to recognize them and generate equivalent and faster code.
2121
*
22-
* References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks)
2322
* Copyright: Copyright (c) Walter Bright 2014.
2423
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
25-
* Authors: Walter Bright
24+
* Authors: Walter Bright, Denis Shelomovskij
2625
* Source: $(DRUNTIMESRC core/_checkedint.d)
2726
*/
2827

@@ -49,10 +48,11 @@ pure:
4948
pragma(inline, true)
5049
int adds(int x, int y, ref bool overflow)
5150
{
52-
long r = cast(long)x + cast(long)y;
53-
if (r < int.min || r > int.max)
51+
const r = x + y;
52+
if ( ~x._differentSign(y) // x and y has the same sign
53+
& x._differentSign(r)) // result has different sign
5454
overflow = true;
55-
return cast(int)r;
55+
return r;
5656
}
5757

5858
unittest
@@ -77,9 +77,9 @@ unittest
7777
pragma(inline, true)
7878
long adds(long x, long y, ref bool overflow)
7979
{
80-
long r = cast(ulong)x + cast(ulong)y;
81-
if (x < 0 && y < 0 && r >= 0 ||
82-
x >= 0 && y >= 0 && r < 0)
80+
const r = x + y;
81+
if ( ~x._differentSign(y) // x and y has the same sign
82+
& x._differentSign(r)) // result has different sign
8383
overflow = true;
8484
return r;
8585
}
@@ -119,8 +119,8 @@ unittest
119119
pragma(inline, true)
120120
uint addu(uint x, uint y, ref bool overflow)
121121
{
122-
uint r = x + y;
123-
if (r < x || r < y)
122+
const r = x + y;
123+
if (r < x)
124124
overflow = true;
125125
return r;
126126
}
@@ -147,8 +147,8 @@ unittest
147147
pragma(inline, true)
148148
ulong addu(ulong x, ulong y, ref bool overflow)
149149
{
150-
ulong r = x + y;
151-
if (r < x || r < y)
150+
const r = x + y;
151+
if (r < x)
152152
overflow = true;
153153
return r;
154154
}
@@ -188,10 +188,11 @@ unittest
188188
pragma(inline, true)
189189
int subs(int x, int y, ref bool overflow)
190190
{
191-
long r = cast(long)x - cast(long)y;
192-
if (r < int.min || r > int.max)
191+
const r = x - y;
192+
if ( x._differentSign(y) // x and y has different sign
193+
& x._differentSign(r)) // result and x has different sign
193194
overflow = true;
194-
return cast(int)r;
195+
return r;
195196
}
196197

197198
unittest
@@ -216,9 +217,9 @@ unittest
216217
pragma(inline, true)
217218
long subs(long x, long y, ref bool overflow)
218219
{
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))
220+
const r = x - y;
221+
if ( x._differentSign(y) // x and y has different sign
222+
& x._differentSign(r)) // result and x has different sign
222223
overflow = true;
223224
return r;
224225
}
@@ -385,10 +386,10 @@ unittest
385386
pragma(inline, true)
386387
int muls(int x, int y, ref bool overflow)
387388
{
388-
long r = cast(long)x * cast(long)y;
389+
const r = cast(long) x * y;
389390
if (r < int.min || r > int.max)
390391
overflow = true;
391-
return cast(int)r;
392+
return cast(int) r;
392393
}
393394

394395
unittest
@@ -415,9 +416,10 @@ unittest
415416
pragma(inline, true)
416417
long muls(long x, long y, ref bool overflow)
417418
{
418-
long r = cast(ulong)x * cast(ulong)y;
419-
enum not0or1 = ~1L;
420-
if((x & not0or1) && ((r == y)? r : (r / x) != y))
419+
const r = x * y;
420+
if ( ~x._differentSign(y) // x and y has the same sign
421+
& r._signBit // and result is negative (covers min * -1)
422+
|| x && r / x != y) // or perform simple check for x != 0
421423
overflow = true;
422424
return r;
423425
}
@@ -462,10 +464,10 @@ unittest
462464
pragma(inline, true)
463465
uint mulu(uint x, uint y, ref bool overflow)
464466
{
465-
ulong r = ulong(x) * ulong(y);
467+
const r = cast(ulong) x * y;
466468
if (r > uint.max)
467469
overflow = true;
468-
return cast(uint)r;
470+
return cast(uint) r;
469471
}
470472

471473
unittest
@@ -492,8 +494,8 @@ unittest
492494
pragma(inline, true)
493495
ulong mulu(ulong x, ulong y, ref bool overflow)
494496
{
495-
ulong r = x * y;
496-
if (x && (r / x) != y)
497+
const r = x * y;
498+
if (x && r / x != y)
497499
overflow = true;
498500
return r;
499501
}
@@ -517,3 +519,20 @@ unittest
517519
assert(mulu(0UL, 0UL, overflow) == 0);
518520
assert(overflow); // sticky
519521
}
522+
523+
524+
private:
525+
526+
pragma(inline, true)
527+
@property size_t _signBit(T)(in T n)
528+
if(is(T == int) || is(T == long))
529+
{
530+
return cast(size_t) (n >>> T.sizeof * 8 - 1);
531+
}
532+
533+
pragma(inline, true)
534+
size_t _differentSign(T)(in T a, in T b)
535+
if(is(T == int) || is(T == long))
536+
{
537+
return a._signBit ^ b._signBit;
538+
}

0 commit comments

Comments
 (0)