Spec-Zone.ru › D

std.range.primitives

Этот модуль является подмодулем std.range.

Он определяет двунаправленные и однонаправленные примитивы диапазонов для массивов: empty, front, back, popFront, popBack и save.

Он предоставляет базовые функциональные возможности диапазонов, определяя несколько шаблонов для проверки, является ли данный объект диапазоном и какого типа диапазоном он является:

isInputRange Проверяет, является ли что-то диапазоном ввода, определённым как что-то, из чего можно последовательно читать данные с помощью примитивов front, popFront, и empty.
isOutputRange Проверяет, является ли что-то диапазоном вывода, определённым как что-то, в которое можно последовательно записывать данные с использованием примитива put.
isForwardRange Проверяет, является ли что-то диапазоном прямого доступа, определённым как диапазон ввода с дополнительной возможностью сохранения текущей позиции с помощью примитива save, что позволяет многократно итерироваться по одному и тому же диапазону.
isBidirectionalRange Проверяет, является ли что-то двунаправленным диапазоном, то есть диапазоном прямого доступа, который позволяет обратное прохождение с использованием примитивов back и popBack.
isRandomAccessRange Проверяет, является ли что-то диапазоном произвольного доступа, который представляет собой двунаправленный диапазон, также поддерживающий операцию индексирования массива с помощью примитива opIndex.


Он также предоставляет ряд шаблонов, проверяющих различные возможности диапазонов:

hasMobileElements Проверяет, можно ли перемещать элементы данного диапазона с помощью примитивов moveFront, moveBack, или moveAt.
ElementType Возвращает тип элемента данного диапазона.
ElementEncodingType Возвращает тип кодирования элемента данного диапазона.
hasSwappableElements Проверяет, является ли диапазон диапазоном прямого доступа с взаимозаменяемыми элементами.
hasAssignableElements Проверяет, является ли диапазон диапазоном прямого доступа с изменяемыми элементами.
hasLvalueElements Проверяет, является ли диапазон диапазоном прямого доступа с элементами, которые можно передавать по ссылке и у которых можно получить адрес.
hasLength Проверяет, обладает ли данный диапазон атрибутом length.
isInfinite Проверяет, является ли данный диапазон бесконечным диапазоном.
hasSlicing Проверяет, поддерживает ли данный диапазон операцию нарезки массива R[x .. y].


Наконец, он включает некоторые удобные функции для работы с диапазонами:

popFrontN Перемещает данный диапазон вперёд на n элементов.
popBackN Перемещает данный двунаправленный диапазон вправо на n элементов.
popFrontExactly Перемещает данный диапазон вперёд ровно на n элементов.
popBackExactly Перемещает данный двунаправленный диапазон вправо ровно на n элементов.
moveFront Удаляет первый элемент диапазона.
moveBack Удаляет последний элемент двунаправленного диапазона.
moveAt Удаляет i-й элемент диапазона произвольного доступа.
walkLength Вычисляет длину любого диапазона за время O(n).
put Выводит элемент e в диапазон.

Источник
std/range/primitives.d
Лицензия:
Boost License 1.0.
Авторы:
Andrei Alexandrescu, David Simcha, и Jonathan M Davis. Некоторые идеи для построения этого модуля были предложены Leonardo Maffi.
enum bool isInputRange(R);

Возвращает true если R является диапазоном ввода. Диапазон ввода должен определять примитивы empty, popFront, и front. Следующий код должен компилироваться для любого диапазона ввода.

R r;              // can define a range object
if (r.empty) {}   // can test for empty
r.popFront();     // can invoke popFront()
auto h = r.front; // can get the front of the range of non-void type


