std.experimental.checkedint - D Programming Language

Menu

- Learn
- Documentation
  - Language Reference
  - Library Reference
  - Command-line Reference
  - Feature Overview
  - Articles
- Downloads
- Packages
- Community
  - Blog
  - Orgs using D
  - Twitter
  - Calendar
  - Forums
  - IRC
  - Wiki
  - GitHub
  - Issues
  - Get involved
  - Contributors
  - Foundation
  - Security Team
  - Donate
  - Sponsors
- Resources
  - Tour
  - Books
  - Tutorials
  - Tools
  - Editors
  - IDEs
  - run.dlang.io
  - Visual D
  - Acknowledgments
  - D Style
  - Glossary
  - Sitemap

Search
Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

# 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 built-in comparison int(-1) > uint(0) is surprisingly true due to language's conversion rules modeled after C). Thus, Checked!int is a virtually drop-in 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 built-in 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 built-in comparison. Also, comparing numbers for equality with floating-point numbers only passes if the integral can be converted to the floating-point 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 floating-point 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 right-hand 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 left-hand 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 right-hand 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 built-in hashing is used.

Source std/experimental/checkedint.d

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 overflow

    auto 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 floating-point values

    auto x = 100.checked!WithNaN;
    writeln(x); // 100
    x /= 0;
    assert(x.isNaN);

Examples:
ProperCompare fixes the comparison operators ==, !=, <, <=, >, and >= to return correct results

    uint x = 1;
    auto y = x.checked!ProperCompare;
    assert(x < -1); // built-in comparison
    assert(y > -1); // ProperCompare

