On this page
std.experimental.checkedint
This module defines facilities for efficient checking of integral operations against overflow, casting with loss of precision, unexpected change of sign, etc. The checking (and possibly correction) can be done at operation level, for example opChecked
!"+"(x, y, overflow)
adds two integrals x
and y
and sets overflow
to true
if an overflow occurred. The flag overflow
(a bool
passed by reference) is not touched if the operation succeeded, so the same flag can be reused for a sequence of operations and tested at the end.
Issuing individual checked operations is flexible and efficient but often tedious. The Checked
facility offers encapsulated integral wrappers that do all checking internally and have configurable behavior upon erroneous results. For example, Checked!int
is a type that behaves like int
but aborts execution immediately whenever involved in an operation that produces the arithmetically wrong result. The accompanying convenience function checked
uses type deduction to convert a value x
of integral type T
to Checked!T
by means of checked(x)
. For example:
void main()
{
import std.experimental.checkedint, std.stdio;
writeln((checked(5) + 7).get); // 12
writeln((checked(10) * 1000 * 1000 * 1000).get); // Overflow
}
Similarly,
checked(1) > uint(0)
aborts execution (even though the builtin comparison int(1) > uint(0)
is surprisingly true due to language's conversion rules modeled after C). Thus, Checked!int
is a virtually dropin replacement for int
useable in debug builds, to be replaced by int
in release mode if efficiency demands it. Checked
has customizable behavior with the help of a second type parameter, Hook
. Depending on what methods Hook
defines, core operations on the underlying integral may be verified for overflow or completely redefined. If Hook
defines no method at all and carries no state, there is no change in behavior, i.e. Checked!(int, void)
is a wrapper around int
that adds no customization at all. This module provides a few predefined hooks (below) that add useful behavior to
Checked
: Abort 
fails every incorrect operation with a message to std.stdio. stderr followed by a call to assert(0) . It is the default second parameter, i.e. Checked!short is the same as Checked!(short, Abort) . 
Throw 
fails every incorrect operation by throwing an exception. 
Warn 
prints incorrect operations to std.stdio.stderr but otherwise preserves the builtin behavior. 
ProperCompare 
fixes the comparison operators == , != , < , <= , > , and >= to return correct results in all circumstances, at a slight cost in efficiency. For example, Checked!(uint, ProperCompare)(1) > 1 is true , which is not the case for the builtin comparison. Also, comparing numbers for equality with floatingpoint numbers only passes if the integral can be converted to the floatingpoint number precisely, so as to preserve transitivity of equality. 
WithNaN 
reserves a special "Not a Number" (NaN) value akin to the homonym value reserved for floatingpoint values. Once a Checked!(X, WithNaN) gets this special value, it preserves and propagates it until reassigned. isNaN can be used to query whether the object is not a number. 
Saturate 
implements saturating arithmetic, i.e. Checked!(int, Saturate) "stops" at int.max for all operations that would cause an int to overflow toward infinity, and at int.min for all operations that would correspondingly overflow toward negative infinity. 
These policies may be used alone, e.g.
Checked!(uint, WithNaN)
defines a uint
like type that reaches a stable NaN state for all erroneous operations. They may also be "stacked" on top of each other, owing to the property that a checked integral emulates an actual integral, which means another checked integral can be built on top of it. Some combinations of interest include: Checked!(Checked!int, ProperCompare) 
defines an int with fixed comparison operators that will fail with assert(0) upon overflow. (Recall that Abort is the default policy.) The order in which policies are combined is important because the outermost policy (ProperCompare in this case) has the first crack at intercepting an operator. The converse combination Checked!(Checked!(int, ProperCompare)) is meaningless because Abort will intercept comparison and will fail without giving ProperCompare a chance to intervene. 
Checked!(Checked!(int, ProperCompare), WithNaN) 
defines an int like type that supports a NaN value. For values that are not NaN, comparison works properly. Again the composition order is important; Checked!(Checked!(int, WithNaN), ProperCompare) does not have good semantics because ProperCompare intercepts comparisons before the numbers involved are tested for NaN. 
The hook's members are looked up statically in a Design by Introspection manner and are all optional. The table below illustrates the members that a hook type may define and their influence over the behavior of the
Checked
type using it. In the table, hook
is an alias for Hook
if the type Hook
does not introduce any state, or an object of type Hook
otherwise. Hook member 
Semantics in Checked!(T, Hook) 

defaultValue 
If defined, Hook.defaultValue!T is used as the default initializer of the payload. 
min 
If defined, Hook.min!T is used as the minimum value of the payload. 
max 
If defined, Hook.max!T is used as the maximum value of the payload. 
hookOpCast 
If defined, hook.hookOpCast!U(get) is forwarded to unconditionally when the payload is to be cast to type U . 
onBadCast 
If defined and hookOpCast is not defined, onBadCast!U(get) is forwarded to when the payload is to be cast to type U and the cast would lose information or force a change of sign. 
hookOpEquals 
If defined, hook.hookOpEquals(get, rhs) is forwarded to unconditionally when the payload is compared for equality against value rhs of integral, floating point, or Boolean type. 
hookOpCmp 
If defined, hook.hookOpCmp(get, rhs) is forwarded to unconditionally when the payload is compared for ordering against value rhs of integral, floating point, or Boolean type. 
hookOpUnary 
If defined, hook.hookOpUnary!op(get) (where op is the operator symbol) is forwarded to for unary operators  and ~ . In addition, for unary operators ++ and  , hook.hookOpUnary!op(payload) is called, where payload is a reference to the value wrapped by Checked so the hook can change it. 
hookOpBinary 
If defined, hook.hookOpBinary!op(get, rhs) (where op is the operator symbol and rhs is the righthand side operand) is forwarded to unconditionally for binary operators + ,  , * , / , % , ^^ , & ,  , ^ , << , >> , and >>> . 
hookOpBinaryRight 
If defined, hook.hookOpBinaryRight!op(lhs, get) (where op is the operator symbol and lhs is the lefthand side operand) is forwarded to unconditionally for binary operators + ,  , * , / , % , ^^ , & ,  , ^ , << , >> , and >>> . 
onOverflow 
If defined, hook.onOverflow!op(get) is forwarded to for unary operators that overflow but only if hookOpUnary is not defined. Unary ~ does not overflow; unary  overflows only when the most negative value of a signed type is negated, and the result of the hook call is returned. When the increment or decrement operators overflow, the payload is assigned the result of hook.onOverflow!op(get) . When a binary operator overflows, the result of hook.onOverflow!op(get, rhs) is returned, but only if Hook does not define hookOpBinary . 
hookOpOpAssign 
If defined, hook.hookOpOpAssign!op(payload, rhs) (where op is the operator symbol and rhs is the righthand side operand) is forwarded to unconditionally for binary operators += , = , *= , /= , %= , ^^= , &= , = , ^= , <<= , >>= , and >>>= . 
onLowerBound 
If defined, hook.onLowerBound(value, bound) (where value is the value being assigned) is forwarded to when the result of binary operators += , = , *= , /= , %= , ^^= , &= , = , ^= , <<= , >>= , and >>>= is smaller than the smallest value representable by T . 
onUpperBound 
If defined, hook.onUpperBound(value, bound) (where value is the value being assigned) is forwarded to when the result of binary operators += , = , *= , /= , %= , ^^= , &= , = , ^= , <<= , >>= , and >>>= is larger than the largest value representable by T . 
hookToHash 
If defined, hook.hookToHash(payload) (where payload is a reference to the value wrapped by Checked) is forwarded to when toHash is called on a Checked type. Custom hashing can be implemented in a Hook , otherwise the builtin hashing is used. 
 Examples:

int[] concatAndAdd(int[] a, int[] b, int offset) { // Aborts on overflow on size computation auto r = new int[(checked(a.length) + b.length).get]; // Aborts on overflow on element computation foreach (i; 0 .. a.length) r[i] = (a[i] + checked(offset)).get; foreach (i; 0 .. b.length) r[i + a.length] = (b[i] + checked(offset)).get; return r; } writeln(concatAndAdd([1, 2, 3], [4, 5], 1)); // [0, 1, 2, 3, 4]
 Examples:
Saturate
stops at an overflowauto x = (cast(byte) 127).checked!Saturate; writeln(x); // 127 x++; writeln(x); // 127
 Examples:
WithNaN
has a special "Not a Number" (NaN) value akin to the homonym value reserved for floatingpoint valuesauto x = 100.checked!WithNaN; writeln(x); // 100 x /= 0; assert(x.isNaN);
 Examples:
ProperCompare
fixes the comparison operators ==, !=, <, <=, >, and >= to return correct resultsuint x = 1; auto y = x.checked!ProperCompare; assert(x < 1); // builtin comparison assert(y > 1); // ProperCompare
 Examples:
Throw
fails every incorrect operation by throwing an exceptionimport std.exception : assertThrown; auto x = 1.checked!Throw; assertThrown(x / 0); assertThrown(x + int.min); assertThrown(x == uint.max);
 struct Checked(T, Hook = Abort) if (isIntegral!T  is(T == Checked!(U, H), U, H));

Checked integral type wraps an integral
T
and customizes its behavior with the help of aHook
type. The type wrapped must be one of the predefined integrals (unqualified), or another instance ofChecked
. alias Representation = T;

The type of the integral subject to checking.
 Hook hook;

hook
is a member variable if it has state, or an alias forHook
otherwise.  inout auto get();

Returns a copy of the underlying value.
 Examples:

auto x = checked(ubyte(42)); static assert(is(typeof(x.get()) == ubyte)); writeln(x.get); // 42 const y = checked(ubyte(42)); static assert(is(typeof(y.get()) == const ubyte)); writeln(y.get); // 42

enum Checked!(T, Hook) min;
enum Checked!(T, Hook) max; 
Defines the minimum and maximum. These values are hookable by defining
Hook.min
and/orHook.max
. Examples:

Defines the minimum and maximum. These values are hookable by defining
Hook.min
and/orHook.max
.writeln(Checked!short.min); // 32768 writeln(Checked!(short, WithNaN).min); // 32767 writeln(Checked!(uint, WithNaN).max); // uint.max  1

this(U)(U rhs)
Constraints: if (valueConvertible!(U, T)  !isIntegral!T && is(typeof(T(rhs)))  is(U == Checked!(V, W), V, W) && is(typeof(Checked!(T, Hook)(rhs.get)))); 
Constructor taking a value properly convertible to the underlying type.
U
may be either an integral that can be converted toT
without a loss, or anotherChecked
instance whose representation may be in turn converted toT
without a loss. Examples:

auto a = checked(42L); writeln(a); // 42 auto b = Checked!long(4242); // convert 4242 to long writeln(b); // 4242

ref Checked opAssign(U)(U rhs) return
Constraints: if (is(typeof(Checked!(T, Hook)(rhs)))); 
Assignment operator. Has the same constraints as the constructor.
 Examples:

Checked!long a; a = 42L; writeln(a); // 42 a = 4242; writeln(a); // 4242
 Examples:

Checked!long a, b; a = b = 3; assert(a == 3 && b == 3);

U opCast(U, this _)()
Constraints: if (isIntegral!U  isFloatingPoint!U  is(U == bool)); 
Casting operator to integral,
bool
, or floating point type. IfHook
defineshookOpCast
, the call immediately returnshook.hookOpCast!U(get)
. Otherwise, casting tobool
yieldsget != 0
and casting to another integral that can represent all values ofT
returnsget
promoted toU
.If a cast to a floatingpoint type is requested and
Hook
definesonBadCast
, the cast is verified by ensuringget == cast(T) U(get)
. If that is nottrue
,hook.onBadCast!U(get)
is returned.
If a cast to an integral type is requested andHook
definesonBadCast
, the cast is verified by ensuringget
andcast(U) get
are the same arithmetic number. (Note thatint(1)
anduint(1)
are different values arithmetically although they have the same bitwise representation and compare equal by language rules.) If the numbers are not arithmetically equal,hook.onBadCast!U(get)
is returned. Examples:

writeln(cast(uint)checked(42)); // 42 writeln(cast(uint)checked!WithNaN(42)); // uint.max

bool opEquals(U, this _)(U rhs)
Constraints: if (isIntegral!U  isFloatingPoint!U  is(U == bool)  is(U == Checked!(V, W), V, W) && is(typeof(this == rhs.payload))); 
Compares
this
againstrhs
for equality. IfHook
defineshookOpEquals
, the function forwards tohook.hookOpEquals(get, rhs)
. Otherwise, the result of the builtin operationget == rhs
is returned.If
U
is also an instance ofChecked
, both hooks (left and righthand side) are introspected for the methodhookOpEquals
. If both define it, priority is given to the lefthand side. Examples:

import std.traits : isUnsigned; static struct MyHook { static bool thereWereErrors; static bool hookOpEquals(L, R)(L lhs, R rhs) { if (lhs != rhs) return false; static if (isUnsigned!L && !isUnsigned!R) { if (lhs > 0 && rhs < 0) thereWereErrors = true; } else static if (isUnsigned!R && !isUnsigned!L) if (lhs < 0 && rhs > 0) thereWereErrors = true; // Preserve builtin behavior. return true; } } auto a = checked!MyHook(42); writeln(a); // uint(42) assert(MyHook.thereWereErrors); MyHook.thereWereErrors = false; writeln(checked!MyHook(uint(42))); // 42 assert(MyHook.thereWereErrors); static struct MyHook2 { static bool hookOpEquals(L, R)(L lhs, R rhs) { return lhs == rhs; } } MyHook.thereWereErrors = false; writeln(checked!MyHook2(uint(42))); // a // Hook on left hand side takes precedence, so no errors assert(!MyHook.thereWereErrors);
 const nothrow @safe size_t toHash();

Generates a hash for
this
. IfHook
defineshookToHash
, the call immediately returnshook.hookToHash(payload)
. IfHook
does not implementhookToHash
, but it has state, a hash will be generated for theHook
using the builtin function and it will be xored with the hash of thepayload
. 
auto opCmp(U, this _)(const U rhs)
Constraints: if (isIntegral!U  isFloatingPoint!U  is(U == bool));
auto opCmp(U, Hook1, this _)(Checked!(U, Hook1) rhs); 
Compares
this
againstrhs
for ordering. IfHook
defineshookOpCmp
, the function forwards tohook.hookOpCmp(get, rhs)
. Otherwise, the result of the builtin comparison operation is returned.If
U
is also an instance ofChecked
, both hooks (left and righthand side) are introspected for the methodhookOpCmp
. If both define it, priority is given to the lefthand side. Examples:

import std.traits : isUnsigned; static struct MyHook { static bool thereWereErrors; static int hookOpCmp(L, R)(L lhs, R rhs) { static if (isUnsigned!L && !isUnsigned!R) { if (rhs < 0 && rhs >= lhs) thereWereErrors = true; } else static if (isUnsigned!R && !isUnsigned!L) { if (lhs < 0 && lhs >= rhs) thereWereErrors = true; } // Preserve builtin behavior. return lhs < rhs ? 1 : lhs > rhs; } } auto a = checked!MyHook(42); assert(a > uint(42)); assert(MyHook.thereWereErrors); static struct MyHook2 { static int hookOpCmp(L, R)(L lhs, R rhs) { // Default behavior return lhs < rhs ? 1 : lhs > rhs; } } MyHook.thereWereErrors = false; assert(Checked!(uint, MyHook2)(uint(42)) <= a); //assert(Checked!(uint, MyHook2)(uint(42)) >= a); // Hook on left hand side takes precedence, so no errors assert(!MyHook.thereWereErrors); assert(a <= Checked!(uint, MyHook2)(uint(42))); assert(MyHook.thereWereErrors);

auto opUnary(string op, this _)()
Constraints: if (op == "+"  op == ""  op == "~");
ref Checked opUnary(string op)() return
Constraints: if (op == "++"  op == ""); 
Defines unary operators
+
,
,~
,++
, and
. Unary+
is not overridable and always has builtin behavior (returnsthis
). For the others, ifHook
defineshookOpUnary
,opUnary
forwards toChecked!(typeof(hook.hookOpUnary!op(get)), Hook)(hook.hookOpUnary!op(get))
.If
Hook
does not definehookOpUnary
but definesonOverflow
,opUnary
forwards tohook.onOverflow!op(get)
in case an overflow occurs. For++
and
, the payload is assigned from the result of the call toonOverflow
.
Note that unary
is considered to overflow ifT
is a signed integral of 32 or 64 bits and is equal to the most negative value. This is because that value has no positive negation. Examples:

static struct MyHook { static bool thereWereErrors; static L hookOpUnary(string x, L)(L lhs) { if (x == "" && lhs == lhs) thereWereErrors = true; return lhs; } } auto a = checked!MyHook(long.min); writeln(a); // a assert(MyHook.thereWereErrors); auto b = checked!void(42); writeln(++b); // 43

auto opBinary(string op, Rhs)(const Rhs rhs)
Constraints: if (isIntegral!Rhs  isFloatingPoint!Rhs  is(Rhs == bool));
const auto opBinary(string op, Rhs)(const Rhs rhs)
Constraints: if (isIntegral!Rhs  isFloatingPoint!Rhs  is(Rhs == bool));
auto opBinary(string op, U, Hook1)(Checked!(U, Hook1) rhs);
const auto opBinary(string op, U, Hook1)(Checked!(U, Hook1) rhs); 
Defines binary operators
+
,
,*
,/
,%
,^^
,&
,
,^
,<<
,>>
, and>>>
. IfHook
defineshookOpBinary
,opBinary
forwards toChecked!(typeof(hook.hookOpBinary!op(get, rhs)), Hook)(hook.hookOpBinary!op(get, rhs))
.If
Hook
does not definehookOpBinary
but definesonOverflow
,opBinary
forwards tohook.onOverflow!op(get, rhs)
in case an overflow occurs.
If twoChecked
instances are involved in a binary operation and both definehookOpBinary
, the lefthand side hook has priority. If both defineonOverflow
, a compiletime error occurs. 
auto opBinaryRight(string op, Lhs)(const Lhs lhs)
Constraints: if (isIntegral!Lhs  isFloatingPoint!Lhs  is(Lhs == bool));
const auto opBinaryRight(string op, Lhs)(const Lhs lhs)
Constraints: if (isIntegral!Lhs  isFloatingPoint!Lhs  is(Lhs == bool)); 
Defines binary operators
+
,
,*
,/
,%
,^^
,&
,
,^
,<<
,>>
, and>>>
for the case when a builtin numeric or Boolean type is on the lefthand side, and aChecked
instance is on the righthand side. 
ref Checked opOpAssign(string op, Rhs)(const Rhs rhs) return
Constraints: if (isIntegral!Rhs  isFloatingPoint!Rhs  is(Rhs == bool));
ref Checked opOpAssign(string op, Rhs)(const Rhs rhs) return
Constraints: if (is(Rhs == Checked!(RhsT, RhsHook), RhsT, RhsHook)); 
Defines operators
+=
,=
,*=
,/=
,%=
,^^=
,&=
,=
,^=
,<<=
,>>=
, and>>>=
.If
Hook
defineshookOpOpAssign
,opOpAssign
forwards tohook.hookOpOpAssign!op(payload, rhs)
, wherepayload
is a reference to the internally held data so the hook can change it.
Otherwise, the operator first evaluatesauto result = opBinary!op(payload, rhs).payload
, which is subject to the hooks inopBinary
. Then, ifresult
is less thanChecked!(T, Hook).min
and ifHook
definesonLowerBound
, the payload is assigned fromhook.onLowerBound(result, min)
. Ifresult
is greater thanChecked!(T, Hook).max
and ifHook
definesonUpperBound
, the payload is assigned fromhook.onUpperBound(result, min)
.
If the righthand side is also a Checked but with a different hook or underlying type, the hook and underlying type of this Checked takes precedence.
In all other cases, the builtin behavior is carried out. Parameters:

op The operator involved (without the "="
, e.g."+"
for"+="
etc)Rhs rhs
The righthand side of the operator (lefthand side is this
)
 Returns:

A reference to
this
.
 Examples:

static struct MyHook { static bool thereWereErrors; static T onLowerBound(Rhs, T)(Rhs rhs, T bound) { thereWereErrors = true; return bound; } static T onUpperBound(Rhs, T)(Rhs rhs, T bound) { thereWereErrors = true; return bound; } } auto x = checked!MyHook(byte.min); x = 1; assert(MyHook.thereWereErrors); MyHook.thereWereErrors = false; x = byte.max; x += 1; assert(MyHook.thereWereErrors);

Checked!(T, Hook) checked(Hook = Abort, T)(const T value)
Constraints: if (is(typeof(Checked!(T, Hook)(value)))); 
Convenience function that turns an integral into the corresponding
Checked
instance by using template argument deduction. The hook type may be specified (by defaultAbort
). Examples:

static assert(is(typeof(checked(42)) == Checked!int)); writeln(checked(42)); // Checked!int(42) static assert(is(typeof(checked!WithNaN(42)) == Checked!(int, WithNaN))); writeln(checked!WithNaN(42)); // Checked!(int, WithNaN)(42)
 struct Abort;

Force all integral errors to fail by printing an error message to
stderr
and then abort the program.Abort
is the default second argument forChecked
. Dst onBadCast(Dst, Src)(Src src);

Called automatically upon a bad cast (one that loses precision or attempts to convert a negative value to an unsigned type). The source type is
Src
and the destination type isDst
. Parameters:

Src src
The source of the cast
 Returns:

Nominally the result is the desired value of the cast operation, which will be forwarded as the result of the cast. For
Abort
, the function never returns because it aborts the program.

T onLowerBound(Rhs, T)(Rhs rhs, T bound);
T onUpperBound(Rhs, T)(Rhs rhs, T bound); 
Called automatically upon a bounds error.
 Parameters:

Rhs rhs
The righthand side value in the assignment, after the operator has been evaluated T bound
The value of the bound being violated
 Returns:

Nominally the result is the desired value of the operator, which will be forwarded as result. For
Abort
, the function never returns because it aborts the program.
 bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs);

Called automatically upon a comparison for equality. In case of a erroneous comparison (one that would make a signed negative value appear equal to an unsigned positive value), this hook issues
assert(0)
which terminates the application. Parameters:

Lhs lhs
The first argument of Checked
, e.g.int
if the lefthand side of the operator isChecked!int
Rhs rhs
The righthand side type involved in the operator
 Returns:
 Upon a correct comparison, returns the result of the comparison. Otherwise, the function terminates the application so it never returns.
 int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs);

Called automatically upon a comparison for ordering using one of the operators
<
,<=
,>
, or>=
. In case the comparison is erroneous (i.e. it would make a signed negative value appear greater than or equal to an unsigned positive value), then application is terminated withassert(0)
. Otherwise, the threestate result is returned (positive iflhs > rhs
, negative iflhs < rhs
,0
otherwise). Parameters:

Lhs lhs
The first argument of Checked
, e.g.int
if the lefthand side of the operator isChecked!int
Rhs rhs
The righthand side type involved in the operator
 Returns:

For correct comparisons, returns a positive integer if
lhs > rhs
, a negative integer iflhs < rhs
,0
if the two are equal. Upon a mistaken comparison such asint(1) < uint(0)
, the function never returns because it aborts the program.

typeof(~Lhs()) onOverflow(string x, Lhs)(Lhs lhs);
typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs); 
Called automatically upon an overflow during a unary or binary operation.
 Parameters:

x The operator, e.g. 
Lhs lhs
The lefthand side (or sole) argument Rhs rhs
The righthand side type involved in the operator
 Returns:

Nominally the result is the desired value of the operator, which will be forwarded as result. For
Abort
, the function never returns because it aborts the program.
 struct Throw;

Force all integral errors to fail by throwing an exception of type
Throw.CheckFailure
. The message coming with the error is similar to the one printed byWarn
. Examples:

void test(T)() { Checked!(int, Throw) x; x = 42; auto x1 = cast(T) x; writeln(x1); // 42 x = T.max + 1; import std.exception : assertThrown, assertNotThrown; assertThrown(cast(T) x); x = x.max; assertThrown(x += 42); assertThrown(x += 42L); x = x.min; assertThrown(x); assertThrown(x = 42); assertThrown(x = 42L); x = 1; assertNotThrown(x == 1); assertThrown(x == uint(1)); assertNotThrown(x <= 1); assertThrown(x <= uint(1)); } test!short; test!(const short); test!(immutable short);
 class CheckFailure: object.Exception;

Exception type thrown upon any failure.
 Dst onBadCast(Dst, Src)(Src src);

Called automatically upon a bad cast (one that loses precision or attempts to convert a negative value to an unsigned type). The source type is
Src
and the destination type isDst
. Parameters:

Src src
The source of the cast
 Returns:

Nominally the result is the desired value of the cast operation, which will be forwarded as the result of the cast. For
Throw
, the function never returns because it throws an exception.

T onLowerBound(Rhs, T)(Rhs rhs, T bound);
T onUpperBound(Rhs, T)(Rhs rhs, T bound); 
Called automatically upon a bounds error.
 Parameters:

Rhs rhs
The righthand side value in the assignment, after the operator has been evaluated T bound
The value of the bound being violated
 Returns:

Nominally the result is the desired value of the operator, which will be forwarded as result. For
Throw
, the function never returns because it throws.
 bool hookOpEquals(L, R)(L lhs, R rhs);

Called automatically upon a comparison for equality. Throws upon an erroneous comparison (one that would make a signed negative value appear equal to an unsigned positive value).
 Parameters:

L lhs
The first argument of Checked
, e.g.int
if the lefthand side of the operator isChecked!int
R rhs
The righthand side type involved in the operator
 Returns:
 The result of the comparison.
 Throws:
CheckFailure
if the comparison is mathematically erroneous.
 int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs);

Called automatically upon a comparison for ordering using one of the operators
<
,<=
,>
, or>=
. In case the comparison is erroneous (i.e. it would make a signed negative value appear greater than or equal to an unsigned positive value), throws aThrow.CheckFailure
exception. Otherwise, the threestate result is returned (positive iflhs > rhs
, negative iflhs < rhs
,0
otherwise). Parameters:

Lhs lhs
The first argument of Checked
, e.g.int
if the lefthand side of the operator isChecked!int
Rhs rhs
The righthand side type involved in the operator
 Returns:

For correct comparisons, returns a positive integer if
lhs > rhs
, a negative integer iflhs < rhs
,0
if the two are equal.
 Throws:

Upon a mistaken comparison such as
int(1) < uint(0)
, the function never returns because it throws aThrow.CheckedFailure
exception.

typeof(~Lhs()) onOverflow(string x, Lhs)(Lhs lhs);
typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs); 
Called automatically upon an overflow during a unary or binary operation.
 Parameters:

x The operator, e.g. 
Lhs lhs
The lefthand side (or sole) argument Rhs rhs
The righthand side type involved in the operator
 Returns:

Nominally the result is the desired value of the operator, which will be forwarded as result. For
Throw
, the function never returns because it throws an exception.
 struct Warn;

Hook that prints to
stderr
a trace of all integral errors, without affecting default behavior. Examples:

auto x = checked!Warn(42); short x1 = cast(short) x; //x += long(int.max); auto y = checked!Warn(cast(const int) 42); short y1 = cast(const byte) y;
 Dst onBadCast(Dst, Src)(Src src);

Called automatically upon a bad cast from
src
to typeDst
(one that loses precision or attempts to convert a negative value to an unsigned type). Parameters:

Src src
The source of the cast Dst The target type of the cast
 Returns:

cast(Dst) src

Lhs onLowerBound(Rhs, T)(Rhs rhs, T bound);
T onUpperBound(Rhs, T)(Rhs rhs, T bound); 
Called automatically upon a bad
opOpAssign
call (one that loses precision or attempts to convert a negative value to an unsigned type). Parameters:

Rhs rhs
The righthand side value in the assignment, after the operator has been evaluated T bound
The bound being violated
 Returns:

cast(Lhs) rhs
 bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs);

Called automatically upon a comparison for equality. In case of an Erroneous comparison (one that would make a signed negative value appear equal to an unsigned positive value), writes a warning message to
stderr
as a side effect. Parameters:

Lhs lhs
The first argument of Checked
, e.g.int
if the lefthand side of the operator isChecked!int
Rhs rhs
The righthand side type involved in the operator
 Returns:

In all cases the function returns the builtin result of
lhs == rhs
.
 Examples:

auto x = checked!Warn(42); // Passes writeln(x); // 42 // Passes but prints a warning // assert(x == uint(42));
 int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs);