Ниже приведены правила диапазонов ввода, которые предполагаются истинными во всем коде Phobos. Эти правила не проверяются на этапе компиляции, поэтому несоблюдение этих правил при написании диапазонов или кода, основанного на диапазонах, приведет к неопределенному поведению.

  • r.empty возвращает false только тогда, когда в диапазоне доступны дополнительные данные.
  • r.empty вычисляется несколько раз без вызова r.popFront, или иначе не изменяя объект диапазона или лежащие в основе данные, дает один и тот же результат при каждом вычислении.
  • r.front возвращает текущий элемент в диапазоне. Он может возвращать по значению или по ссылке.
  • r.front может быть законно вычислен, если и только если вычисление r.empty равно или равно false.
  • r.front вычисляется несколько раз без вызова r.popFront, или иначе не изменяя объект диапазона или лежащие в основе данные, дает один и тот же результат при каждом вычислении.
  • r.popFront переходит к следующему элементу в диапазоне.
  • r.popFront может быть вызван, если и только если вычисление r.empty равно или равно false.


Кроме того, обратите внимание, что код Phobos предполагает, что примитивы r.front и r.empty имеют сложность Ο(1) или «дешевые» с точки зрения времени выполнения. Выражения Ο() в документации функций диапазона делаются с этим предположением.

См. также:
Заголовок std.range для руководств по диапазонам.
Параметры:
R тип для проверки
Возвращает:
true если R является диапазоном ввода, false если нет
Примеры:
struct A {}
struct B
{
    void popFront();
    @property bool empty();
    @property int front();
}
static assert(!isInputRange!A);
static assert( isInputRange!B);
static assert( isInputRange!(int[]));
static assert( isInputRange!(char[]));
static assert(!isInputRange!(char[4]));
static assert( isInputRange!(inout(int)[]));

static struct NotDefaultConstructible
{
    @disable this();
    void popFront();
    @property bool empty();
    @property int front();
}
static assert( isInputRange!NotDefaultConstructible);

static struct NotDefaultConstructibleOrCopyable
{
    @disable this();
    @disable this(this);
    void popFront();
    @property bool empty();
    @property int front();
}
static assert(isInputRange!NotDefaultConstructibleOrCopyable);

static struct Frontless
{
    void popFront();
    @property bool empty();
}
static assert(!isInputRange!Frontless);

static struct VoidFront
{
    void popFront();
    @property bool empty();
    void front();
}
static assert(!isInputRange!VoidFront);
void put(R, E)(ref R r, E e);

Выводит e в r. Точный эффект зависит от двух типов. Принимаются несколько случаев, как описано ниже. Сценарии обрабатываются в порядке, и первый, который скомпилируется, "выигрывает" и оценивается.

