/********************************************** * This module implements integral arithmetic primitives that check * for out-of-range results. * * Integral arithmetic operators operate on fixed width types. * Results that are not representable in those fixed widths are silently * truncated to fit. * This module offers integral arithmetic primitives that produce the * same results, but set an 'overflow' flag when such truncation occurs. * The setting is sticky, meaning that numerous operations can be cascaded * and then the flag need only be checked at the end. * Whether the operation is signed or unsigned is indicated by an 's' or 'u' * suffix, respectively. While this could be achieved without such suffixes by * using overloading on the signedness of the types, the suffix makes it clear * which is happening without needing to examine the types. * * While the generic versions of these functions are computationally expensive * relative to the cost of the operation itself, compiler implementations are free * to recognize them and generate equivalent and faster code. * * The functions here are templates so they can be used with -betterC, * as betterC does not link with this library. * * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks) * Copyright: Copyright (c) Walter Bright 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Walter Bright * Source: $(DRUNTIMESRC core/_checkedint.d) */ module core.checkedint; import core.internal.attributes : betterC; nothrow:@safe:@nogc:pure: /******************************* * Add two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the sum */ 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) overflow = true; return cast(int)r;} ///@betterCunittest{ bool overflow; assert(adds(2, 3, overflow) == 5); assert(!overflow); assert(adds(1, int.max - 1, overflow) == int.max); assert(!overflow); assert(adds(int.min + 1, -1, overflow) == int.min); assert(!overflow); assert(adds(int.max, 1, overflow) == int.min); assert(overflow); overflow = false; assert(adds(int.min, -1, overflow) == int.max); assert(overflow); assert(adds(0, 0, overflow) == 0); assert(overflow); // sticky} /// dittopragma(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) overflow = true; return r;} ///@betterCunittest{ bool overflow; assert(adds(2L, 3L, overflow) == 5); assert(!overflow); assert(adds(1L, long.max - 1, overflow) == long.max); assert(!overflow); assert(adds(long.min + 1, -1, overflow) == long.min); assert(!overflow); assert(adds(long.max, 1, overflow) == long.min); assert(overflow); overflow = false; assert(adds(long.min, -1, overflow) == long.max); assert(overflow); assert(adds(0L, 0L, overflow) == 0); assert(overflow); // sticky} static if (is(cent)){/// dittopragma(inline, true)cent adds()(cent x, cent y, ref bool overflow){ cent r = cast(ucent)x + cast(ucent)y; if (x < 0 && y < 0 && r >= 0 || x >= 0 && y >= 0 && r < 0) overflow = true; return r;} unittest{ bool overflow; assert(adds(cast(cent)2L, 3L, overflow) == 5); assert(!overflow); assert(adds(1L, cent.max - 1, overflow) == cent.max); assert(!overflow); assert(adds(cent.min + 1, -1, overflow) == cent.min); assert(!overflow); assert(adds(cent.max, 1, overflow) == cent.min); assert(overflow); overflow = false; assert(adds(cent.min, -1, overflow) == cent.max); assert(overflow); assert(adds(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky}} /******************************* * Add two unsigned integers, checking for overflow (aka carry). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the sum */ pragma(inline, true)uint addu()(uint x, uint y, ref bool overflow){ immutable uint r = x + y; immutable bool o = r < x; assert(o == (r < y)); if (o) overflow = true; return r;} ///@betterCunittest{ for (uint i = 0; i < 10; ++i) { bool overflow; immutable uint r = addu (uint.max - i, uint.max - i, overflow); assert(r == 2 * (uint.max - i)); assert(overflow); } bool overflow; assert(addu(2, 3, overflow) == 5); assert(!overflow); assert(addu(1, uint.max - 1, overflow) == uint.max); assert(!overflow); assert(addu(uint.min, -1, overflow) == uint.max); assert(!overflow); assert(addu(uint.max, 1, overflow) == uint.min); assert(overflow); overflow = false; assert(addu(uint.min + 1, -1, overflow) == uint.min); assert(overflow); assert(addu(0, 0, overflow) == 0); assert(overflow); // sticky} /// dittopragma(inline, true)ulong addu()(ulong x, ulong y, ref bool overflow){ immutable ulong r = x + y; immutable bool o = r < x; assert(o == (r < y)); if (o) overflow = true; return r;} ///@betterCunittest{ bool overflow; assert(addu(2L, 3L, overflow) == 5); assert(!overflow); assert(addu(1, ulong.max - 1, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.min, -1L, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.max, 1, overflow) == ulong.min); assert(overflow); overflow = false; assert(addu(ulong.min + 1, -1L, overflow) == ulong.min); assert(overflow); assert(addu(0L, 0L, overflow) == 0); assert(overflow); // sticky} static if (is(ucent)){/// dittopragma(inline, true)ucent addu()(ucent x, ucent y, ref bool overflow){ immutable ucent r = x + y; immutable bool o = r < x; assert(o == (r < y)); if (o) overflow = true; return r;} unittest{ bool overflow; assert(addu(cast(ucent)2L, 3L, overflow) == 5); assert(!overflow); assert(addu(1, ucent.max - 1, overflow) == ucent.max); assert(!overflow); assert(addu(ucent.min, -1L, overflow) == ucent.max); assert(!overflow); assert(addu(ucent.max, 1, overflow) == ucent.min); assert(overflow); overflow = false; assert(addu(ucent.min + 1, -1L, overflow) == ucent.min); assert(overflow); assert(addu(cast(ucent)0L, 0L, overflow) == 0); assert(overflow); // sticky}} /******************************* * Subtract two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the difference */ pragma(inline, true)int subs()(int x, int y, ref bool overflow){ immutable long r = cast(long)x - cast(long)y; if (r < int.min || r > int.max) overflow = true; return cast(int)r;} ///@betterCunittest{ bool overflow; assert(subs(2, -3, overflow) == 5); assert(!overflow); assert(subs(1, -int.max + 1, overflow) == int.max); assert(!overflow); assert(subs(int.min + 1, 1, overflow) == int.min); assert(!overflow); assert(subs(int.max, -1, overflow) == int.min); assert(overflow); overflow = false; assert(subs(int.min, 1, overflow) == int.max); assert(overflow); assert(subs(0, 0, overflow) == 0); assert(overflow); // sticky} /// dittopragma(inline, true)long subs()(long x, long y, ref bool overflow){ immutable long r = cast(ulong)x - cast(ulong)y; if (x < 0 && y >= 0 && r >= 0 || x >= 0 && y < 0 && (r < 0 || y == long.min)) overflow = true; return r;} ///@betterCunittest{ bool overflow; assert(subs(2L, -3L, overflow) == 5); assert(!overflow); assert(subs(1L, -long.max + 1, overflow) == long.max); assert(!overflow); assert(subs(long.min + 1, 1, overflow) == long.min); assert(!overflow); assert(subs(-1L, long.min, overflow) == long.max); assert(!overflow); assert(subs(long.max, -1, overflow) == long.min); assert(overflow); overflow = false; assert(subs(long.min, 1, overflow) == long.max); assert(overflow); assert(subs(0L, 0L, overflow) == 0); assert(overflow); // sticky} static if (is(cent)){/// dittopragma(inline, true)cent subs()(cent x, cent y, ref bool overflow){ immutable cent r = cast(ucent)x - cast(ucent)y; if (x < 0 && y >= 0 && r >= 0 || x >= 0 && y < 0 && (r < 0 || y == long.min)) overflow = true; return r;} unittest{ bool overflow; assert(subs(cast(cent)2L, -3L, overflow) == 5); assert(!overflow); assert(subs(1L, -cent.max + 1, overflow) == cent.max); assert(!overflow); assert(subs(cent.min + 1, 1, overflow) == cent.min); assert(!overflow); assert(subs(-1L, cent.min, overflow) == cent.max); assert(!overflow); assert(subs(cent.max, -1, overflow) == cent.min); assert(overflow); overflow = false; assert(subs(cent.min, 1, overflow) == cent.max); assert(overflow); assert(subs(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky}} /******************************* * Subtract two unsigned integers, checking for overflow (aka borrow). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the difference */ pragma(inline, true)uint subu()(uint x, uint y, ref bool overflow){ if (x < y) overflow = true; return x - y;} ///@betterCunittest{ bool overflow; assert(subu(3, 2, overflow) == 1); assert(!overflow); assert(subu(uint.max, 1, overflow) == uint.max - 1); assert(!overflow); assert(subu(1, 1, overflow) == uint.min); assert(!overflow); assert(subu(0, 1, overflow) == uint.max); assert(overflow); overflow = false; assert(subu(uint.max - 1, uint.max, overflow) == uint.max); assert(overflow); assert(subu(0, 0, overflow) == 0); assert(overflow); // sticky} /// dittopragma(inline, true)ulong subu()(ulong x, ulong y, ref bool overflow){ if (x < y) overflow = true; return x - y;} ///@betterCunittest{ bool overflow; assert(subu(3UL, 2UL, overflow) == 1); assert(!overflow); assert(subu(ulong.max, 1, overflow) == ulong.max - 1); assert(!overflow); assert(subu(1UL, 1UL, overflow) == ulong.min); assert(!overflow); assert(subu(0UL, 1UL, overflow) == ulong.max); assert(overflow); overflow = false; assert(subu(ulong.max - 1, ulong.max, overflow) == ulong.max); assert(overflow); assert(subu(0UL, 0UL, overflow) == 0); assert(overflow); // sticky} static if (is(ucent)){/// dittopragma(inline, true)ucent subu()(ucent x, ucent y, ref bool overflow){ if (x < y) overflow = true; return x - y;} unittest{ bool overflow;Lines 1–500 of 943. Load more
/********************************************** * This module implements integral arithmetic primitives that check * for out-of-range results. * * Integral arithmetic operators operate on fixed width types. * Results that are not representable in those fixed widths are silently * truncated to fit. * This module offers integral arithmetic primitives that produce the * same results, but set an 'overflow' flag when such truncation occurs. * The setting is sticky, meaning that numerous operations can be cascaded * and then the flag need only be checked at the end. * Whether the operation is signed or unsigned is indicated by an 's' or 'u' * suffix, respectively. While this could be achieved without such suffixes by * using overloading on the signedness of the types, the suffix makes it clear * which is happening without needing to examine the types. * * While the generic versions of these functions are computationally expensive * relative to the cost of the operation itself, compiler implementations are free * to recognize them and generate equivalent and faster code. * * The functions here are templates so they can be used with -betterC, * as betterC does not link with this library. * * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks) * Copyright: Copyright (c) Walter Bright 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Walter Bright * Source: $(DRUNTIMESRC core/_checkedint.d) */ module core.checkedint; import core.internal.attributes : betterC; nothrow: @safe: @nogc: pure: /******************************* * Add two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the sum */ 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) overflow = true; return cast(int)r; } /// @betterC unittest { bool overflow; assert(adds(2, 3, overflow) == 5); assert(!overflow); assert(adds(1, int.max - 1, overflow) == int.max); assert(!overflow); assert(adds(int.min + 1, -1, overflow) == int.min); assert(!overflow); assert(adds(int.max, 1, overflow) == int.min); assert(overflow); overflow = false; assert(adds(int.min, -1, overflow) == int.max); assert(overflow); assert(adds(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto 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) overflow = true; return r; } /// @betterC unittest { bool overflow; assert(adds(2L, 3L, overflow) == 5); assert(!overflow); assert(adds(1L, long.max - 1, overflow) == long.max); assert(!overflow); assert(adds(long.min + 1, -1, overflow) == long.min); assert(!overflow); assert(adds(long.max, 1, overflow) == long.min); assert(overflow); overflow = false; assert(adds(long.min, -1, overflow) == long.max); assert(overflow); assert(adds(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(cent)) { /// ditto pragma(inline, true) cent adds()(cent x, cent y, ref bool overflow) { cent r = cast(ucent)x + cast(ucent)y; if (x < 0 && y < 0 && r >= 0 || x >= 0 && y >= 0 && r < 0) overflow = true; return r; } unittest { bool overflow; assert(adds(cast(cent)2L, 3L, overflow) == 5); assert(!overflow); assert(adds(1L, cent.max - 1, overflow) == cent.max); assert(!overflow); assert(adds(cent.min + 1, -1, overflow) == cent.min); assert(!overflow); assert(adds(cent.max, 1, overflow) == cent.min); assert(overflow); overflow = false; assert(adds(cent.min, -1, overflow) == cent.max); assert(overflow); assert(adds(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Add two unsigned integers, checking for overflow (aka carry). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the sum */ pragma(inline, true) uint addu()(uint x, uint y, ref bool overflow) { immutable uint r = x + y; immutable bool o = r < x; assert(o == (r < y)); if (o) overflow = true; return r; } /// @betterC unittest { for (uint i = 0; i < 10; ++i) { bool overflow; immutable uint r = addu (uint.max - i, uint.max - i, overflow); assert(r == 2 * (uint.max - i)); assert(overflow); } bool overflow; assert(addu(2, 3, overflow) == 5); assert(!overflow); assert(addu(1, uint.max - 1, overflow) == uint.max); assert(!overflow); assert(addu(uint.min, -1, overflow) == uint.max); assert(!overflow); assert(addu(uint.max, 1, overflow) == uint.min); assert(overflow); overflow = false; assert(addu(uint.min + 1, -1, overflow) == uint.min); assert(overflow); assert(addu(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) ulong addu()(ulong x, ulong y, ref bool overflow) { immutable ulong r = x + y; immutable bool o = r < x; assert(o == (r < y)); if (o) overflow = true; return r; } /// @betterC unittest { bool overflow; assert(addu(2L, 3L, overflow) == 5); assert(!overflow); assert(addu(1, ulong.max - 1, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.min, -1L, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.max, 1, overflow) == ulong.min); assert(overflow); overflow = false; assert(addu(ulong.min + 1, -1L, overflow) == ulong.min); assert(overflow); assert(addu(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(ucent)) { /// ditto pragma(inline, true) ucent addu()(ucent x, ucent y, ref bool overflow) { immutable ucent r = x + y; immutable bool o = r < x; assert(o == (r < y)); if (o) overflow = true; return r; } unittest { bool overflow; assert(addu(cast(ucent)2L, 3L, overflow) == 5); assert(!overflow); assert(addu(1, ucent.max - 1, overflow) == ucent.max); assert(!overflow); assert(addu(ucent.min, -1L, overflow) == ucent.max); assert(!overflow); assert(addu(ucent.max, 1, overflow) == ucent.min); assert(overflow); overflow = false; assert(addu(ucent.min + 1, -1L, overflow) == ucent.min); assert(overflow); assert(addu(cast(ucent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Subtract two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the difference */ pragma(inline, true) int subs()(int x, int y, ref bool overflow) { immutable long r = cast(long)x - cast(long)y; if (r < int.min || r > int.max) overflow = true; return cast(int)r; } /// @betterC unittest { bool overflow; assert(subs(2, -3, overflow) == 5); assert(!overflow); assert(subs(1, -int.max + 1, overflow) == int.max); assert(!overflow); assert(subs(int.min + 1, 1, overflow) == int.min); assert(!overflow); assert(subs(int.max, -1, overflow) == int.min); assert(overflow); overflow = false; assert(subs(int.min, 1, overflow) == int.max); assert(overflow); assert(subs(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) long subs()(long x, long y, ref bool overflow) { immutable long r = cast(ulong)x - cast(ulong)y; if (x < 0 && y >= 0 && r >= 0 || x >= 0 && y < 0 && (r < 0 || y == long.min)) overflow = true; return r; } /// @betterC unittest { bool overflow; assert(subs(2L, -3L, overflow) == 5); assert(!overflow); assert(subs(1L, -long.max + 1, overflow) == long.max); assert(!overflow); assert(subs(long.min + 1, 1, overflow) == long.min); assert(!overflow); assert(subs(-1L, long.min, overflow) == long.max); assert(!overflow); assert(subs(long.max, -1, overflow) == long.min); assert(overflow); overflow = false; assert(subs(long.min, 1, overflow) == long.max); assert(overflow); assert(subs(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(cent)) { /// ditto pragma(inline, true) cent subs()(cent x, cent y, ref bool overflow) { immutable cent r = cast(ucent)x - cast(ucent)y; if (x < 0 && y >= 0 && r >= 0 || x >= 0 && y < 0 && (r < 0 || y == long.min)) overflow = true; return r; } unittest { bool overflow; assert(subs(cast(cent)2L, -3L, overflow) == 5); assert(!overflow); assert(subs(1L, -cent.max + 1, overflow) == cent.max); assert(!overflow); assert(subs(cent.min + 1, 1, overflow) == cent.min); assert(!overflow); assert(subs(-1L, cent.min, overflow) == cent.max); assert(!overflow); assert(subs(cent.max, -1, overflow) == cent.min); assert(overflow); overflow = false; assert(subs(cent.min, 1, overflow) == cent.max); assert(overflow); assert(subs(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Subtract two unsigned integers, checking for overflow (aka borrow). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the difference */ pragma(inline, true) uint subu()(uint x, uint y, ref bool overflow) { if (x < y) overflow = true; return x - y; } /// @betterC unittest { bool overflow; assert(subu(3, 2, overflow) == 1); assert(!overflow); assert(subu(uint.max, 1, overflow) == uint.max - 1); assert(!overflow); assert(subu(1, 1, overflow) == uint.min); assert(!overflow); assert(subu(0, 1, overflow) == uint.max); assert(overflow); overflow = false; assert(subu(uint.max - 1, uint.max, overflow) == uint.max); assert(overflow); assert(subu(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) ulong subu()(ulong x, ulong y, ref bool overflow) { if (x < y) overflow = true; return x - y; } /// @betterC unittest { bool overflow; assert(subu(3UL, 2UL, overflow) == 1); assert(!overflow); assert(subu(ulong.max, 1, overflow) == ulong.max - 1); assert(!overflow); assert(subu(1UL, 1UL, overflow) == ulong.min); assert(!overflow); assert(subu(0UL, 1UL, overflow) == ulong.max); assert(overflow); overflow = false; assert(subu(ulong.max - 1, ulong.max, overflow) == ulong.max); assert(overflow); assert(subu(0UL, 0UL, overflow) == 0); assert(overflow); // sticky } static if (is(ucent)) { /// ditto pragma(inline, true) ucent subu()(ucent x, ucent y, ref bool overflow) { if (x < y) overflow = true; return x - y; } unittest { bool overflow;