Spec-Zone.ru › D

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 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;

Тип целочисленного объекта, подлежащего проверке.

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!int
Rhs rhs Тип правой части, участвующей в операторе
Возвращает:
При правильном сравнении возвращает результат сравнения. В противном случае функция завершает приложение, поэтому она никогда не возвращается.
int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs);

Вызывается автоматически при сравнении для упорядочения с помощью одного из операторов <, <=, >, или >=. В случае ошибочного сравнения (то есть, которое сделает отрицательное знаковое значение больше или равно положительному беззнаковому значению), приложение завершается с assert(0). В противном случае возвращается результат сравнения (положительное, если lhs > rhs, отрицательное, если lhs < rhs, 0 в противном случае).

Параметры:
Lhs lhs Первый аргумент Checked, например, int если левая часть оператора - Checked!int
Rhs 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!int
R rhs Тип правого аргумента, участвующего в операторе
Возвращаемое значение:
Результат сравнения.
Исключения:
CheckFailure при математически ошибочном сравнении.
int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs);

Вызывается автоматически при сравнении для упорядочивания с помощью одного из операторов <, <=, >, или >=. В случае ошибочного сравнения (т.е. если отрицательное знаковое значение выглядит больше или равно положительному беззнаковому значению), выбрасывается исключение Throw.CheckFailure. В противном случае возвращается результат в трёх состояниях (положительное, если lhs > rhs, отрицательное, если lhs < rhs, 0 в противном случае).

Параметры:
Lhs lhs Первый аргумент оператора Checked, например, int, если левая часть оператора — Checked!int
Rhs 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!int
Rhs 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!int
Rhs 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!int
Rhs Тип правого аргумента, участвующего в операторе
Возвращаемое значение:
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 Оператор, участвующий в операции opAssign
Lhs Левая часть оператора (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). По сути, поведение такое:

  1. Выполнить операцию с бесконечной точностью
  2. Если результат с бесконечной точностью помещается в тип результата, вернуть его и не трогать overflow
  3. В противном случае, установить 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API