В этой таблице «doPut» — метод, помещающий e в r, используя правильный примитив: r.put(e) если R определяет put, r.front = e если r является диапазоном ввода (после r.popFront() или r(e) в противном случае.

Фрагмент кода Сценарий
r.doPut(e); R конкретно принимает E.
r.doPut([ e ]); R конкретно принимает E[].
r.putChar(e); R принимает какую-либо форму строки или символа. put будет транскодировать символ e соответственно.
for (; !e.empty; e.popFront()) put(r, e.front); Копирование диапазона E в R.

Подсказка
put не следует использовать в стиле «UFCS», например r.put(e). Это может вызвать R.put непосредственно, минуя любые функции преобразования, предоставляемые Range.put. Предпочтительнее put(r, e).
Примеры:
Когда метод put диапазона вывода принимает только элементы типа T, используйте глобальную функцию put для обработки вывода T[] в диапазон или наоборот.
import std.traits : isSomeChar;

static struct A
{
    string data;

    void put(C)(C c) if (isSomeChar!C)
    {
        data ~= c;
    }
}
static assert(isOutputRange!(A, char));

auto a = A();
put(a, "Hello");
writeln(a.data); // "Hello"
Примеры:
Динамические массивы рассматриваются как срезы массивов и вызовут popFront для среза после копирования элемента. Не забудьте сохранить положение массива перед вызовом put.
int[] a = [1, 2, 3], b = [10, 20];
auto c = a;
put(a, b);
writeln(c); // [10, 20, 3]
// at this point, a was advanced twice, so it only contains
// its last element while c represents the whole array
writeln(a); // [3]
Примеры:
Также возможно транскодировать символы любой ширины или строки в узкие строки — put выполняет преобразование за вас. Обратите внимание, что вывод символа той же ширины, что и целевой тип буфера, является nothrow, но транскодирование может вызвать std.utf.UTFException.
// the elements must be mutable, so using string or const(char)[]
// won't compile
char[] s1 = new char[13];
auto r1 = s1;
put(r1, "Hello, World!"w);
writeln(s1); // "Hello, World!"
enum bool isOutputRange(R, E);

Возвращает true если R является диапазоном вывода для элементов типа E. Диапазон вывода функционально определяется как диапазон, поддерживающий операцию put(r, e), как определено выше.

См. также:
Заголовок std.range для руководств по диапазонам.
Примеры:
void myprint(scope const(char)[] s) { }
static assert(isOutputRange!(typeof(&myprint), char));

static assert( isOutputRange!(char[], char));
static assert( isOutputRange!(dchar[], wchar));
static assert( isOutputRange!(dchar[], dchar));
enum bool isForwardRange(R);

Возвращает true если R является диапазоном вперед. Диапазон вперед является диапазоном ввода r, который может сохранять «точки останова», сохраняя r.save в другое значение типа R. Примечательными примерами диапазонов ввода, которые не являются диапазонами вперед, являются диапазоны файлов/сокет; копирование такого диапазона не сохранит позицию в потоке, и они, скорее всего, повторно используют внутренний буфер, поскольку весь поток не находится в памяти. Соответственно, продвижение либо оригинала, либо копии продвинет поток, поэтому копии не являются независимыми.

Следующий код должен компилироваться для любого диапазона вперед.

static assert(isInputRange!R);
R r1;
auto s1 = r1.save;
static assert(is(typeof(s1) == R));


Сохранение диапазона не дублирует его; в приведенном выше примере r1 и r2 все еще ссылаются на одни и те же данные. Они просто независимо перемещаются по этим данным.

Семантика диапазона вперед (не проверяемая во время компиляции) такая же, как и для диапазона ввода, с дополнительным требованием, что обратный переход должен быть возможен путем сохранения копии объекта диапазона с save и последующим использованием.

См. также:
Заголовок std.range для руководств по диапазонам.
Примеры:
static assert(!isForwardRange!(int));
static assert( isForwardRange!(int[]));
static assert( isForwardRange!(inout(int)[]));
enum bool isBidirectionalRange(R);

Возвращает true если R является двунаправленным диапазоном. Двунаправленный диапазон — это диапазон вперед, который также предлагает примитивы back и popBack. Следующий код должен компилироваться для любого двунаправленного диапазона.

Семантика двунаправленного диапазона (не проверяемая во время компиляции) предполагается следующей (r — объект типа R):

  • r.back возвращает (возможно, ссылку на) последний элемент в диапазоне. Вызов r.back разрешен только в том случае, если вызов r.empty вернул false.

См. также:
Заголовок std.range для руководств по диапазонам.
Примеры:
alias R = int[];
R r = [0,1];
static assert(isForwardRange!R);           // is forward range
r.popBack();                               // can invoke popBack
auto t = r.back;                           // can get the back of the range
auto w = r.front;
static assert(is(typeof(t) == typeof(w))); // same type for front and back
enum bool isRandomAccessRange(R);

Возвращает true если R является диапазоном произвольного доступа. Диапазон произвольного доступа — это двунаправленный диапазон, который также предлагает примитив opIndex, ИЛИ бесконечный диапазон вперед, который предлагает opIndex. В любом случае, диапазон должен либо предлагать length, либо быть бесконечным. Следующий код должен компилироваться для любого диапазона произвольного доступа.

Семантика диапазона произвольного доступа (не проверяемая во время компиляции) предполагается следующей (r — объект типа R):

  • r.opIndex(n) возвращает ссылку на n-й элемент в диапазоне.


Хотя char[] и wchar[] (а также их квалифицированные версии, включая string и wstring) являются массивами, isRandomAccessRange возвращает false для них, потому что они используют кодировки переменной длины (UTF-8 и UTF-16 соответственно). Эти типы являются только двунаправленными диапазонами.

См. также:
Заголовок std.range для руководств по диапазонам.
Примеры:
import std.traits : isAggregateType, isAutodecodableString;

alias R = int[];

// range is finite and bidirectional or infinite and forward.
static assert(isBidirectionalRange!R ||
              isForwardRange!R && isInfinite!R);

R r = [0,1];
auto e = r[1]; // can index
auto f = r.front;
static assert(is(typeof(e) == typeof(f))); // same type for indexed and front
static assert(!(isAutodecodableString!R && !isAggregateType!R)); // narrow strings cannot be indexed as ranges
static assert(hasLength!R || isInfinite!R); // must have length or be infinite

// $ must work as it does with arrays if opIndex works with $
static if (is(typeof(r[$])))
{
    static assert(is(typeof(f) == typeof(r[$])));

    // $ - 1 doesn't make sense with infinite ranges but needs to work
    // with finite ones.
    static if (!isInfinite!R)
        static assert(is(typeof(f) == typeof(r[$ - 1])));
}
enum bool hasMobileElements(R);

Возвращает true если R является диапазоном ввода, поддерживающим примитив moveFront, а также moveBack и moveAt, если это двунаправленный или диапазон произвольного доступа. Они могут быть явно реализованы или могут работать через стандартное поведение модульных функций moveFront и др. Следующий код должен компилироваться для любого диапазона с подвижными элементами.

alias E = ElementType!R;
R r;
static assert(isInputRange!R);
static assert(is(typeof(moveFront(r)) == E));
static if (isBidirectionalRange!R)
    static assert(is(typeof(moveBack(r)) == E));
static if (isRandomAccessRange!R)
    static assert(is(typeof(moveAt(r, 0)) == E));

Примеры:
import std.algorithm.iteration : map;
import std.range : iota, repeat;

static struct HasPostblit
{
    this(this) {}
}

auto nonMobile = map!"a"(repeat(HasPostblit.init));
static assert(!hasMobileElements!(typeof(nonMobile)));
static assert( hasMobileElements!(int[]));
static assert( hasMobileElements!(inout(int)[]));
static assert( hasMobileElements!(typeof(iota(1000))));

static assert( hasMobileElements!( string));
static assert( hasMobileElements!(dstring));
static assert( hasMobileElements!( char[]));
static assert( hasMobileElements!(dchar[]));
template ElementType(R)

Тип элемента R. R не обязательно должен быть диапазоном. Тип элемента определяется как тип, возвращаемый r.front для объекта r типа R. Например, ElementType!(T[]) является T если T[] не является узкой строкой; если это так, то тип элемента — dchar. Если R не имеет front, то ElementType!R является void.

Примеры:
import std.range : iota;

// Standard arrays: returns the type of the elements of the array
static assert(is(ElementType!(int[]) == int));

// Accessing .front retrieves the decoded dchar
static assert(is(ElementType!(char[])  == dchar)); // rvalue
static assert(is(ElementType!(dchar[]) == dchar)); // lvalue

// Ditto
static assert(is(ElementType!(string) == dchar));
static assert(is(ElementType!(dstring) == immutable(dchar)));

// For ranges it gets the type of .front.
auto range = iota(0, 10);
static assert(is(ElementType!(typeof(range)) == int));
template ElementEncodingType(R)

Тип кодирования элемента R. Для узких строк (char[], wchar[] и их квалифицированные варианты, включая string и wstring), ElementEncodingType является типом символа строки. Для всех остальных типов, ElementEncodingType совпадает с ElementType.

Примеры:
import std.range : iota;
// internally the range stores the encoded type
static assert(is(ElementEncodingType!(char[])  == char));

static assert(is(ElementEncodingType!(wstring) == immutable(wchar)));

static assert(is(ElementEncodingType!(byte[]) == byte));

auto range = iota(0, 10);
static assert(is(ElementEncodingType!(typeof(range)) == int));
enum bool hasSwappableElements(R);

Возвращает true если R является диапазоном ввода и содержит элементы, допускающие обмен. Следующий код должен компилироваться для любого диапазона с элементами, допускающими обмен.

R r;
static assert(isInputRange!R);
swap(r.front, r.front);
static if (isBidirectionalRange!R) swap(r.back, r.front);
static if (isRandomAccessRange!R) swap(r[0], r.front);

Примеры:
static assert(!hasSwappableElements!(const int[]));
static assert(!hasSwappableElements!(const(int)[]));
static assert(!hasSwappableElements!(inout(int)[]));
static assert( hasSwappableElements!(int[]));

static assert(!hasSwappableElements!( string));
static assert(!hasSwappableElements!(dstring));
static assert(!hasSwappableElements!( char[]));
static assert( hasSwappableElements!(dchar[]));
enum bool hasAssignableElements(R);

Возвращает true если R является диапазоном ввода и содержит изменяемые элементы. Следующий код должен компилироваться для любого диапазона с присваиваемыми элементами.

R r;
static assert(isInputRange!R);
r.front = r.front;
static if (isBidirectionalRange!R) r.back = r.front;
static if (isRandomAccessRange!R) r[0] = r.front;

Примеры:
static assert(!hasAssignableElements!(const int[]));
static assert(!hasAssignableElements!(const(int)[]));
static assert( hasAssignableElements!(int[]));
static assert(!hasAssignableElements!(inout(int)[]));

static assert(!hasAssignableElements!( string));
static assert(!hasAssignableElements!(dstring));
static assert(!hasAssignableElements!( char[]));
static assert( hasAssignableElements!(dchar[]));
enum bool hasLvalueElements(R);

Проверяет, содержит ли диапазон R элементы типа lvalue. Эти элементы определяются как элементы, которые можно передавать по ссылке и для которых можно взять адрес. Следующий код должен компилироваться для любого диапазона с элементами типа lvalue.

void passByRef(ref ElementType!R stuff);
...
static assert(isInputRange!R);
passByRef(r.front);
static if (isBidirectionalRange!R) passByRef(r.back);
static if (isRandomAccessRange!R) passByRef(r[0]);

template hasLength(R)

Возвращает true если R имеет член length, который возвращает значение типа size_t. R не обязательно должен быть диапазоном. Если R является диапазоном, алгоритмы стандартной библиотеки гарантируют поддержку length с типом size_t.

Обратите внимание, что length является необязательным примитивом, так как ни один диапазон не обязан его реализовывать. Некоторые диапазоны не хранят свою длину явно, некоторые не могут вычислить её без полного перебора диапазона (например, потоки сокетов), а некоторые диапазоны могут быть бесконечными.

Хотя типы узких строк (char[], wchar[], и их квалифицированные производные) определяют свойство length, hasLength возвращает false для них. Это связано с тем, что длина узкой строки не отражает количество символов, а количество единиц кодирования, и поэтому не полезна при использовании алгоритмов, ориентированных на диапазоны. Для использования строк в качестве диапазонов с произвольным доступом и длиной используйте std.string.representation или std.utf.byCodeUnit.

Примеры:
static assert(!hasLength!(char[]));
static assert( hasLength!(int[]));
static assert( hasLength!(inout(int)[]));

struct A { size_t length() { return 0; } }
struct B { @property size_t length() { return 0; } }
static assert( hasLength!(A));
static assert( hasLength!(B));
template isInfinite(R)

Возвращает true если R является бесконечным диапазоном ввода. Бесконечный диапазон ввода — это диапазон ввода, который имеет статически определённый перечисленный член, называемый empty, который всегда равен false, например:

struct MyInfiniteRange
{
    enum bool empty = false;
    ...
}

Примеры:
import std.range : Repeat;
static assert(!isInfinite!(int[]));
static assert( isInfinite!(Repeat!(int)));
enum bool hasSlicing(R);

Возвращает true если R поддерживает оператор среза с целочисленными границами, который возвращает тип диапазона вперёд.

Для конечных диапазонов результат opSlice должен быть того же типа, что и исходный тип диапазона. Если диапазон определяет opDollar, то он должен поддерживать вычитание.

Для бесконечных диапазонов, когда не используется opDollar, результат opSlice должен быть результатом take или takeExactly над исходным диапазоном (они оба возвращают тот же тип для бесконечных диапазонов). Однако при использовании opDollar, результат opSlice должен быть того же типа, что и исходный диапазон.

Следующее выражение должно быть истинным, чтобы hasSlicing было true:

    isForwardRange!R
    && !isNarrowString!R
    && is(ReturnType!((R r) => r[1 .. 1].length) == size_t)
    && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R)
    && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R))
    && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R
        || is(typeof(lvalueOf!R[0 .. $ - 1]) == R))
    && is(typeof((ref R r)
    {
        static assert(isForwardRange!(typeof(r[1 .. 2])));
    }));