Called automatically upon a comparison for ordering using one of the operators
<
,<=
,>
, or>=
. In case the comparison is erroneous (i.e. it would make a signed negative value appear greater than or equal to an unsigned positive value), then a warning message is printed tostderr
. Parameters:

Lhs lhs
The first argument of Checked
, e.g.int
if the lefthand side of the operator isChecked!int
Rhs rhs
The righthand side type involved in the operator
 Returns:

In all cases, returns
lhs < rhs ? 1 : lhs > rhs
. The result is not autocorrected in case of an erroneous comparison.
 Examples:

auto x = checked!Warn(42); // Passes assert(x <= 42); // Passes but prints a warning // assert(x <= uint(42));

typeof(~Lhs()) onOverflow(string x, Lhs)(ref Lhs lhs);
typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs); 
Called automatically upon an overflow during a unary or binary operation.
 Parameters:

x The operator involved Lhs The first argument of Checked
, e.g.int
if the lefthand side of the operator isChecked!int
Rhs The righthand side type involved in the operator
 Returns:
mixin(x ~ "lhs")
for unary,mixin("lhs" ~ x ~ "rhs")
for binary
 struct ProperCompare;

Hook that provides arithmetically correct comparisons for equality and ordering. Comparing an object of type
Checked!(X, ProperCompare)
against another integral (for equality or ordering) ensures that no surprising conversions from signed to unsigned integral occur before the comparison. UsingChecked!(X, ProperCompare)
on either side of a comparison for equality against a floatingpoint number makes sure the integral can be properly converted to the floating point type, thus making sure equality is transitive. Examples:

alias opEqualsProper = ProperCompare.hookOpEquals; assert(opEqualsProper(42, 42)); assert(opEqualsProper(42.0, 42.0)); assert(opEqualsProper(42u, 42)); assert(opEqualsProper(42, 42u)); writeln(1); // 4294967295u assert(!opEqualsProper(1, 4294967295u)); assert(!opEqualsProper(const uint(1), 1)); assert(!opEqualsProper(uint(1), 1.0)); writeln(3_000_000_000U); // 1_294_967_296 assert(!opEqualsProper(3_000_000_000U, 1_294_967_296));
 bool hookOpEquals(L, R)(L lhs, R rhs);

Hook for
==
and!=
that ensures comparison against integral values has the behavior expected by the usual arithmetic rules. The builtin semantics yield surprising behavior when comparing signed values against unsigned values for equality, for exampleuint.max == 1
or1_294_967_296 == 3_000_000_000u
. The callhookOpEquals(x, y)
returnstrue
if and only ifx
andy
represent the same arithmetic number.If one of the numbers is an integral and the other is a floatingpoint number,
hookOpEquals(x, y)
returnstrue
if and only if the integral can be converted exactly (without approximation) to the floatingpoint number. This is in order to preserve transitivity of equality: ifhookOpEquals(x, y)
andhookOpEquals(y, z)
thenhookOpEquals(y, z)
, in casex
,y
, andz
are a mix of integral and floatingpoint numbers. Parameters:

L lhs
The lefthand side of the comparison for equality R rhs
The righthand side of the comparison for equality
 Returns:

The result of the comparison,
true
if the values are equal
 auto hookOpCmp(L, R)(L lhs, R rhs);

Hook for
<
,<=
,>
, and>=
that ensures comparison against integral values has the behavior expected by the usual arithmetic rules. The builtin semantics yield surprising behavior when comparing signed values against unsigned values, for example0u < 1
. The callhookOpCmp(x, y)
returns1
if and only ifx
is smaller thany
in abstract arithmetic sense.If one of the numbers is an integral and the other is a floatingpoint number,
hookOpEquals(x, y)
returns a floatingpoint number that is1
ifx < y
,0
ifx == y
,1
ifx > y
, andNaN
if the floatingpoint number isNaN
. Parameters:

L lhs
The lefthand side of the comparison for ordering R rhs
The righthand side of the comparison for ordering
 Returns:

The result of the comparison (negative if
lhs < rhs
, positive iflhs > rhs
,0
if the values are equal)
 struct WithNaN;

Hook that reserves a special value as a "Not a Number" representative. For signed integrals, the reserved value is
T.min
. For signed integrals, the reserved value isT.max
.The default value of a
Checked!(X, WithNaN)
is its NaN value, so care must be taken that all variables are explicitly initialized. Any arithmetic and logic operation involving at least on NaN becomes NaN itself. All ofa == b
,a < b
,a > b
,a <= b
,a >= b
yieldfalse
if at least one ofa
andb
is NaN. Examples:

auto x1 = Checked!(int, WithNaN)(); assert(x1.isNaN); writeln(x1.get); // int.min assert(x1 != x1); assert(!(x1 < x1)); assert(!(x1 > x1)); assert(!(x1 == x1)); ++x1; assert(x1.isNaN); writeln(x1.get); // int.min x1; assert(x1.isNaN); writeln(x1.get); // int.min x1 = 42; assert(!x1.isNaN); writeln(x1); // x1 assert(x1 <= x1); assert(x1 >= x1); static assert(x1.min == int.min + 1); x1 += long(int.max);
 enum T defaultValue(T);

The default value used for values not explicitly initialized. It is the NaN value, i.e.
T.min
for signed integrals andT.max
for unsigned integrals. 
enum T max(T);
enum T min(T); 
The maximum value representable is
T.max
for signed integrals,T.max  1
for unsigned integrals. The minimum value representable isT.min + 1
for signed integrals,0
for unsigned integrals.  Lhs hookOpCast(Lhs, Rhs)(Rhs rhs);

If
rhs
isWithNaN.defaultValue!Rhs
, returnsWithNaN.defaultValue!Lhs
. Otherwise, returnscast(Lhs) rhs
. Parameters:

Rhs rhs
the value being cast ( Rhs
is the first argument toChecked
)Lhs the target type of the cast
 Returns:
 The result of the cast operation.
 Examples:

auto x = checked!WithNaN(422); writeln((cast(ubyte)x)); // 255 x = checked!WithNaN(422); writeln((cast(byte)x)); // 128 writeln(cast(short)x); // 422 assert(cast(bool) x); x = x.init; // set back to NaN assert(x != true); assert(x != false);
 bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs);

Returns
false
iflhs == WithNaN.defaultValue!Lhs
,lhs == rhs
otherwise. Parameters:

Lhs lhs
The lefthand side of the comparison ( Lhs
is the first argument toChecked
)Rhs rhs
The righthand side of the comparison
 Returns:

lhs != WithNaN.defaultValue!Lhs && lhs == rhs
 double hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs);

If
lhs == WithNaN.defaultValue!Lhs
, returnsdouble.init
. Otherwise, has the same semantics as the default comparison. Parameters:

Lhs lhs
The lefthand side of the comparison ( Lhs
is the first argument toChecked
)Rhs rhs
The righthand side of the comparison
 Returns:
double.init
iflhs == WitnNaN.defaultValue!Lhs
,1.0
iflhs < rhs
,0.0
iflhs == rhs
,1.0
iflhs > rhs
.
 Examples:

Checked!(int, WithNaN) x; assert(!(x < 0) && !(x > 0) && !(x == 0)); x = 1; assert(x > 0 && !(x < 0) && !(x == 0));
 auto hookOpUnary(string x, T)(ref T v);

