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.

Outside of generic code that needs to work with both SafeInt!N and N, it is generally preferable to use 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)
  2. template SafeInt(N, IntFlagPolicy policy, Flag!"bitOps" bitOps = Yes.bitOps)

Constructors

this
this(const 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(const M exp)
auto divPow2(const M exp)
ilogb
SafeInt!(int, policy, bitOps) ilogb()
modPow2
auto modPow2(const M exp)
auto modPow2(const M exp)
mulPow2
auto mulPow2(const M exp)
auto mulPow2(const M exp)

See safeOp.

opAssign
typeof(this) opAssign(const M that)

Assign the value of that to this SafeInt instance.

opBinary
M opBinary(const M right)

Perform a floating-point math operation.

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

See safeOp.

opBinaryRight
M opBinaryRight(const M left)

Perform a floating-point math operation.

opBinaryRight
SafeInt!(OpType!(M, op, N), policy, bitOps) opBinaryRight(const 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(const M right)

Perform a floating-point comparison to right.

opCmp
int opCmp(const M right)

See safeOp.

opEquals
bool opEquals(const M right)
opOpAssign
typeof(this) opOpAssign(const M right)
opUnary
typeof(this) 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(const 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(const M exp)

See safeOp.

toHash
size_t toHash()

Get a simple hashcode for this value.

toString
string toString()

Get a string representation of this value.

toString
void toString(Writer w, FormatSpec!Char fmt = (FormatSpec!Char).init)

Puts a string representation of this value into w. This overload will not allocate, unless std.range.primitives.put(w, ...) allocates.

Properties

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

Get a view of this SafeInt that allows bitwise operations.

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.

Variables

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

1 // Mixing standard signed and unsigned types is dangerous...
2 int ba = -1;
3 uint bb = 0;
4 assert(ba > bb);
5 
6 auto bc = ba + bb;
7 assert(is(typeof(bc) == uint));
8 assert(bc == 4294967295u);
9 
10 // ...that's why SafeInt doesn't allow it.
11 import checkedint.throws : SafeInt, to; // use IntFlagPolicy.throws
12 
13 SafeInt!int sa = -1;
14 SafeInt!uint sb = 0u;
15 static assert(!__traits(compiles, sa < sb));
16 static assert(!__traits(compiles, sa + sb));
17 
18 // Instead, use checkedint.to() to safely convert to a common type...
19 auto sbi = to!(SafeInt!int)(sb);
20 assert(sa < sbi);
21 auto sc = sa + sbi;
22 assert(sc == -1);
23 // (...or just switch to SmartInt.)
1 // When IntFlagPolicy.throws is set, SafeInt operations that fail at runtime will throw a CheckedIntException.
2 import checkedint.throws : SafeInt;
3 
4 SafeInt!uint sa = 1u;
5 SafeInt!uint sb = 0u;
6 
7 bool overflow = false;
8 try
9 {
10     SafeInt!uint sc = sb - sa;
11     assert(false);
12 }
13 catch (CheckedIntException e)
14 {
15     assert(e.intFlags == IntFlag.negOver);
16     overflow = true;
17 }
18 assert(overflow);
19 
20 bool div0 = false;
21 try
22 {
23     // With standard integers, this would crash the program with an unrecoverable FPE...
24     SafeInt!uint sc = sa / sb;
25     assert(false);
26 }
27 catch (CheckedIntException e)
28 {
29     // ...but with SafeInt, it just throws a normal Exception.
30     assert(e.intFlags == IntFlag.div0);
31     div0 = true;
32 }
33 assert(div0);
1 // When IntFlagPolicy.sticky is set, SafeInt operations that fail at runtime set one or more bits in IntFlags.local.
2 import checkedint.sticky : SafeInt;
3 
4 SafeInt!uint sa = 1u;
5 SafeInt!uint sb = 0u;
6 SafeInt!uint sc;
7 
8 sc = sb - sa;
9 assert(IntFlags.local == IntFlag.negOver);
10 
11 // With standard integers, this would crash the program with an unrecoverable FPE...
12 sc = sa / sb;
13 // ...but with SmartInt, it just sets a bit in IntFlags.local.
14 assert(IntFlags.local & IntFlag.div0);
15 
16 // Each flag will remain set until cleared:
17 assert(IntFlags.local.clear() == (IntFlag.negOver | IntFlag.div0));
18 assert(!IntFlags.local);

Meta