Примеры:
import std.range : takeExactly;
static assert( hasSlicing!(int[]));
static assert( hasSlicing!(const(int)[]));
static assert(!hasSlicing!(const int[]));
static assert( hasSlicing!(inout(int)[]));
static assert(!hasSlicing!(inout int []));
static assert( hasSlicing!(immutable(int)[]));
static assert(!hasSlicing!(immutable int[]));
static assert(!hasSlicing!string);
static assert( hasSlicing!dstring);

enum rangeFuncs = "@property int front();" ~
                  "void popFront();" ~
                  "@property bool empty();" ~
                  "@property auto save() { return this; }" ~
                  "@property size_t length();";

struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); }
struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); }
struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); }
struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); }
static assert(!hasSlicing!(A));
static assert( hasSlicing!(B));
static assert( hasSlicing!(C));
static assert(!hasSlicing!(D));

struct InfOnes
{
    enum empty = false;
    void popFront() {}
    @property int front() { return 1; }
    @property InfOnes save() { return this; }
    auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); }
    auto opSlice(size_t i, Dollar d) { return this; }

    struct Dollar {}
    Dollar opDollar() const { return Dollar.init; }
}

static assert(hasSlicing!InfOnes);
auto walkLength(Range)(Range range)
Ограничения: если (isInputRange!Range && !isInfinite!Range);

