std.experimental.checkedint
Этот модуль определяет средства для эффективной проверки целочисленных операций на переполнение, преобразования с потерей точности, неожиданного изменения знака и т. д. Проверка (и, возможно, исправление) может выполняться на уровне операции, например, opChecked!"+"(x, y, overflow) складывает два целых числа x и y и устанавливает overflow в true в случае переполнения. Флаг overflow (ссылка на bool) не изменяется, если операция выполнена успешно, поэтому этот же флаг можно повторно использовать для последовательности операций и проверить в конце.
Выдача отдельных проверочных операций гибкая и эффективная, но часто утомительная. Объект Checked предлагает инкапсулированные целочисленные оболочки, которые выполняют всю проверку внутренне и имеют настраиваемое поведение при ошибочных результатах. Например, Checked!int — это тип, который ведет себя как int , но немедленно прерывает выполнение всякий раз, когда участвует в операции, которая дает арифметически неверный результат. Сопутствующая функция удобства checked использует вывод типа для преобразования значения x целочисленного типа T в Checked!T с помощью checked(x). Например:
void main()
{
import std.experimental.checkedint, std.stdio;
writeln((checked(5) + 7).get); // 12
writeln((checked(10) * 1000 * 1000 * 1000).get); // Overflow
}
Аналогично,
checked(-1) > uint(0) прерывает выполнение (даже если встроенное сравнение int(-1) > uint(0) неожиданно истинно из-за правил преобразования языка, основанных на C). Таким образом, Checked!int — это практически прямой аналог int, используемый в отладочных сборках, который заменяется на int в релизной сборке, если это требует эффективности. Checked имеет настраиваемое поведение с помощью второго параметра типа Hook. В зависимости от того, какие методы Hook определяет, основные операции над базовым целым числом могут быть проверены на переполнение или полностью переопределены. Если Hook не определяет ни одного метода и не содержит состояния, поведение не изменяется, т. е. Checked!(int, void) является оболочкой над int , которая не добавляет никаких настроек. Этот модуль предоставляет несколько предопределенных хуков (ниже), которые добавляют полезное поведение к
Checked: Abort | отказывает в каждой неправильной операции с сообщением в std.stdio. stderr, за которым следует вызов assert(0). Это параметр по умолчанию, т. е. Checked!short эквивалентен Checked!(short, Abort). |
Throw | отказывает в каждой неправильной операции, сгенерировав исключение. |
Warn | выводит неправильные операции в std.stdio.stderr, но в остальном сохраняет встроенное поведение. |
ProperCompare | исправляет операторы сравнения ==, !=, <, <=, >, и >= для возвращения правильных результатов во всех случаях, с небольшой потерей эффективности. Например, Checked!(uint, ProperCompare)(1) > -1 равно true, что не так для встроенного сравнения. Кроме того, сравнение чисел на равенство с числами с плавающей точкой проходит только в том случае, если целое число может быть точно преобразовано в число с плавающей точкой, чтобы сохранить транзитивность равенства. |
WithNaN | зарезервирует специальное значение «Не число» (NaN), аналогичное одноименному значению, зарезервированному для чисел с плавающей точкой. После того, как Checked!(X, WithNaN) получит это специальное значение, оно сохранит и распространит его до повторной присваивания. isNaN можно использовать для запроса, является ли объект не числом. |
Saturate | реализует насыщающую арифметику, т. е. Checked!(int, Saturate) «останавливается» на int.max для всех операций, которые привели бы к переполнению int в бесконечность, и на int.min для всех операций, которые соответствуют переполнению в сторону отрицательной бесконечности. |
Эти политики могут использоваться по отдельности, например,
Checked!(uint, WithNaN) определяет тип, подобный uint , который достигает стабильного состояния NaN для всех ошибочных операций. Они также могут «накладываться» друг на друга, благодаря свойству, что целочисленное число с проверкой эмулирует фактическое целочисленное число, а это означает, что на нём может быть построено другое целочисленное число с проверкой. Некоторые интересные комбинации включают: Checked!(Checked!int, ProperCompare) |
определяет тип, подобный int , с фиксированными операторами сравнения, которые при переполнении будут завершаться с ошибкой assert(0). (Напомним, что Abort — это политика по умолчанию). Порядок комбинирования политик важен, так как внешняя политика (ProperCompare в данном случае) первой перехватывает оператор. Обратная комбинация Checked!(Checked!(int, ProperCompare)) не имеет смысла, потому что Abort будет перехватывать сравнение и завершаться ошибкой, не дав ProperCompare возможности вмешаться. |
Checked!(Checked!(int, ProperCompare), WithNaN) |
определяет тип, подобный int , который поддерживает значение NaN. Для значений, не являющихся NaN, сравнение работает правильно. Снова важен порядок композиции; Checked!(Checked!(int, WithNaN), ProperCompare) не имеет хорошей семантики, потому что ProperCompare перехватывает сравнения до проверки чисел на NaN. |
Члены хука ищутся статически в стиле «Разработка с помощью интроспекции», и все они необязательны. Таблица ниже иллюстрирует члены, которые может определить тип хука, и их влияние на поведение типа
Checked , который его использует. В таблице hook — это псевдоним для Hook , если тип Hook не вводит никакого состояния, или объект типа Hook в противном случае.
Hook член | Семантика в Checked!(T, Hook)
|
|---|---|
defaultValue | Если определено, Hook.defaultValue!T используется в качестве значения по умолчанию для инициализации полезной нагрузки. |
min | Если определено, Hook.min!T используется как минимальное значение полезной нагрузки. |
max | Если определено, Hook.max!T используется как максимальное значение полезной нагрузки. |
hookOpCast | Если определено, hook.hookOpCast!U(get) передаётся безусловно, когда полезная нагрузка должна быть приведена к типу U. |
onBadCast | Если определено и hookOpCast не определено, onBadCast!U(get) передаётся, когда полезная нагрузка должна быть приведена к типу U, и приведение может потерять информацию или изменить знак. |
hookOpEquals | Если определено, hook.hookOpEquals(get, rhs) передаётся безусловно, когда полезная нагрузка сравнивается на равенство со значением rhs целочисленного, с плавающей точкой или булевого типа. |
hookOpCmp | Если определено, hook.hookOpCmp(get, rhs) передаётся безусловно, когда полезная нагрузка сравнивается по порядку со значением rhs целочисленного, с плавающей точкой или булевого типа. |
hookOpUnary | Если определено, hook.hookOpUnary!op(get) (где op — символ оператора) передаётся для унарных операторов - и ~. Кроме того, для унарных операторов ++ и --, вызывается hook.hookOpUnary!op(payload), где payload — ссылка на значение, обернутое в Checked, чтобы обработчик мог его изменить. |
hookOpBinary | Если определено, hook.hookOpBinary!op(get, rhs) (где op — символ оператора, а rhs — операнд правой части) передаётся безусловно для бинарных операторов +, -, *, /, %, ^^, &, |, ^, <<, >>, и >>>. |
hookOpBinaryRight | Если определено, hook.hookOpBinaryRight!op(lhs, get) (где op — символ оператора, а lhs — операнд левой части) передаётся безусловно для бинарных операторов +, -, *, /, %, ^^, &, |, ^, <<, >>, и >>>. |
onOverflow | Если определено, hook.onOverflow!op(get) передаётся для унарных операторов, которые вызывают переполнение, только если hookOpUnary не определено. Унарный ~ не вызывает переполнение; унарный - вызывает переполнение только тогда, когда отрицается самое маленькое значение знакового типа, и возвращается результат вызова обработчика. Когда операторы инкремента или декремента вызывают переполнение, полезной нагрузке присваивается результат hook.onOverflow!op(get). Когда бинарный оператор вызывает переполнение, возвращается результат hook.onOverflow!op(get, rhs), но только если Hook не определяет hookOpBinary. |
hookOpOpAssign | Если определено, hook.hookOpOpAssign!op(payload, rhs) (где op — символ оператора, а rhs — операнд правой части) передаётся безусловно для бинарных операторов +=, -=, *=, /=, %=, ^^=, &=, |=, ^=, <<=, >>=, и >>>=. |
onLowerBound | Если определено, hook.onLowerBound(value, bound) (где value — присваиваемое значение) передаётся, когда результат бинарных операторов +=, -=, *=, /=, %=, ^^=, &=, |=, ^=, <<=, >>=, и >>>= меньше наименьшего значения, представимого в T. |
onUpperBound | Если определено, hook.onUpperBound(value, bound) (где value — присваиваемое значение) передаётся, когда результат бинарных операторов +=, -=, *=, /=, %=, ^^=, &=, |=, ^=, <<=, >>=, и >>>= больше наибольшего значения, представимого в T. |
hookToHash | Если определено, hook.hookToHash(payload) (где payload — ссылка на значение, обернутое в Checked) передаётся, когда вызывается toHash для типа Checked. Пользовательское хеширование может быть реализовано в Hook, иначе используется встроенное хеширование. |
- Источник
- std/experimental/checkedint.d
- Примеры:
-
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]
- Примеры:
-
Saturateостанавливается на переполненииauto x = (cast(byte) 127).checked!Saturate; writeln(x); // 127 x++; writeln(x); // 127
- Примеры:
-
WithNaNимеет специальное значение "Не число" (NaN), аналогичное значению, зарезервированному для значений с плавающей точкойauto x = 100.checked!WithNaN; writeln(x); // 100 x /= 0; assert(x.isNaN);
- Примеры:
-
ProperCompareисправляет операторы сравнения ==, !=, <, <=, >, и >= для возвращения правильных результатовuint x = 1; auto y = x.checked!ProperCompare; assert(x < -1); // built-in comparison assert(y > -1); // ProperCompare
- Примеры:
-
Throwпрерывает каждую неверную операцию, выбросив исключение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
Tand customizes its behavior with the help of aHooktype. The type wrapped must be one of the predefined integrals (unqualified), or another instance ofChecked.- alias Representation = T;
-
Тип целочисленного объекта, подлежащего проверке.
- Hook hook;
-
hook— это переменная-член, если она имеет состояние, или псевдоним дляHookв противном случае. - inout auto get();
-
Возвращает копию базового значения.
- Примеры:
-
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; -
Определяет минимальное и максимальное значения. Эти значения можно настраивать, определив
Hook.minи/илиHook.max.- Примеры:
- Определяет минимальное и максимальное значения. Эти значения можно настраивать, определив
Hook.minи/или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)
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)))); -
Конструктор, принимающий значение, корректно преобразуемое в базовый тип.
Uможет быть целым числом, которое можно преобразовать вTбез потерь, или другим экземпляромChecked, представление которого в свою очередь может быть преобразовано вTбез потерь.- Примеры:
-
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)))); -
Оператор присваивания. Имеет те же ограничения, что и конструктор.
- Примеры:
-
Checked!long a; a = 42L; writeln(a); // 42 a = 4242; writeln(a); // 4242
- Примеры:
-
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)); -
Оператор преобразования к целочисленному,
bool, или плавающему типу. ЕслиHookопределяетhookOpCast, вызов сразу возвращаетhook.hookOpCast!U(get). В противном случае, преобразование кboolдаётget != 0, а преобразование к другому целому числу, которое может представлять все значенияTвозвращаетget, преобразованное к типуU.Если требуется преобразование к типу с плавающей точкой, и
HookопределяетonBadCast, преобразование проверяется, гарантируяget == cast(T) U(get). Если это неtrue, возвращаетсяhook.onBadCast!U(get).
Если требуется преобразование к целому типу, иHookопределяетonBadCast, преобразование проверяется, гарантируяgetиcast(U) getявляются одинаковыми арифметическими числами. (Обратите внимание, чтоint(-1)иuint(1)являются различными арифметическими значениями, хотя они имеют одинаковое битовое представление и сравниваются как равные по правилам языка.) Если числа не равны арифметически, возвращаетсяhook.onBadCast!U(get).- Примеры:
-
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))); -
Сравнивает
thisсrhsна равенство. ЕслиHookопределяетhookOpEquals, функция перенаправляется наhook.hookOpEquals(get, rhs). В противном случае возвращается результат встроенной операцииget == rhs.Если
Uтакже является экземпляромChecked, оба хука (левый и правый) проверяются на методhookOpEquals. Если оба его определяют, приоритет отдаётся левому хуку.- Примеры:
-
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 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();
-
Генерирует хэш для
this. ЕслиHookопределяетhookToHash, вызов сразу возвращаетhook.hookToHash(payload). ЕслиHookне реализуетhookToHash, но имеет состояние, хэш будет сгенерирован дляHookс использованием встроенной функции и побитово сложен с хэшемpayload. - 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); -
Сравнивает
thisсrhsдля упорядочения. ЕслиHookопределяетhookOpCmp, функция перенаправляется наhook.hookOpCmp(get, rhs). В противном случае возвращается результат встроенной операции сравнения.Если
Uтакже является экземпляромChecked, оба хука (левый и правый) проверяются на методhookOpCmp. Если оба его определяют, приоритет отдаётся левому хуку.- Примеры:
-
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 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 _)()
Constraints: if (op == "+" || op == "-" || op == "~");
ref Checked opUnary(string op)() return
Constraints: if (op == "++" || op == "--"); -
Определяет унарные операторы
+,-,~,++, и--. Унарный+не переопределяется и всегда имеет встроенное поведение (возвращаетthis). Для остальных, еслиHookопределяетhookOpUnary,opUnaryперенаправляется наChecked!(typeof(hook.hookOpUnary!op(get)), Hook)(hook.hookOpUnary!op(get)).Если
Hookне определяетhookOpUnaryно определяетonOverflow,opUnaryперенаправляется наhook.onOverflow!op(get)в случае переполнения. Для++и--, полезная нагрузка присваивается из результата вызоваonOverflow.
Обратите внимание, что унарный-считается переполняющим, еслиT— знаковое целое число 32 или 64 бит и равно наименьшему отрицательному значению. Это потому, что это значение не имеет положительного отрицания.- Примеры:
-
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); -
Определяет бинарные операторы
+,-,*,/,%,^^,&,|,^,<<,>>, и>>>. ЕслиHookопределяетhookOpBinary,opBinaryперенаправляется наChecked!(typeof(hook.hookOpBinary!op(get, rhs)), Hook)(hook.hookOpBinary!op(get, rhs)).Если
Hookне определяетhookOpBinaryно определяетonOverflow,opBinaryперенаправляется наhook.onOverflow!op(get, rhs)в случае переполнения.
Если два экземпляраCheckedучаствуют в бинарной операции, и оба определяютhookOpBinary, унарный оператор левой части имеет приоритет. Если оба определяютonOverflow, возникает ошибка компиляции. - 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)); -
Определяет бинарные операторы
+,-,*,/,%,^^,&,|,^,<<,>>, и>>>в случае, когда встроенный числовой или булевский тип находится слева, а экземплярChecked— справа. - 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));
-
Определяет операторы
+=,-=,*=,/=,%=,^^=,&=,|=,^=,<<=,>>=, и>>>=.Если
HookопределяетhookOpOpAssign,opOpAssignперенаправляется наhook.hookOpOpAssign!op(payload, rhs), гдеpayloadявляется ссылкой на внутренние данные, чтобы обработчик мог их изменить.
В противном случае, оператор сначала оцениваетauto result = opBinary!op(payload, rhs).payload, который подвергается обработке вopBinary. Затем, еслиresultменьшеChecked!(T, Hook).minи еслиHookопределяетonLowerBound, полезная нагрузка назначается изhook.onLowerBound(result, min). ЕслиresultбольшеChecked!(T, Hook).maxи еслиHookопределяетonUpperBound, полезная нагрузка назначается изhook.onUpperBound(result, min).
Если правая часть также является Checked, но с другим обработчиком или базовым типом, обработчик и базовый тип этого Checked имеют приоритет.
Во всех остальных случаях выполняется встроенное поведение.- Параметры:
op Используемый оператор (без "=", например,"+"для"+="и т. д.)Rhs rhsПравая часть оператора (левая часть - this)
- Возвращает:
- Ссылка на
this.
- Примеры:
-
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)))); -
Удобная функция, которая преобразует целое число в соответствующий экземпляр
Checked, используя вывод шаблона аргументов. Тип обработчика может быть указан (по умолчаниюAbort).- Примеры:
-
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;
-
Принудительно заставляет все целочисленные ошибки завершаться ошибкой, выведя сообщение об ошибке в
stderrи затем прервав программу.Abortявляется значением по умолчанию для второго аргументаChecked.- Dst onBadCast(Dst, Src)(Src src);
-
Вызывается автоматически при ошибочном приведении типов (приведении, которое теряет точность или пытается преобразовать отрицательное значение в беззнаковый тип). Тип источника -
Src, а тип назначения -Dst.- Параметры:
Src srcИсточник приведения
- Возвращает:
- В идеале результат - желаемое значение операции приведения, которое будет передано как результат приведения. Для
Abort, функция никогда не возвращается, так как она прерывает программу.
- T onLowerBound(Rhs, T)(Rhs rhs, T bound);
T onUpperBound(Rhs, T)(Rhs rhs, T bound); -
Вызывается автоматически при ошибке границ.
- Параметры:
Rhs rhsЗначение правой части в присваивании после вычисления оператора T boundЗначение нарушенной границы
- Возвращает:
- В идеале результат - желаемое значение оператора, которое будет возвращено в качестве результата. Для
Abort, функция никогда не возвращается, так как она прерывает программу.
- bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs);
-
Вызывается автоматически при сравнении на равенство. В случае ошибочного сравнения (которое сделает отрицательное знаковое значение равным положительному беззнаковому значению), этот обработчик генерирует
assert(0), что приводит к завершению приложения.- Параметры:
Lhs lhsПервый аргумент Checked, например,intесли левая часть оператора -Checked!intRhs rhsТип правой части, участвующей в операторе
- Возвращает:
- При правильном сравнении возвращает результат сравнения. В противном случае функция завершает приложение, поэтому она никогда не возвращается.
- int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs);
-
Вызывается автоматически при сравнении для упорядочения с помощью одного из операторов
<,<=,>, или>=. В случае ошибочного сравнения (то есть, которое сделает отрицательное знаковое значение больше или равно положительному беззнаковому значению), приложение завершается сassert(0). В противном случае возвращается результат сравнения (положительное, еслиlhs > rhs, отрицательное, еслиlhs < rhs,0в противном случае).- Параметры:
Lhs lhsПервый аргумент Checked, например,intесли левая часть оператора -Checked!intRhs rhsТип правой части, участвующей в операторе
- Возвращает:
- При правильных сравнениях возвращает положительное целое число, если
lhs > rhs, отрицательное целое число, еслиlhs < rhs,0если значения равны. При ошибочном сравнении, например,int(-1) < uint(0), функция никогда не возвращается, так как она прерывает программу.
- typeof(~Lhs()) onOverflow(string x, Lhs)(Lhs lhs);
typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs); -
Вызывается автоматически при переполнении во время унарной или бинарной операции.
- Параметры:
x Оператор, например, -Lhs lhsЛевый (или единственный) аргумент Rhs rhsТип правой части, участвующей в операторе
- Возвращает:
- В идеале результат - желаемое значение оператора, которое будет возвращено в качестве результата. Для
Abort, функция никогда не возвращается, так как она прерывает программу.
- struct Throw;
-
Принудительно обрабатывать все целочисленные ошибки, выбрасывая исключение типа
Throw.CheckFailure. Сообщение об ошибке аналогично сообщению, выводимомуWarn.- Примеры:
-
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;
-
Тип исключения, выбрасываемого при любой ошибке.
- Dst onBadCast(Dst, Src)(Src src);
-
Вызывается автоматически при некорректном приведении типов (при потере точности или попытке преобразования отрицательного значения в беззнаковый тип). Тип источника —
Src, а тип назначения —Dst.- Параметры:
Src srcИсточник приведения
- Возвращаемое значение:
- В нормальном случае результатом является желаемое значение операции приведения, которое будет передано как результат приведения. В случае
Throw, функция никогда не возвращает значение, так как выбрасывает исключение.
- T onLowerBound(Rhs, T)(Rhs rhs, T bound);
T onUpperBound(Rhs, T)(Rhs rhs, T bound); -
Вызывается автоматически при ошибке границ.
- Параметры:
Rhs rhsЗначение правой части в присваивании после вычисления оператора T boundЗначение границы, нарушенной операцией
- Возвращаемое значение:
- В нормальном случае результатом является желаемое значение оператора, которое будет возвращено. В случае
Throw, функция никогда не возвращает значение, так как выбрасывает исключение.
- bool hookOpEquals(L, R)(L lhs, R rhs);
-
Вызывается автоматически при сравнении на равенство. Выбрасывает исключение при ошибочном сравнении (при котором отрицательное знаковое значение выглядит равным положительному беззнаковому значению).
- Параметры:
L lhsПервый аргумент оператора Checked, например,int, если левая часть оператора —Checked!intR rhsТип правого аргумента, участвующего в операторе
- Возвращаемое значение:
- Результат сравнения.
- Исключения:
-
CheckFailureпри математически ошибочном сравнении.
- int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs);
-
Вызывается автоматически при сравнении для упорядочивания с помощью одного из операторов
<,<=,>, или>=. В случае ошибочного сравнения (т.е. если отрицательное знаковое значение выглядит больше или равно положительному беззнаковому значению), выбрасывается исключениеThrow.CheckFailure. В противном случае возвращается результат в трёх состояниях (положительное, еслиlhs > rhs, отрицательное, еслиlhs < rhs,0в противном случае).- Параметры:
Lhs lhsПервый аргумент оператора Checked, например,int, если левая часть оператора —Checked!intRhs rhsТип правого аргумента, участвующего в операторе
- Возвращаемое значение:
- При корректном сравнении возвращает положительное целое число, если
lhs > rhs, отрицательное целое число, еслиlhs < rhs,0если значения равны.
- Исключения:
- В случае ошибочного сравнения, например,
int(-1) < uint(0), функция никогда не возвращает значение, так как выбрасывает исключениеThrow.CheckedFailure.
- typeof(~Lhs()) onOverflow(string x, Lhs)(Lhs lhs);
typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs); -
Вызывается автоматически при переполнении во время унарной или бинарной операции.
- Параметры:
x Оператор, например, -Lhs lhsЛевый (или единственный) аргумент Rhs rhsТип правого аргумента, участвующего в операторе
- Возвращаемое значение:
- В нормальном случае результатом является желаемое значение оператора, которое будет возвращено. В случае
Throw, функция никогда не возвращает значение, так как выбрасывает исключение.
- struct Warn;
-
Обработчик, выводящий в
stderrотслеживание всех целочисленных ошибок без изменения стандартного поведения.- Примеры:
-
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);
-
Вызывается автоматически при некорректном приведении типов из
srcк типуDst(при потере точности или попытке преобразования отрицательного значения в беззнаковый тип).- Параметры:
Src srcИсточник приведения Dst Целевой тип приведения
- Возвращаемое значение:
cast(Dst) src
- Lhs onLowerBound(Rhs, T)(Rhs rhs, T bound);
T onUpperBound(Rhs, T)(Rhs rhs, T bound); -
Вызывается автоматически при ошибочном вызове
opOpAssign(с потерей точности или попыткой преобразования отрицательного значения в беззнаковый тип).- Параметры:
Rhs rhsЗначение правой части в присваивании после вычисления оператора T boundНарушенная граница
- Возвращаемое значение:
cast(Lhs) rhs
- bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs);
-
Вызывается автоматически при сравнении на равенство. В случае ошибочного сравнения (при котором отрицательное знаковое значение выглядит равным положительному беззнаковому значению) выводит предупреждение в
stderr.- Параметры:
Lhs lhsПервый аргумент оператора Checked, например,int, если левая часть оператора —Checked!intRhs rhsТип правого аргумента, участвующего в операторе
- Возвращаемое значение:
- Во всех случаях функция возвращает встроенный результат
lhs == rhs.
- Примеры:
-
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);
-
Вызывается автоматически при сравнении для упорядочивания с помощью одного из операторов
<,<=,>, или>=. В случае ошибочного сравнения (например, отрицательное знаковое значение выглядит больше или равно положительному беззнаковому значению) печатает сообщение предупреждения вstderr.- Параметры:
Lhs lhsПервый аргумент оператора Checked, например,int, если левая часть оператора —Checked!intRhs rhsТип правого аргумента, участвующего в операторе
- Возвращаемое значение:
- Во всех случаях возвращает
lhs < rhs ? -1 : lhs > rhs. Результат не корректируется автоматически в случае ошибочного сравнения.
- Примеры:
-
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); -
Вызывается автоматически при переполнении во время унарной или бинарной операции.
- Параметры:
x Вовлеченный оператор Lhs Первый аргумент оператора Checked, например,int, если левая часть оператора —Checked!intRhs Тип правого аргумента, участвующего в операторе
- Возвращаемое значение:
-
mixin(x ~ "lhs")для унарной,mixin("lhs" ~ x ~ "rhs")для бинарной
- struct ProperCompare;
-
Модуль, обеспечивающий арифметически корректные сравнения на равенство и порядок. Сравнение объекта типа
Checked!(X, ProperCompare)с другим целым числом (для равенства или порядка) гарантирует, что перед сравнением не произойдёт неожиданное преобразование от знакового к беззнаковому целочисленному типу. ИспользованиеChecked!(X, ProperCompare)по обе стороны от сравнения на равенство с плавающей точкой гарантирует, что целое число может быть корректно преобразовано в тип с плавающей точкой, тем самым обеспечивая транзитивность равенства.- Примеры:
-
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);
-
Модуль для
==и!=, гарантирующий, что сравнение с целыми значениями имеет поведение, ожидаемое по обычным правилам арифметики. Встроенная семантика приводит к неожиданному поведению при сравнении знаковых и беззнаковых целых чисел на равенство, напримерuint.max == -1или-1_294_967_296 == 3_000_000_000u. ВызовhookOpEquals(x, y)возвращаетtrueтогда и только тогда, когдаxиyпредставляют одно и то же арифметическое число.Если одно из чисел является целым, а другое — числом с плавающей точкой, то
hookOpEquals(x, y)возвращаетtrueтогда и только тогда, когда целое число может быть преобразовано точно (без приближения) в число с плавающей точкой. Это необходимо для сохранения транзитивности равенства: еслиhookOpEquals(x, y)иhookOpEquals(y, z), тоhookOpEquals(y, z), в случае, когдаx,y, иzпредставляют собой смесь целых и чисел с плавающей точкой.- Параметры:
L lhsЛевая часть сравнения на равенство R rhsПравая часть сравнения на равенство
- Возвращаемое значение:
- Результат сравнения,
trueесли значения равны
- auto hookOpCmp(L, R)(L lhs, R rhs);
-
Модуль для
<,<=,>, и>=, гарантирующий, что сравнение с целыми значениями имеет поведение, ожидаемое по обычным правилам арифметики. Встроенная семантика приводит к неожиданному поведению при сравнении знаковых и беззнаковых целых чисел, например0u < -1. ВызовhookOpCmp(x, y)возвращает-1тогда и только тогда, когдаxменьшеyв абстрактном арифметическом смысле.Если одно из чисел — целое, а другое — число с плавающей точкой,
hookOpEquals(x, y)возвращает число с плавающей точкой, которое-1еслиx < y,0еслиx == y,1еслиx > y, иNaNесли число с плавающей точкойNaN.- Параметры:
L lhsЛевая часть сравнения на порядок R rhsПравая часть сравнения на порядок
- Возвращаемое значение:
- Результат сравнения (отрицательное, если
lhs < rhs, положительное, еслиlhs > rhs,0если значения равны)
- struct WithNaN;
-
Обработчик, который резервирует специальное значение в качестве представителя «не числа» (NaN). Для знаковых целых чисел резервированное значение равно
T.min. Для знаковых целых чисел резервированное значение равноT.max.Значение по умолчанию для
Checked!(X, WithNaN)— это его значение NaN, поэтому необходимо следить за тем, чтобы все переменные были явно инициализированы. Любая арифметическая или логическая операция, включающая хотя бы одно NaN, становится равной NaN. Всеa == b,a < b,a > b,a <= b,a >= bдают результатfalse, если хотя бы одно изaиbравно NaN.- Примеры:
-
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);
-
Значение по умолчанию для значений, которые не были явно инициализированы. Это значение NaN, т.е.
T.minдля знаковых целых чисел иT.maxдля беззнаковых целых чисел. - enum T max(T);
enum T min(T); -
Максимальное представимое значение равно
T.maxдля знаковых целых чисел,T.max - 1для беззнаковых целых чисел. Минимальное представимое значение равноT.min + 1для знаковых целых чисел,0для беззнаковых целых чисел. - Lhs hookOpCast(Lhs, Rhs)(Rhs rhs);
-
Если
rhsравноWithNaN.defaultValue!Rhs, возвращаетWithNaN.defaultValue!Lhs. В противном случае возвращаетcast(Lhs) rhs.- Параметры:
Rhs rhsзначение, которое приводится ( Rhs— первый аргумент дляChecked)Lhs целевой тип приведения
- Возвращает:
- Результат операции приведения.
- Примеры:
-
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);
-
Возвращает
falseеслиlhs == WithNaN.defaultValue!Lhs,lhs == rhsв противном случае.- Параметры:
Lhs lhsЛевая часть сравнения ( Lhs— первый аргумент дляChecked)Rhs rhsПравая часть сравнения
- Возвращает:
lhs != WithNaN.defaultValue!Lhs && lhs == rhs
- double hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs);
-
Если
lhs == WithNaN.defaultValue!Lhs, возвращаетdouble.init. В противном случае имеет те же семантику, что и по умолчанию.- Параметры:
Lhs lhsЛевая часть сравнения ( Lhs— первый аргумент дляChecked)Rhs rhsПравая часть сравнения
- Возвращает:
-
double.initеслиlhs == WitnNaN.defaultValue!Lhs,-1.0еслиlhs < rhs,0.0еслиlhs == rhs,1.0еслиlhs > rhs.
- Примеры:
-
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);
-
Определяет обработчики для унарных операторов
-,~,++, и--.Для
-и~, еслиv == WithNaN.defaultValue!T, возвращаетWithNaN.defaultValue!T. В противном случае семантика такая же, как и для встроенного оператора.
Для++и--, еслиv == WithNaN.defaultValue!Lhsили операция приведет к переполнению, устанавливаетvвWithNaN.defaultValue!T. В противном случае семантика такая же, как и для встроенного оператора.- Параметры:
x Символ оператора T vЛевая часть сравнения ( T— первый аргумент дляChecked)
- Возвращает:
- Для
x == "-" || x == "~": Еслиv == WithNaN.defaultValue!T, функция возвращаетWithNaN.defaultValue!T. В противном случае возвращает нормальный результат оператора. - Для
x == "++" || x == "--": Функция возвращаетvoid.
- Для
- Примеры:
-
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);
-
Определяет обработчики для бинарных операторов
+,-,*,/,%,^^,&,|,^,<<,>>, и>>>для случаев, когда объектCheckedявляется операндом левой части. Еслиlhs == WithNaN.defaultValue!Lhs, возвращаетWithNaN.defaultValue!(typeof(lhs + rhs))без вычисления операнда. В противном случае вычисляет операнд. Если вычисление не приводит к переполнению, возвращает результат. В противном случае возвращаетWithNaN.defaultValue!(typeof(lhs + rhs)).- Параметры:
x Символ оператора L lhsОперанд левой части ( Lhs— первый аргумент дляChecked)R rhsОперанд правой части
- Возвращает:
- Если
lhs != WithNaN.defaultValue!Lhsи оператор не приводит к переполнению, функция возвращает тот же результат, что и встроенный оператор. Во всех других случаях возвращаетWithNaN.defaultValue!(typeof(lhs + rhs)).
- Примеры:
-
Checked!(int, WithNaN) x; assert((x + 1).isNaN); x = 100; assert(!(x + 1).isNaN);
- auto hookOpBinaryRight(string x, L, R)(L lhs, R rhs);
-
Определяет обработчики для бинарных операторов
+,-,*,/,%,^^,&,|,^,<<,>>, и>>>для случаев, когда объектCheckedявляется операндом правой части. Еслиrhs == WithNaN.defaultValue!Rhs, возвращаетWithNaN.defaultValue!(typeof(lhs + rhs))без вычисления операнда. В противном случае вычисляет операнд. Если вычисление не приводит к переполнению, возвращает результат. В противном случае возвращаетWithNaN.defaultValue!(typeof(lhs + rhs)).- Параметры:
x Символ оператора L lhsОперанд левой части R rhsОперанд правой части ( Rhs— первый аргумент дляChecked)
- Возвращает:
- Если
rhs != WithNaN.defaultValue!Rhsи оператор не приводит к переполнению, функция возвращает тот же результат, что и встроенный оператор. Во всех других случаях возвращаетWithNaN.defaultValue!(typeof(lhs + rhs)).
- Примеры:
-
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);
-
Определяет обработчики для бинарных операторов
+=,-=,*=,/=,%=,^^=,&=,|=,^=,<<=,>>=, и>>>=для случаев, когда объектCheckedявляется операндом левой части. Еслиlhs == WithNaN.defaultValue!Lhs, никаких действий не выполняется. В противном случае вычисляет операнд. Если вычисление не приводит к переполнению и результат помещается вLhsбез потери информации или изменения знака, устанавливаетlhsв результат. В противном случае устанавливаетlhsвWithNaN.defaultValue!Lhs.- Параметры:
x Символ оператора (без =)L lhsОперанд левой части ( Lhs— первый аргумент дляChecked)R rhsОперанд правой части
- Возвращает:
void
- Примеры:
-
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);
-
Определяет, является ли объект
Checked!(T, WithNaN)не числом (NaN).- Параметры:
Checked!(T, WithNaN) xэкземпляр Checked
- Возвращает:
-
trueеслиxравно NaN,falseв противном случае
- Примеры:
-
auto x1 = Checked!(int, WithNaN)(); assert(x1.isNaN); x1 = 1; assert(!x1.isNaN); x1 = x1.init; assert(x1.isNaN);
- struct Saturate;
-
Обработчик, реализующий насыщение, т.е. любая арифметическая операция, которая привела бы к переполнению, оставляет результат на его крайнем значении (
minилиmaxв зависимости от направления переполнения).Насыщение не является «липким»; если значение достигает своего значения насыщения, другая операция может вернуть его в нормальный диапазон.
- Примеры:
-
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); -
Реализует насыщение для операторов
+=,-=,*=,/=,%=,^^=,&=,|=,^=,<<=,>>=, и>>>=. Этот обработчик вызывается, если результат бинарной операции не помещается вLhsбез потери информации или изменения знака.- Параметры:
Rhs Тип правой части в присваивании после вычисления операции T boundПревышенное ограничение
- Возвращаемое значение:
-
Lhs.maxеслиrhs >= 0,Lhs.minв противном случае.
- Примеры:
-
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); -
Реализует насыщение для операторов
+,-(унарный и бинарный),*,/,%,^^,&,|,^,<<,>>, и>>>.Для унарных операторов
-,onOverflowвызывается, еслиlhs == Lhs.minиLhsявляется типом со знаком. Функция возвращаетLhs.max.
Для бинарных операторов результат следующий:-
Lhs.maxесли результат переполняется в положительном направлении, при делении на0, или при сдвиге вправо на отрицательное значение -
Lhs.minесли результат переполняется в отрицательном направлении -
0еслиlhsсдвигается влево на отрицательное значение или сдвигается вправо на большое положительное значение
- Параметры:
x Оператор, участвующий в операции opAssignLhs Левая часть оператора ( Lhs- первый аргумент дляChecked)Rhs Тип правой части оператора
- Возвращаемое значение:
- Насыщенный результат оператора.
- Примеры:
-
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); -
Определяет бинарные операции с проверкой переполнения для любых двух целочисленных типов. Тип результата подчиняется правилам языка (даже когда они могут быть неинтуитивными), и
overflowустанавливается, если происходит переполнение (включая непреднамеренное изменение знака, например,-1преобразуется вuint). По сути, поведение такое:- Выполнить операцию с бесконечной точностью
- Если результат с бесконечной точностью помещается в тип результата, вернуть его и не трогать
overflow - В противном случае, установить
overflowвtrueи вернуть неопределенное значение
Реализация использует свойства типов и операций для минимизации дополнительной работы.- Параметры:
x Участвующий бинарный оператор, например /L lhsЛевая часть оператора R rhsПравая часть оператора bool overflowИндикатор переполнения (присваивается trueв случае ошибки)
- Возвращаемое значение:
- Результат операции, такой же, как у встроенного оператора
- Примеры:
-
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);
- Примеры:
-
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