Examples:
Throw fails every incorrect operation by throwing an exception

    import 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 a Hook type. The type wrapped must be one of the predefined integrals (unqualified), or another instance of `Checked`.
  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 for Hook 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/or Hook.`max`.
    Examples:
    Defines the minimum and maximum. These values are hookable by defining Hook.`min` and/or Hook.`max`.

        writeln(Checked!short.min); // -32768
        writeln(Checked!(short, WithNaN).min); // -32767
        writeln(Checked!(uint, WithNaN).max); // uint.max - 1

  this(U)(U `rhs`)
  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 to T without a loss, or another Checked instance whose representation may be in turn converted to T without a loss.
    Examples:

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

  void `opAssign`(U)(U `rhs`)
  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

  U `opCast`(U, this _)()
  if (isIntegral!U || isFloatingPoint!U || is(U == bool));
    Casting operator to integral, bool, or floating point type. If Hook defines hookOpCast, the call immediately returns hook.hookOpCast!U(get). Otherwise, casting to bool yields get != 0 and casting to another integral that can represent all values of T returns get promoted to U.
    If a cast to a floating-point type is requested and Hook defines onBadCast, the cast is verified by ensuring get == cast(T) U(get). If that is not true, hook.onBadCast!U(get) is returned.
    If a cast to an integral type is requested and Hook defines onBadCast, the cast is verified by ensuring get and cast(U) get are the same arithmetic number. (Note that int(-1) and uint(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`)
  if (isIntegral!U || isFloatingPoint!U || is(U == bool) || is(U == Checked!(V, W), V, W) && is(typeof(this == `rhs`.payload)));
    Compares this against `rhs` for equality. If Hook defines hookOpEquals, the function forwards to hook.hookOpEquals(get, rhs). Otherwise, the result of the built-in operation get == rhs is returned.
    If U is also an instance of Checked, both hooks (left- and right-hand side) are introspected for the method hookOpEquals. If both define it, priority is given to the left-hand side.
    Examples:

        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 built-in 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. If Hook defines hookToHash, the call immediately returns hook.hookToHash(payload). If Hook does not implement hookToHash, but it has state, a hash will be generated for the Hook using the built-in function and it will be xored with the hash of the payload.
  auto `opCmp`(U, this _)(const U `rhs`)
  if (isIntegral!U || isFloatingPoint!U || is(U == bool));
  auto `opCmp`(U, Hook1, this _)(Checked!(U, Hook1) `rhs`);
    Compares this against `rhs` for ordering. If Hook defines hookOpCmp, the function forwards to hook.hookOpCmp(get, rhs). Otherwise, the result of the built-in comparison operation is returned.
    If U is also an instance of Checked, both hooks (left- and right-hand side) are introspected for the method hookOpCmp. If both define it, priority is given to the left-hand side.
    Examples:

        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 built-in 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 _)()
  if (op == "+" || op == "-" || op == "~");
  ref Checked `opUnary`(string op)() return
  if (op == "++" || op == "--");
    Defines unary operators +, -, ~, ++, and --. Unary + is not overridable and always has built-in behavior (returns this). For the others, if Hook defines hookOpUnary, `opUnary` forwards to Checked!(typeof(hook.hookOpUnary!op(get)), Hook)(hook.hookOpUnary!op(get)).
    If Hook does not define hookOpUnary but defines onOverflow, `opUnary` forwards to hook.onOverflow!op(get) in case an overflow occurs. For ++ and --, the payload is assigned from the result of the call to onOverflow.
    Note that unary - is considered to overflow if T 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`)
  if (isIntegral!Rhs || isFloatingPoint!Rhs || is(Rhs == bool));
  const auto `opBinary`(string op, Rhs)(const Rhs `rhs`)
  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 >>>. If Hook defines hookOpBinary, `opBinary` forwards to Checked!(typeof(hook.hookOpBinary!op(get, rhs)), Hook)(hook.hookOpBinary!op(get, rhs)).
    If Hook does not define hookOpBinary but defines onOverflow, `opBinary` forwards to hook.onOverflow!op(get, `rhs`) in case an overflow occurs.
    If two Checked instances are involved in a binary operation and both define hookOpBinary, the left-hand side hook has priority. If both define onOverflow, a compile-time error occurs.
  auto `opBinaryRight`(string op, Lhs)(const Lhs `lhs`)
  if (isIntegral!Lhs || isFloatingPoint!Lhs || is(Lhs == bool));
  const auto `opBinaryRight`(string op, Lhs)(const Lhs `lhs`)
  if (isIntegral!Lhs || isFloatingPoint!Lhs || is(Lhs == bool));
    Defines binary operators +, -, *, /, %, ^^, &, |, ^, <<, >>, and >>> for the case when a built-in numeric or Boolean type is on the left-hand side, and a Checked instance is on the right-hand side.
  ref Checked `opOpAssign`(string op, Rhs)(const Rhs `rhs`) return
  if (isIntegral!Rhs || isFloatingPoint!Rhs || is(Rhs == bool));
  ref Checked `opOpAssign`(string op, Rhs)(const Rhs `rhs`) return
  if (is(Rhs == Checked!(RhsT, RhsHook), RhsT, RhsHook));
    Defines operators +=, -=, *=, /=, %=, ^^=, &=, |=, ^=, <<=, >>=, and >>>=.
    If Hook defines hookOpOpAssign, `opOpAssign` forwards to hook.hookOpOpAssign!op(payload, `rhs`), where payload is a reference to the internally held data so the hook can change it.
    Otherwise, the operator first evaluates auto result = opBinary!op(payload, rhs).payload, which is subject to the hooks in opBinary. Then, if result is less than Checked!(T, Hook).min and if Hook defines onLowerBound, the payload is assigned from hook.onLowerBound(result, min). If result is greater than Checked!(T, Hook).max and if Hook defines onUpperBound, the payload is assigned from hook.onUpperBound(result, min).
    If the right-hand 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 built-in behavior is carried out.
    Parameters:

    op | The operator involved (without the "=", e.g. "+" for "+=" etc)
    Rhs `rhs` | The right-hand side of the operator (left-hand 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`)
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 default Abort).
  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 for Checked.
  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 is Dst.
    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 right-hand 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 left-hand side of the operator is Checked!int
    Rhs `rhs` | The right-hand 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 with assert(0). Otherwise, the three-state result is returned (positive if lhs > rhs, negative if lhs < rhs, 0 otherwise).
    Parameters:

    Lhs `lhs` | The first argument of Checked, e.g. int if the left-hand side of the operator is Checked!int
    Rhs `rhs` | The right-hand side type involved in the operator

    Returns:
    For correct comparisons, returns a positive integer if lhs > rhs, a negative integer if lhs < rhs, 0 if the two are equal. Upon a mistaken comparison such as int(-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 left-hand side (or sole) argument
    Rhs `rhs` | The right-hand 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 by Warn.
  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 is Dst.
    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 right-hand 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 left-hand side of the operator is Checked!int
    R `rhs` | The right-hand 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 a Throw.CheckFailure exception. Otherwise, the three-state result is returned (positive if lhs > rhs, negative if lhs < rhs, 0 otherwise).
    Parameters:

    Lhs `lhs` | The first argument of Checked, e.g. int if the left-hand side of the operator is Checked!int
    Rhs `rhs` | The right-hand side type involved in the operator

    Returns:
    For correct comparisons, returns a positive integer if lhs > rhs, a negative integer if lhs < 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 a Throw.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 left-hand side (or sole) argument
    Rhs `rhs` | The right-hand 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 type Dst (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 right-hand 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 left-hand side of the operator is Checked!int
    Rhs `rhs` | The right-hand side type involved in the operator

    Returns:
    In all cases the function returns the built-in 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 to stderr.
    Parameters:

    Lhs `lhs` | The first argument of Checked, e.g. int if the left-hand side of the operator is Checked!int
    Rhs `rhs` | The right-hand 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 left-hand side of the operator is Checked!int
    Rhs | The right-hand 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. Using Checked!(X, ProperCompare) on either side of a comparison for equality against a floating-point 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 built-in semantics yield surprising behavior when comparing signed values against unsigned values for equality, for example uint.max == -1 or -1_294_967_296 == 3_000_000_000u. The call hookOpEquals(x, y) returns true if and only if x and y represent the same arithmetic number.
    If one of the numbers is an integral and the other is a floating-point number, hookOpEquals(x, y) returns true if and only if the integral can be converted exactly (without approximation) to the floating-point number. This is in order to preserve transitivity of equality: if hookOpEquals(x, y) and hookOpEquals(y, z) then hookOpEquals(y, z), in case x, y, and z are a mix of integral and floating-point numbers.
    Parameters:

    L `lhs` | The left-hand side of the comparison for equality
    R `rhs` | The right-hand 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 built-in semantics yield surprising behavior when comparing signed values against unsigned values, for example 0u < -1. The call hookOpCmp(x, y) returns -1 if and only if x is smaller than y in abstract arithmetic sense.
    If one of the numbers is an integral and the other is a floating-point number, hookOpEquals(x, y) returns a floating-point number that is -1 if x < y, 0 if x == y, 1 if x > y, and NaN if the floating-point number is NaN.
    Parameters:

    L `lhs` | The left-hand side of the comparison for ordering
    R `rhs` | The right-hand side of the comparison for ordering

    Returns:
    The result of the comparison (negative if lhs < rhs, positive if lhs > 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 is T.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 of a == b, a < b, a > b, a <= b, a >= b yield false if at least one of a and b 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 and T.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 is T.min + 1 for signed integrals, 0 for unsigned integrals.
  Lhs `hookOpCast`(Lhs, Rhs)(Rhs `rhs`);
    If `rhs` is WithNaN.defaultValue!Rhs, returns WithNaN.defaultValue!Lhs. Otherwise, returns cast(Lhs) rhs.
    Parameters:

    Rhs `rhs` | the value being cast (Rhs is the first argument to Checked)
    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 if lhs == WithNaN.defaultValue!Lhs, lhs == rhs otherwise.
    Parameters:

    Lhs `lhs` | The left-hand side of the comparison (Lhs is the first argument to Checked)
    Rhs `rhs` | The right-hand side of the comparison

    Returns:
    `lhs` != WithNaN.defaultValue!Lhs && `lhs` == `rhs`
  double `hookOpCmp`(Lhs, Rhs)(Lhs `lhs`, Rhs `rhs`);
    If lhs == WithNaN.defaultValue!Lhs, returns double.init. Otherwise, has the same semantics as the default comparison.
    Parameters:

    Lhs `lhs` | The left-hand side of the comparison (Lhs is the first argument to Checked)
    Rhs `rhs` | The right-hand side of the comparison

    Returns:
    double.init if `lhs` == WitnNaN.defaultValue!Lhs, -1.0 if lhs < rhs, 0.0 if lhs == rhs, 1.0 if lhs > 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 ~, if v == WithNaN.defaultValue!T, returns WithNaN.defaultValue!T. Otherwise, the semantics is the same as for the built-in operator.
    For ++ and --, if v == WithNaN.defaultValue!Lhs or the operation would result in an overflow, sets `v` to WithNaN.defaultValue!T. Otherwise, the semantics is the same as for the built-in operator.
    Parameters:

    x | The operator symbol
    T `v` | The left-hand side of the comparison (T is the first argument to Checked)

    Returns:
    - For x == "-" || x == "~": If v == WithNaN.defaultValue!T, the function returns WithNaN.defaultValue!T. Otherwise it returns the normal result of the operator.
    - For x == "++" || x == "--": The function returns void.
    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 a Checked object is the left-hand side operand. If lhs == WithNaN.defaultValue!Lhs, returns WithNaN.defaultValue!(typeof(lhs + rhs)) without evaluating the operand. Otherwise, evaluates the operand. If evaluation does not overflow, returns the result. Otherwise, returns WithNaN.defaultValue!(typeof(lhs + rhs)).
    Parameters:

    x | The operator symbol
    L `lhs` | The left-hand side operand (Lhs is the first argument to Checked)
    R `rhs` | The right-hand side operand

    Returns:
    If lhs != WithNaN.defaultValue!Lhs and the operator does not overflow, the function returns the same result as the built-in operator. In all other cases, returns WithNaN.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 a Checked object is the right-hand side operand. If rhs == WithNaN.defaultValue!Rhs, returns WithNaN.defaultValue!(typeof(lhs + rhs)) without evaluating the operand. Otherwise, evaluates the operand. If evaluation does not overflow, returns the result. Otherwise, returns WithNaN.defaultValue!(typeof(lhs + rhs)).
    Parameters:

    x | The operator symbol
    L `lhs` | The left-hand side operand
    R `rhs` | The right-hand side operand (Rhs is the first argument to Checked)

    Returns:
    If rhs != WithNaN.defaultValue!Rhs and the operator does not overflow, the function returns the same result as the built-in operator. In all other cases, returns WithNaN.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 a Checked object is the left-hand side operand. If lhs == WithNaN.defaultValue!Lhs, no action is carried. Otherwise, evaluates the operand. If evaluation does not overflow and fits in Lhs without loss of information or change of sign, sets `lhs` to the result. Otherwise, sets `lhs` to WithNaN.defaultValue!Lhs.
    Parameters:

    x | The operator symbol (without the =)
    L `lhs` | The left-hand side operand (Lhs is the first argument to Checked)
    R `rhs` | The right-hand 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 if `x` 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 or max 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 in Lhs without loss of information or a change in sign.
    Parameters:

    Rhs | The right-hand side type in the assignment, after the operation has been computed
    T `bound` | The bound being violated

    Returns:
    Lhs.max if rhs >= 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 if lhs == Lhs.min and Lhs is a signed type. The function returns Lhs.max.
    For binary operators, the result is as follows:
    - Lhs.max if the result overflows in the positive direction, on division by 0, or on shifting right by a negative value
    - Lhs.min if the result overflows in the negative direction
    - 0 if `lhs` is being shifted left by a negative value, or shifted right by a large positive value
    Parameters:

    x | The operator involved in the opAssign operation
    Lhs | The left-hand side of the operator (Lhs is the first argument to Checked)
    Rhs | The right-hand 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`)
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 to uint). Conceptually the behavior is:
  1. Perform the operation in infinite precision
  2. If the infinite-precision result fits in the result type, return it and do not touch `overflow`
  3. Otherwise, set `overflow` to true 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 left-hand side of the operator
  R `rhs` | The right-hand 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 built-in 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);

Copyright © 1999-2018 by the D Language Foundation | Page generated by Ddoc on Wed Nov 14 02:26:52 2018