auto walkLength(Range)(Range range, const size_t upTo)
Ограничения: если (isInputRange!Range);

Это реализация length для любого типа диапазона.

Если hasLength!Range, просто возвращает range.length без проверки upTo (если указано).

В противном случае, перебирает диапазон по его длине и возвращает количество пройденных элементов. Выполняет Ο(n) вычислений range.empty и range.popFront(), где n — эффективная длина range.

Параметр upTo полезен для «прекращения потерь», если нужно проверить, содержит ли диапазон хотя бы определённое количество элементов. Если параметр upTo указан, останавливается, если выполнено upTo шагов и возвращает upTo.

Бесконечные диапазоны совместимы, при условии, что указан параметр upTo, в этом случае реализация просто возвращает upTo.

Примеры:
import std.range : iota;

writeln(10.iota.walkLength); // 10
// iota has a length function, and therefore the
// doesn't have to be walked, and the upTo
// parameter is ignored
writeln(10.iota.walkLength(5)); // 10
size_t popFrontN(Range)(ref Range r, size_t n)
Ограничения: если (isInputRange!Range);

size_t popBackN(Range)(ref Range r, size_t n)
Ограничения: если (isBidirectionalRange!Range);

popFrontN жадно продвигает r (не копию) до n раз (вызывая r.popFront). popFrontN принимает r по ref, поэтому изменяет исходный диапазон. Завершается за Ο(1) шагов для диапазонов, поддерживающих срез и имеющих длину. Завершается за Ο(n) времени для всех остальных диапазонов.

