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