Defines hooks for unary operators

,~
,++
, and
.For

and~
, ifv == WithNaN.defaultValue!T
, returnsWithNaN.defaultValue!T
. Otherwise, the semantics is the same as for the builtin operator.
For++
and
, ifv == WithNaN.defaultValue!Lhs
or the operation would result in an overflow, setsv
toWithNaN.defaultValue!T
. Otherwise, the semantics is the same as for the builtin operator. Parameters:

x The operator symbol T v
The lefthand side of the comparison ( T
is the first argument toChecked
)
 Returns:

 For
x == ""  x == "~"
: Ifv == WithNaN.defaultValue!T
, the function returnsWithNaN.defaultValue!T
. Otherwise it returns the normal result of the operator.  For
x == "++"  x == ""
: The function returnsvoid
.
 For
 Examples:

Checked!(int, WithNaN) x; ++x; assert(x.isNaN); x = 1; assert(!x.isNaN); x = x; ++x; assert(!x.isNaN);
 auto hookOpBinary(string x, L, R)(L lhs, R rhs);

Defines hooks for binary operators
+
,
,*
,/
,%
,^^
,&
,
,^
,<<
,>>
, and>>>
for cases where aChecked
object is the lefthand side operand. Iflhs == WithNaN.defaultValue!Lhs
, returnsWithNaN.defaultValue!(typeof(lhs + rhs))
without evaluating the operand. Otherwise, evaluates the operand. If evaluation does not overflow, returns the result. Otherwise, returnsWithNaN.defaultValue!(typeof(lhs + rhs))
. Parameters:

x The operator symbol L lhs
The lefthand side operand ( Lhs
is the first argument toChecked
)R rhs
The righthand side operand
 Returns:

If
lhs != WithNaN.defaultValue!Lhs
and the operator does not overflow, the function returns the same result as the builtin operator. In all other cases, returnsWithNaN.defaultValue!(typeof(lhs + rhs))
.
 Examples:

Checked!(int, WithNaN) x; assert((x + 1).isNaN); x = 100; assert(!(x + 1).isNaN);
 auto hookOpBinaryRight(string x, L, R)(L lhs, R rhs);

Defines hooks for binary operators
+
,
,*
,/
,%
,^^
,&
,
,^
,<<
,>>
, and>>>
for cases where aChecked
object is the righthand side operand. Ifrhs == WithNaN.defaultValue!Rhs
, returnsWithNaN.defaultValue!(typeof(lhs + rhs))
without evaluating the operand. Otherwise, evaluates the operand. If evaluation does not overflow, returns the result. Otherwise, returnsWithNaN.defaultValue!(typeof(lhs + rhs))
. Parameters:

x The operator symbol L lhs
The lefthand side operand R rhs
The righthand side operand ( Rhs
is the first argument toChecked
)
 Returns:

If
rhs != WithNaN.defaultValue!Rhs
and the operator does not overflow, the function returns the same result as the builtin operator. In all other cases, returnsWithNaN.defaultValue!(typeof(lhs + rhs))
.
 Examples:

Checked!(int, WithNaN) x; assert((1 + x).isNaN); x = 100; assert(!(1 + x).isNaN);
 void hookOpOpAssign(string x, L, R)(ref L lhs, R rhs);