popBackN ведет себя так же, как popFrontN, но удаляет элементы с конца (двунаправленного) диапазона вместо начала.

Возвращает:
Сколько r было фактически продвинуто, что может быть меньше n, если r не содержал по крайней мере n элементов.
См. также:
std.range.drop, std.range.dropBack
Примеры:
int[] a = [ 1, 2, 3, 4, 5 ];
a.popFrontN(2);
writeln(a); // [3, 4, 5]
a.popFrontN(7);
writeln(a); // []
Примеры:
import std.algorithm.comparison : equal;
import std.range : iota;
auto LL = iota(1L, 7L);
auto r = popFrontN(LL, 2);
assert(equal(LL, [3L, 4L, 5L, 6L]));
writeln(r); // 2
Примеры:
int[] a = [ 1, 2, 3, 4, 5 ];
a.popBackN(2);
writeln(a); // [1, 2, 3]
a.popBackN(7);
writeln(a); // []
Примеры:
import std.algorithm.comparison : equal;
import std.range : iota;
auto LL = iota(1L, 7L);
auto r = popBackN(LL, 2);
assert(equal(LL, [1L, 2L, 3L, 4L]));
writeln(r); // 2
void popFrontExactly(Range)(ref Range r, size_t n)
Ограничения: если (isInputRange!Range);

