19
19
* relative to the cost of the operation itself, compiler implementations are free
20
20
* to recognize them and generate equivalent and faster code.
21
21
*
22
- * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks)
23
22
* Copyright: Copyright (c) Walter Bright 2014.
24
23
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
25
- * Authors: Walter Bright
24
+ * Authors: Walter Bright, Denis Shelomovskij
26
25
* Source: $(DRUNTIMESRC core/_checkedint.d)
27
26
*/
28
27
@@ -49,10 +48,11 @@ pure:
49
48
pragma (inline, true )
50
49
int adds (int x, int y, ref bool overflow)
51
50
{
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
54
54
overflow = true ;
55
- return cast ( int ) r;
55
+ return r;
56
56
}
57
57
58
58
unittest
@@ -77,9 +77,9 @@ unittest
77
77
pragma (inline, true )
78
78
long adds (long x, long y, ref bool overflow)
79
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 )
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
83
83
overflow = true ;
84
84
return r;
85
85
}
@@ -119,8 +119,8 @@ unittest
119
119
pragma (inline, true )
120
120
uint addu (uint x, uint y, ref bool overflow)
121
121
{
122
- uint r = x + y;
123
- if (r < x || r < y )
122
+ const r = x + y;
123
+ if (r < x)
124
124
overflow = true ;
125
125
return r;
126
126
}
@@ -147,8 +147,8 @@ unittest
147
147
pragma (inline, true )
148
148
ulong addu (ulong x, ulong y, ref bool overflow)
149
149
{
150
- ulong r = x + y;
151
- if (r < x || r < y )
150
+ const r = x + y;
151
+ if (r < x)
152
152
overflow = true ;
153
153
return r;
154
154
}
@@ -188,10 +188,11 @@ unittest
188
188
pragma (inline, true )
189
189
int subs (int x, int y, ref bool overflow)
190
190
{
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
193
194
overflow = true ;
194
- return cast ( int ) r;
195
+ return r;
195
196
}
196
197
197
198
unittest
@@ -216,9 +217,9 @@ unittest
216
217
pragma (inline, true )
217
218
long subs (long x, long y, ref bool overflow)
218
219
{
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
222
223
overflow = true ;
223
224
return r;
224
225
}
@@ -385,10 +386,10 @@ unittest
385
386
pragma (inline, true )
386
387
int muls (int x, int y, ref bool overflow)
387
388
{
388
- long r = cast (long )x * cast ( long ) y;
389
+ const r = cast (long ) x * y;
389
390
if (r < int .min || r > int .max)
390
391
overflow = true ;
391
- return cast (int )r;
392
+ return cast (int ) r;
392
393
}
393
394
394
395
unittest
@@ -415,9 +416,10 @@ unittest
415
416
pragma (inline, true )
416
417
long muls (long x, long y, ref bool overflow)
417
418
{
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
421
423
overflow = true ;
422
424
return r;
423
425
}
@@ -462,10 +464,10 @@ unittest
462
464
pragma (inline, true )
463
465
uint mulu (uint x, uint y, ref bool overflow)
464
466
{
465
- ulong r = ulong (x) * ulong (y) ;
467
+ const r = cast ( ulong ) x * y ;
466
468
if (r > uint .max)
467
469
overflow = true ;
468
- return cast (uint )r;
470
+ return cast (uint ) r;
469
471
}
470
472
471
473
unittest
@@ -492,8 +494,8 @@ unittest
492
494
pragma (inline, true )
493
495
ulong mulu (ulong x, ulong y, ref bool overflow)
494
496
{
495
- ulong r = x * y;
496
- if (x && ( r / x) != y)
497
+ const r = x * y;
498
+ if (x && r / x != y)
497
499
overflow = true ;
498
500
return r;
499
501
}
@@ -517,3 +519,20 @@ unittest
517
519
assert (mulu(0UL , 0UL , overflow) == 0 );
518
520
assert (overflow); // sticky
519
521
}
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