Defines hooks for binary operators
+=
,=
,*=
,/=
,%=
,^^=
,&=
,=
,^=
,<<=
,>>=
, and>>>=
for cases where aChecked
object is the lefthand side operand. Iflhs == WithNaN.defaultValue!Lhs
, no action is carried. Otherwise, evaluates the operand. If evaluation does not overflow and fits inLhs
without loss of information or change of sign, setslhs
to the result. Otherwise, setslhs
toWithNaN.defaultValue!Lhs
. Parameters:

x The operator symbol (without the =
)L lhs
The lefthand side operand ( Lhs
is the first argument toChecked
)R rhs
The righthand side operand
 Returns:

void
 Examples:

Checked!(int, WithNaN) x; x += 4; assert(x.isNaN); x = 0; x += 4; assert(!x.isNaN); x += int.max; assert(x.isNaN);
 bool isNaN(T)(const Checked!(T, WithNaN) x);

Queries whether a
Checked!(T, WithNaN)
object is not a number (NaN). Parameters:

Checked!(T, WithNaN) x
the Checked
instance queried
 Returns:
true
ifx
is a NaN,false
otherwise
 Examples:

auto x1 = Checked!(int, WithNaN)(); assert(x1.isNaN); x1 = 1; assert(!x1.isNaN); x1 = x1.init; assert(x1.isNaN);
 struct Saturate;

Hook that implements saturation, i.e. any arithmetic operation that would overflow leaves the result at its extreme value (
min
ormax
depending on the direction of the overflow).Saturation is not sticky; if a value reaches its saturation value, another operation may take it back to normal range.
 Examples:

auto x = checked!Saturate(int.max); ++x; writeln(x); // int.max x; writeln(x); // int.max  1 x = int.min; writeln(x); // int.max x = 42; writeln(x); // int.min writeln(x * 2); // int.max

T onLowerBound(Rhs, T)(Rhs rhs, T bound);
T onUpperBound(Rhs, T)(Rhs rhs, T bound); 
Implements saturation for operators
+=
,=
,*=
,/=
,%=
,^^=
,&=
,=
,^=
,<<=
,>>=
, and>>>=
. This hook is called if the result of the binary operation does not fit inLhs
without loss of information or a change in sign. Parameters:

Rhs The righthand side type in the assignment, after the operation has been computed T bound
The bound being violated
 Returns:
Lhs.max
ifrhs >= 0
,Lhs.min
otherwise.
 Examples:

auto x = checked!Saturate(short(100)); x += 33000; writeln(x); // short.max x = 70000; writeln(x); // short.min

auto onOverflow(string x, Lhs)(Lhs lhs);
typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs); 
Implements saturation for operators
+
,
(unary and binary),*
,/
,%
,^^
,&
,
,^
,<<
,>>
, and>>>
.For unary

,onOverflow
is called iflhs == Lhs.min
andLhs
is a signed type. The function returnsLhs.max
.
For binary operators, the result is as follows:Lhs.max
if the result overflows in the positive direction, on division by0
, or on shifting right by a negative valueLhs.min
if the result overflows in the negative direction0
iflhs
is being shifted left by a negative value, or shifted right by a large positive value
 Parameters:

x The operator involved in the opAssign
operationLhs The lefthand side of the operator ( Lhs
is the first argument toChecked
)Rhs The righthand side type in the operator
 Returns:
 The saturated result of the operator.
 Examples:

writeln(checked!Saturate(int.max) + 1); // int.max writeln(checked!Saturate(100)^^10); // int.max writeln(checked!Saturate(100)^^10); // int.max writeln(checked!Saturate(100) / 0); // int.max writeln(checked!Saturate(100) << 1); // 0 writeln(checked!Saturate(100) << 33); // int.max writeln(checked!Saturate(100) >> 1); // int.max writeln(checked!Saturate(100) >> 33); // 0

typeof(mixin(x == "cmp" ? "0" : "L() " ~ x ~ " R()")) opChecked(string x, L, R)(const L lhs, const R rhs, ref bool overflow)
Constraints: if (isIntegral!L && isIntegral!R); 
Defines binary operations with overflow checking for any two integral types. The result type obeys the language rules (even when they may be counterintuitive), and
overflow
is set if an overflow occurs (including inadvertent change of signedness, e.g.1
is converted touint
). Conceptually the behavior is: Perform the operation in infinite precision
 If the infiniteprecision result fits in the result type, return it and do not touch
overflow
 Otherwise, set
overflow
totrue
and return an unspecified value
The implementation exploits properties of types and operations to minimize additional work. Parameters:

x The binary operator involved, e.g. /
L lhs
The lefthand side of the operator R rhs
The righthand side of the operator bool overflow
The overflow indicator (assigned true
in case there's an error)
 Returns:
 The result of the operation, which is the same as the builtin operator
 Examples:

bool overflow; assert(opChecked!"+"(const short(1), short(1), overflow) == 2 && !overflow); assert(opChecked!"+"(1, 1, overflow) == 2 && !overflow); assert(opChecked!"+"(1, 1u, overflow) == 2 && !overflow); assert(opChecked!"+"(1, 1u, overflow) == 0 && !overflow); assert(opChecked!"+"(1u, 1, overflow) == 0 && !overflow);
 Examples:

bool overflow; assert(opChecked!""(1, 1, overflow) == 0 && !overflow); assert(opChecked!""(1, 1u, overflow) == 0 && !overflow); assert(opChecked!""(1u, 1, overflow) == 2 && !overflow); assert(opChecked!""(1, 1u, overflow) == 0 && overflow);
© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_experimental_checkedint.html