void popBackExactly(Range)(ref Range r, size_t n)
Ограничения: если (isBidirectionalRange!Range);

Жадно продвигает r (не копию) ровно на n раз (вызывая r.popFront). popFrontExactly принимает r по ref, поэтому изменяет исходный диапазон. Завершается за Ο(1) шагов для диапазонов, поддерживающих срез и имеющих длину или являющихся бесконечными. Завершается за Ο(n) времени для всех остальных диапазонов.

Примечание
В отличие от popFrontN, popFrontExactly предполагает, что диапазон содержит по крайней мере n элементов. Это делает popFrontExactly быстрее, чем popFrontN, но также означает, что если range не содержит по крайней мере n элементов, он попытается вызвать popFront на пустом диапазоне, что является неопределённым поведением. Поэтому используйте popFrontExactly только в том случае, если гарантируется, что range содержит по крайней мере n элементов.
popBackExactly будет вести себя аналогично, но удалит элементы с конца (двунаправленного) диапазона вместо начала.
См. также:
std.range.dropExactly, std.range.dropBackExactly
Примеры:
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filterBidirectional;

auto a = [1, 2, 3];
a.popFrontExactly(1);
writeln(a); // [2, 3]
a.popBackExactly(1);
writeln(a); // [2]

string s = "日本語";
s.popFrontExactly(1);
writeln(s); // "本語"
s.popBackExactly(1);
writeln(s); // "本"

auto bd = filterBidirectional!"true"([1, 2, 3]);
bd.popFrontExactly(1);
assert(bd.equal([2, 3]));
bd.popBackExactly(1);
assert(bd.equal([2]));
ElementType!R moveFront(R)(R r);

Выталкивает элемент с начала r и возвращает его. Оставляет r.front в разрушаемом состоянии, которое не выделяет ресурсы (обычно равно его значению .init).

Примеры:
auto a = [ 1, 2, 3 ];
writeln(moveFront(a)); // 1
writeln(a.length); // 3

// define a perfunctory input range
struct InputRange
{
    enum bool empty = false;
    enum int front = 7;
    void popFront() {}
    int moveFront() { return 43; }
}
InputRange r;
// calls r.moveFront
writeln(moveFront(r)); // 43
ElementType!R moveBack(R)(R r);

Выталкивает элемент с конца r и возвращает его. Оставляет r.back в разрушаемом состоянии, которое не выделяет ресурсы (обычно равно его значению .init).

Примеры:
struct TestRange
{
    int payload = 5;
    @property bool empty() { return false; }
    @property TestRange save() { return this; }
    @property ref int front() return { return payload; }
    @property ref int back() return { return payload; }
    void popFront() { }
    void popBack() { }
}
static assert(isBidirectionalRange!TestRange);
TestRange r;
auto x = moveBack(r);
writeln(x); // 5
ElementType!R moveAt(R)(R r, size_t i);

Выталкивает элемент с индексом i в r и возвращает его. Оставляет r[i] в разрушаемом состоянии, которое не выделяет ресурсы (обычно равно его значению .init).

Примеры:
auto a = [1,2,3,4];
foreach (idx, it; a)
{
    writeln(it); // moveAt(a, idx)
}
@property bool empty(T)(auto ref scope T a)
Ограничения: если (is(typeof(a.length) : size_t));

