Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 38 additions & 25 deletions src/core/checkedint.d
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why take out the reference? This is critical information.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function implementations are completely rewritten so there is no connection with this blog any more. Also after looking into the blog it looks very silly: after the author performs bitshifts in checked_add_3 instead of using bitwise operators (like done in this pull) he uses this long and slow way:

(sa && sb && !sr) ||
(!sa && !sb && sr)

So is the really a reason to include a reference to this blog?

* Copyright: Copyright (c) Walter Bright 2014.
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Authors: Walter Bright
* Authors: Walter Bright, Denis Shelomovskij
* Source: $(DRUNTIMESRC core/_checkedint.d)
*/

Expand All @@ -49,10 +49,11 @@ pure:
pragma(inline, true)
int adds(int x, int y, ref bool overflow)
{
long r = cast(long)x + cast(long)y;
if (r < int.min || r > int.max)
const r = x + y;
if (!x._differentSign(y) && // x and y has the same sign
x._differentSign(r)) // result has different sign
overflow = true;
return cast(int)r;
return r;
}

unittest
Expand All @@ -77,9 +78,9 @@ unittest
pragma(inline, true)
long adds(long x, long y, ref bool overflow)
{
long r = cast(ulong)x + cast(ulong)y;
if (x < 0 && y < 0 && r >= 0 ||
x >= 0 && y >= 0 && r < 0)
const r = x + y;
if (!x._differentSign(y) && // x and y has the same sign
x._differentSign(r)) // result has different sign
overflow = true;
return r;
}
Expand Down Expand Up @@ -119,8 +120,8 @@ unittest
pragma(inline, true)
uint addu(uint x, uint y, ref bool overflow)
{
uint r = x + y;
if (r < x || r < y)
const r = x + y;
if (r < x)
overflow = true;
return r;
}
Expand All @@ -147,8 +148,8 @@ unittest
pragma(inline, true)
ulong addu(ulong x, ulong y, ref bool overflow)
{
ulong r = x + y;
if (r < x || r < y)
const r = x + y;
if (r < x)
overflow = true;
return r;
}
Expand Down Expand Up @@ -188,10 +189,11 @@ unittest
pragma(inline, true)
int subs(int x, int y, ref bool overflow)
{
long r = cast(long)x - cast(long)y;
if (r < int.min || r > int.max)
const r = x - y;
if (x._differentSign(y) && // x and y has different sign
x._differentSign(r)) // result and x has different sign
overflow = true;
return cast(int)r;
return r;
}

unittest
Expand All @@ -216,9 +218,9 @@ unittest
pragma(inline, true)
long subs(long x, long y, ref bool overflow)
{
long r = cast(ulong)x - cast(ulong)y;
if (x < 0 && y >= 0 && r >= 0 ||
x >= 0 && y < 0 && (r < 0 || y == long.min))
const r = x - y;
if (x._differentSign(y) && // x and y has different sign
x._differentSign(r)) // result and x has different sign
overflow = true;
return r;
}
Expand Down Expand Up @@ -385,10 +387,10 @@ unittest
pragma(inline, true)
int muls(int x, int y, ref bool overflow)
{
long r = cast(long)x * cast(long)y;
const r = cast(long) x * y;
if (r < int.min || r > int.max)
overflow = true;
return cast(int)r;
return cast(int) r;
}

unittest
Expand All @@ -415,9 +417,10 @@ unittest
pragma(inline, true)
long muls(long x, long y, ref bool overflow)
{
long r = cast(ulong)x * cast(ulong)y;
enum not0or1 = ~1L;
if((x & not0or1) && ((r == y)? r : (r / x) != y))
const r = x * y;
if (!x._differentSign(y) && // x and y has the same sign
r < 0 || // and result is negative (covers min * -1)
x && r / x != y) // or perform simple check for x != 0
overflow = true;
return r;
}
Expand Down Expand Up @@ -462,10 +465,10 @@ unittest
pragma(inline, true)
uint mulu(uint x, uint y, ref bool overflow)
{
ulong r = ulong(x) * ulong(y);
const r = cast(ulong) x * y;
if (r > uint.max)
overflow = true;
return cast(uint)r;
return cast(uint) r;
}

unittest
Expand All @@ -492,7 +495,7 @@ unittest
pragma(inline, true)
ulong mulu(ulong x, ulong y, ref bool overflow)
{
ulong r = x * y;
const r = x * y;
if (x && (r / x) != y)
overflow = true;
return r;
Expand All @@ -517,3 +520,13 @@ unittest
assert(mulu(0UL, 0UL, overflow) == 0);
assert(overflow); // sticky
}


private:

pragma(inline, true)
bool _differentSign(T)(in T a, in T b)
if(is(T == int) || is(T == long))
{
return (a < 0) != (b < 0);
}