safeOp.binary

Perform the binary (two-argument) integer operation specified by op.

  • Unsafe signed/unsigned operations will generate a compile-time error.
  • +, -, *, /, and % are checked for overflow at runtime.
  • / and % are also checked for divide-by-zero.
  • <<, >>, and >>> are checked to verify that right >= 0 and right < (8 * typeof(left).sizeof). Otherwise, IntFlag.undef is raised.


Note also:

  • The shift operators are not checked for overflow and should not be used for multiplication, division, or exponentiation. Instead, use mulPow2() and divPow2(), which internally use the bitshifts for speed, but check for overflow and correctly handle negative values.
  • Likewise, modPow2() should be used for remainders instead of &.
  • ^^ and ^^= will remain disabled in favour of pow until DMD issues 15288 and 15412 are fixed.


Like the standard equivalents, the assignment operators (+=, -=, *=, etc.) take left by ref and will overwrite it with the result of the operation.

  1. OpType!(N, op, M) binary(N left, M right)
  2. N binary(N left, M right)
    template safeOp(IntFlagPolicy policy)
    ref @safe
    N
    binary
    (
    string op
    N
    M
    )
    (
    return ref N left
    ,
    const M right
    )
    if (
    isIntegral!N &&
    &&
    (op[$ - 1] == '=')
    )

Examples

import checkedint.sticky : safeOp; // use IntFlagPolicy.sticky

assert(safeOp.binary!"+"(17, -5) == 12);
static assert(!__traits(compiles, safeOp.binary!"+"(-1, 1u)));

ulong a = 18_446_744_073_709_551_615uL;
safeOp.binary!"+="(a, 1u);
assert(IntFlags.local.clear() == IntFlag.posOver);

assert(safeOp.binary!"-"(17u, 5u) == 12u);
safeOp.binary!"-"(5u, 17u);
assert(IntFlags.local.clear() == IntFlag.negOver);

ulong b = 123_456_789_987_654_321uL;
static assert(!__traits(compiles, safeOp.binary!"-="(b, 987_654_321)));
assert(safeOp.binary!"-="(b, 987_654_321u) == 123_456_789_000_000_000uL);
assert(b == 123_456_789_000_000_000uL);

assert(safeOp.binary!"*"(-1 << 30, 2) == int.min);
safeOp.binary!"*"(1 << 30, 2);
assert(IntFlags.local.clear() == IntFlag.negOver);

uint c = 1u << 18;
assert(safeOp.binary!"*="(c, 1u << 4) == 1u << 22);
assert(c == 1u << 22);

assert(safeOp.binary!"/"(22, 11) == 2);
assert(!__traits(compiles, safeOp.binary!"/"(-22, 11u)));
safeOp.binary!"/"(0, 0);
assert(IntFlags.local.clear() == IntFlag.div0);

long j = long.min;
safeOp.binary!"/="(j, -1);
assert(IntFlags.local.clear() == IntFlag.posOver);

assert(safeOp.binary!"%"(20u, 7u) == 6u);
static assert(!__traits(compiles, safeOp.binary!"%"(20u, -7)));
safeOp.binary!"%"(20u, 0u);
assert(IntFlags.local.clear() == IntFlag.div0);

short n = 75;
assert(safeOp.binary!"%="(n, -10) == 5);
assert(n == 5);
import checkedint.sticky : safeOp; // use IntFlagPolicy.sticky

assert(safeOp.binary!"<<"(-0x80,  2) == -0x200);
safeOp.binary!"<<"(-0x80, -2);
assert(IntFlags.local.clear() == IntFlag.undef);

ubyte a = 0x3u;
safeOp.binary!"<<="(a, 7);
assert(a == 0x80u);

assert(safeOp.binary!">>"(-0xC, 5u) == -0x1);
safeOp.binary!">>"(-0xC, long.max);
assert(IntFlags.local.clear() == IntFlag.undef);

short b = 0x700;
assert(safeOp.binary!">>="(b, 8) == 0x7);
assert(b == 0x7);

assert(safeOp.binary!">>>"(-0x80, 2u) == 0x3FFF_FFE0);
safeOp.binary!">>>"(-0x80, 32);
assert(IntFlags.local.clear() == IntFlag.undef);

int c = 0xFE_DCBA;
assert(safeOp.binary!">>>="(c, 12) == 0xFED);
assert(c == 0xFED);

assert(safeOp.binary!"&"(0x6Fu, 0x4076)  == 0x66u);

ubyte d = 0x6Fu;
assert(safeOp.binary!"&="(d, 0x4076) == 0x66u);
assert(d == 0x66u);

assert(safeOp.binary!"|"(0x6F, 0x4076u) == 0x407Fu);

byte e = 0x6F;
assert(safeOp.binary!"|="(e, 0x4076u) == 0x7F);
assert(e == 0x7F);

assert(safeOp.binary!"^"(0x6F, 0x4076) == 0x4019);

int f = 0x6F;
assert(safeOp.binary!"^="(f, 0x4076) == 0x4019);
assert(f == 0x4019);

assert(!IntFlags.local);

Meta