Реализует примитив интерфейса диапазона empty для типов, которые подчиняются свойству hasLength и для узких строк. Из-за того, что нечлены функции могут вызываться с первым аргументом с использованием точки, a.empty эквивалентно empty(a).

Примеры:
auto a = [ 1, 2, 3 ];
assert(!a.empty);
assert(a[3 .. $].empty);

int[string] b;
assert(b.empty);
b["zero"] = 0;
assert(!b.empty);
pure nothrow @nogc @property @safe inout(T)[] save(T)(return scope inout(T)[] a);

Реализует примитив интерфейса диапазона save для встроенных массивов. Из-за того, что нестатические функции могут вызываться с первым аргументом с использованием нотации точки, array.save эквивалентно save(array). Функция не дублирует содержимое массива, она просто возвращает свой аргумент.

Примеры:
auto a = [ 1, 2, 3 ];
auto b = a.save;
assert(b is a);
pure nothrow @nogc @safe void popFront(T)(ref scope inout(T)[] a)
Constraints: if (!isAutodecodableString!(T[]) && !is(T[] == void[]));

pure nothrow @trusted void popFront(C)(ref scope inout(C)[] str)
Constraints: if (isAutodecodableString!(C[]));

Реализует примитив интерфейса диапазона popFront для встроенных массивов. Из-за того, что нестатические функции могут вызываться с первым аргументом с использованием нотации точки, array.popFront эквивалентно popFront(array). Для узких строк, popFront автоматически переходит к следующему кодовому пункту.

Примеры:
auto a = [ 1, 2, 3 ];
a.popFront();
writeln(a); // [2, 3]
pure nothrow @nogc @safe void popBack(T)(ref scope inout(T)[] a)
Constraints: if (!isAutodecodableString!(T[]) && !is(T[] == void[]));

pure @safe void popBack(T)(ref scope inout(T)[] a)
Constraints: if (isAutodecodableString!(T[]));

Реализует примитив интерфейса диапазона popBack для встроенных массивов. Из-за того, что нестатические функции могут вызываться с первым аргументом с использованием нотации точки, array.popBack эквивалентно popBack(array). Для узких строк, popFront автоматически удаляет последний кодовый пункт.

Примеры:
auto a = [ 1, 2, 3 ];
a.popBack();
writeln(a); // [1, 2]
enum bool autodecodeStrings;
ЭКСПЕРИМЕНТАЛЬНО
чтобы попробовать отключить автодекодирование, установите версию NoAutodecodeStrings. В настоящее время ожидается, что большинство вещей с этой версией не будут работать.
pure nothrow @nogc @property ref @safe inout(T) front(T)(return scope inout(T)[] a)
Constraints: if (!isAutodecodableString!(T[]) && !is(T[] == void[]));

pure @property @safe dchar front(T)(scope const(T)[] a)
Constraints: if (isAutodecodableString!(T[]));

Реализует примитив интерфейса диапазона front для встроенных массивов. Из-за того, что нестатические функции могут вызываться с первым аргументом с использованием нотации точки, array.front эквивалентно front(array). Для узких строк, front автоматически возвращает первый кодовый пункт как dchar.

Примеры:
int[] a = [ 1, 2, 3 ];
writeln(a.front); // 1
pure nothrow @nogc @property ref @safe inout(T) back(T)(return scope inout(T)[] a)
Constraints: if (!isAutodecodableString!(T[]) && !is(T[] == void[]));

pure @property @safe dchar back(T)(scope const(T)[] a)
Constraints: if (isAutodecodableString!(T[]));

Реализует примитив интерфейса диапазона back для встроенных массивов. Из-за того, что нестатические функции могут вызываться с первым аргументом с использованием нотации точки, array.back эквивалентно back(array). Для узких строк, back автоматически возвращает последний кодовый пункт как dchar.

Примеры:
int[] a = [ 1, 2, 3 ];
writeln(a.back); // 3
a.back += 4;
writeln(a.back); // 7

© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_range_primitives.html

Spec-Zone.ru

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