SafeInt

Wrapper for any basic integral type N that uses the checked operations from safeOp and rejects attempts to directly assign values that cannot be proven to be within the range representable by N. (checkedint.to() can be used to safely assign values of incompatible types, with runtime bounds checking.)

SafeInt is designed to be as interchangeable with N as possible, without compromising safety. The DebugInt template allows a variable to use SafeInt in debug mode to find bugs, and N directly in release mode for greater speed and a smaller binary.

If you're not trying to write generic code that works with both SafeInt!N and N, you should probably be using SmartInt instead. It generates far fewer error messages; mostly it "just works".

  • policy controls the error signalling policy (see checkedint.flags).
  • bitOps may be set to No.bitOps if desired, to turn bitwise operations on this type into a compile-time error.
  1. struct SafeInt(N, IntFlagPolicy _policy, Flag!"bitOps" bitOps = Yes.bitOps)
    @safe
    struct SafeInt (
    N
    IntFlagPolicy _policy
    Flag!"bitOps" bitOps = Yes.bitOps
    ) if (
    isIntegral!N &&
    isUnqual!N
    ) {}
  2. template SafeInt(N, IntFlagPolicy policy, Flag!"bitOps" bitOps = Yes.bitOps)

Constructors

this
this(M that)

Assign the value of that to this SafeInt instance.

Members

Functions

abs
typeof(this) abs()

See safeOp.

bsf
SafeInt!(int, policy, bitOps) bsf()
bsr
SafeInt!(int, policy, bitOps) bsr()
divPow2
auto divPow2(M exp)
ilogb
SafeInt!(int, policy, bitOps) ilogb()
modPow2
auto modPow2(M exp)
mulPow2
auto mulPow2(M exp)

See safeOp.

opAssign
typeof(this) opAssign(M that)

Assign the value of that to this SafeInt instance.

opBinary
M opBinary(M right)

Perform a floating-point math operation.

opBinary
SafeInt!(OpType!(N, op, BasicScalar!M), .max(policy, intFlagPolicyOf!M), bitOps && hasBitOps!M) opBinary(M right)

See safeOp.

opBinaryRight
M opBinaryRight(M left)

Perform a floating-point math operation.

opBinaryRight
SafeInt!(OpType!(M, op, N), policy, bitOps) opBinaryRight(M left)

See safeOp.

opCast
M opCast()

Convert this value to floating-point. This always succeeds, although some loss of precision may occur if M.sizeof <= N.sizeof.

opCast
M opCast()

this != 0

opCast
M opCast()

Convert this value to type M using checkedint.to() for bounds checking. An IntFlag will be raised if M cannot represent the current value of this SafeInt.

opCmp
auto opCmp(M right)

Perform a floating-point comparison to right.

opCmp
int opCmp(M right)

See safeOp.

opEquals
bool opEquals(M right)
opOpAssign
typeof(this) opOpAssign(M right)
opUnary
typeof(this) opUnary()

See safeOp.

popcnt
SafeInt!(int, policy, bitOps) popcnt()

Count the number of set bits using core.bitop.popcnt().

pow
M pow(M exp)

Raise this to the exp power using std.math.pow().

pow
SafeInt!(CallType!(std.math.pow, N, BasicScalar!M), .max(policy, intFlagPolicyOf!M), bitOps && hasBitOps!M) pow(M exp)

See safeOp.

toHash
size_t toHash()

Get a simple hashcode for this value.

toString
void toString(Writer sink, FormatSpec!Char fmt)
string toString()

Get a string representation of this value.

Properties

bits
inout(SafeInt!(N, policy, Yes.bitOps)) bits [@property getter]

Get a view of this SafeInt that allows bitwise operations.

bscal
inout(N) bscal [@property getter]
Undocumented in source. Be warned that the author may not have intended to support it.
idx
Select!(isSigned!N, ptrdiff_t, size_t) idx [@property getter]

Convert this value to a type suitable for indexing an array:

  • If N is signed, a ptrdiff_t is returned.
  • If N is unsigned, a size_t is returned.

checkedint.to() is used for bounds checking.

max
auto max [@property getter]
Undocumented in source. Be warned that the author may not have intended to support it.
min
auto min [@property getter]
Undocumented in source. Be warned that the author may not have intended to support it.

Variables

bits
SafeInt!(N, policy, Yes.bitOps) bits;
Undocumented in source.
bscal
N bscal;

The basic integral value of this SafeInt. Accessing this directly may be useful for:

  • Intentionally doing modular (unchecked) arithmetic, or
  • Interacting with APIs that are not checkedint aware.
max
enum SafeInt!(N, policy, bitOps) max;

The most positive possible value of this SafeInt type.

min
enum SafeInt!(N, policy, bitOps) min;

The most negative possible value of this SafeInt type.

policy
enum IntFlagPolicy policy;

The error signalling policy used by this SafeInt type.

Examples

// Mixing standard signed and unsigned types is dangerous...
int ba = -1;
uint bb = 0;
assert(ba > bb);

auto bc = ba + bb;
assert(is(typeof(bc) == uint));
assert(bc == 4294967295u);

// ...that's why SafeInt won't let you do it.
import checkedint.throws : SafeInt, to; // use IntFlagPolicy.throws

SafeInt!int sa = -1;
SafeInt!uint sb = 0u;
static assert(!__traits(compiles, sa < sb));
static assert(!__traits(compiles, sa + sb));

// Instead, use checkedint.to() to safely convert to a common type...
auto sbi = to!(SafeInt!int)(sb);
assert(sa < sbi);
auto sc = sa + sbi;
assert(sc == -1);
// (...or just switch to SmartInt.)
// When IntFlagPolicy.throws is set, SafeInt operations that fail at runtime will throw a CheckedIntException.
import checkedint.throws : SafeInt;

SafeInt!uint sa = 1u;
SafeInt!uint sb = 0u;

bool overflow = false;
try
{
    SafeInt!uint sc = sb - sa;
    assert(false);
}
catch(CheckedIntException e)
{
    assert(e.intFlags == IntFlag.negOver);
    overflow = true;
}
assert(overflow);

bool div0 = false;
try
{
    // With standard integers, this would crash the program with an unrecoverable FPE...
    SafeInt!uint sc = sa / sb;
    assert(false);
}
catch(CheckedIntException e)
{
    // ...but with SafeInt, it just throws a normal Exception.
    assert(e.intFlags == IntFlag.div0);
    div0 = true;
}
assert(div0);
// When IntFlagPolicy.noex is set, SafeInt operations that fail at runtime set one or more bits in IntFlags.local.
import checkedint.noex : SafeInt;

SafeInt!uint sa = 1u;
SafeInt!uint sb = 0u;
SafeInt!uint sc;

sc = sb - sa;
assert(IntFlags.local == IntFlag.negOver);

// With standard integers, this would crash the program with an unrecoverable FPE...
sc = sa / sb;
// ...but with SmartInt, it just sets a bit in IntFlags.local.
assert(IntFlags.local & IntFlag.div0);

// Each flag will remain set until cleared:
assert(IntFlags.local.clear() == (IntFlag.negOver | IntFlag.div0));
assert(!IntFlags.local);

Meta