Переместиться к: bringToFront · copy · fill · initializeAll · move · moveAll · moveEmplace · moveEmplaceAll · moveEmplaceSome · moveSome · remove · reverse · strip · stripLeft · stripRight · swap · swapAt · swapRanges · SwapStrategy · uninitializedFill
Имя функции | Описание |
---|---|
bringToFront | Если a = [1, 2, 3] и b = [4, 5, 6, 7], bringToFront(a, b) оставит a = [4, 5, 6] и b = [7, 1, 2, 3]. |
copy | Копирует диапазон в другой. Если a = [1, 2, 3] и b = new int[5], тогда copy(a, b) оставит b = [1, 2, 3, 0, 0] и возвратит b[3 .. $]. |
fill | Заполняет диапазон образцом, например, если a = new int[3], тогда fill(a, 4) оставит a = [4, 4, 4], а fill(a, [3, 4]) оставит a = [3, 4, 3]. |
initializeAll | Если a = [1.2, 3.4], тогда initializeAll(a) оставит a = [double.init, double.init]. |
move | move(a, b) перемещает a в b. move(a) читает a разрушительно при необходимости. |
moveAll | Перемещает все элементы из одного диапазона в другой. |
moveSome | Перемещает так много элементов, сколько возможно, из одного диапазона в другой. |
remove | Удаляет элементы из диапазона на-месте и возвращает укороченный диапазон. |
reverse | Если a = [1, 2, 3], reverse(a) изменит его в [3, 2, 1]. |
strip | Удаляет все начальные и конечные элементы, равные значению, или удовлетворяющие предикату. Если a = [1, 1, 0, 1, 1], тогда strip(a, 1) и strip!(e => e == 1)(a) возвратят [0]. |
stripLeft | Удаляет все начальные элементы, равные значению, или удовлетворяющие предикату. Если a = [1, 1, 0, 1, 1], тогда stripLeft(a, 1) и stripLeft!(e => e == 1)(a) возвратят [0, 1, 1]. |
stripRight | Удаляет все конечные элементы, равные значению, или удовлетворяющие предикату. Если a = [1, 1, 0, 1, 1], тогда stripRight(a, 1) и stripRight!(e => e == 1)(a) возвратят [1, 1, 0]. |
swap | Меняет два значения. |
swapAt | Меняет два значения по индексам. |
swapRanges | Меняет все элементы двух диапазонов. |
uninitializedFill | Заполняет значением диапазон (предполагаемый неинициализированным). |
Исходный код: std/algorithm/mutation.d
bringToFront
(Range1, Range2)(Range1 front
, Range2 back
)bringToFront
довольно гибкая и полезная. Она может вращать элементы в одном буфере влево или вправо, менять буферы равной длины, и даже перемещать элементы через непересекающиеся буферы разных типов и разной длины.
bringToFront
принимает два диапазона front
и back
, которые могут быть различных типов. Рассматривая конкатенацию front
и
back
как один объединённый диапазон, bringToFront
сдвигает объединённый диапазон так, что все элементы из back
переходят в начало объединённого диапазона. Относительное упорядочение элементов в front
и back
, соответственно, остается неизменным.
Выполняется за Ο(max(front
.length, back
.length)) операций обмена.
Предварительные условия:
Либо front
и back
не пересекаются, либо back
достижима из front
, и front
не достижим из back
.
Range1 front |
входной диапазон |
Range2 back |
лидирующий диапазон |
front
, то есть, длина back
.
bringToFront
– это вращение элементов в буфере. Например:
auto arr = [4, 5, 6, 7, 1, 2, 3]; auto p = bringToFront(arr[0 .. 4], arr[4 .. $]); assert(p == arr.length - 4); assert(arr == [ 1, 2, 3, 4, 5, 6, 7 ]);
front
действительно может "переступить" диапазон back
. Это очень полезно с лидирующими диапазонами, которые не могут удобно вычислять ограниченные справа поддиапазоны, подобно arr[0 .. 4] в предыдущем примере. В примере ниже, r2 является правым поддиапазоном r1.
import std.algorithm.comparison : equal; import std.container : SList; auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3); auto r1 = list[]; auto r2 = list[]; popFrontN(r2, 4); assert(equal(r2, [ 1, 2, 3 ])); bringToFront(r1, r2); assert(equal(list[], [ 1, 2, 3, 4, 5, 6, 7 ]));
import std.algorithm.comparison : equal; import std.container : SList; auto list = SList!(int)(4, 5, 6, 7); auto vec = [ 1, 2, 3 ]; bringToFront(list[], vec); assert(equal(list[], [ 1, 2, 3, 4 ])); assert(equal(vec, [ 5, 6, 7 ]));
copy
(SourceRange, TargetRange)(SourceRange source
, TargetRange target
)copy
(SourceRange, TargetRange)(SourceRange source
, TargetRange target
)source
в цель target
и возвращает остальную (незаполненную) часть цели.
Предварительные условия:
Цель target
должна иметь достаточно места, чтобы разместить весь источник целиком.
SourceRange source |
входной диапазон |
TargetRange target |
выходной диапазон |
target
int[] a = [ 1, 5 ]; int[] b = [ 9, 8 ]; int[] buf = new int[](a.length + b.length + 10); auto rem = a.copy(buf); // копирование a в buf rem = b.copy(rem); // копирование b в оставшуюся часть buf assert(buf[0 .. a.length + b.length] == [1, 5, 9, 8]); assert(rem.length == 10); // неиспользуемое место в buf
target
поддерживают присвоение от элементов диапазона source
, принимаются различные типы диапазонов:
float[] src = [ 1.0f, 5 ]; double[] dest = new double[src.length]; src.copy(dest);
import std.range; int[] src = [ 1, 5, 8, 9, 10 ]; auto dest = new int[](3); src.take(dest.length).copy(dest); assert(dest == [ 1, 5, 8 ]);
import std.algorithm.iteration : filter; int[] src = [ 1, 5, 8, 9, 10, 1, 2, 0 ]; auto dest = new int[src.length]; auto rem = src .filter!(a => (a & 1) == 1) .copy(dest); assert(dest[0 .. $ - rem.length] == [ 1, 5, 9, 1 ]);
import std.algorithm, std.range; int[] src = [1, 2, 4]; int[] dest = [0, 0, 0, 0, 0]; src.retro.copy(dest.retro); assert(dest == [0, 0, 1, 2, 4]);
Переместиться к: 2
fill
(Range, Value)(Range range
, Value value
)range
.front = value
)));
value
каждому элементу входного диапазона range
.
Range range |
Входной диапазон, который выводит наружу ссылки на свои элементы, и его элементы поддерживают присвоение |
Value value |
Значение, присваиваемое каждому элементу диапазона |
int[] a = [ 1, 2, 3, 4 ]; fill(a, 5); assert(a == [ 5, 5, 5, 5 ]);
fill
(Range1, Range2)(Range1 range
, Range2 filler
)range
образцом, копируемым из заполнителя filler
. Длина диапазона не обязана быть кратной длине заполнителя. Если заполнитель пустой, бросается исключение.
Range1 range |
Входной диапазон, который выводит наружу ссылки на свои элементы, и его элементы поддерживают присвоение |
Range2 filler |
Лидирующий диапазон, который представляет заполняющий образец. |
int[] a = [ 1, 2, 3, 4, 5 ]; int[] b = [ 8, 9 ]; fill(a, b); assert(a == [ 8, 9, 8, 9, 8 ]);
initializeAll
(Range)(Range range
)initializeAll
(Range)(Range range
)Range range |
Входной диапазон, который выводит наружу ссылки на свои элементы, и его элементы поддерживают присвоение |
import core.stdc.stdlib : malloc, free; struct S { int a = 10; } auto s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5]; initializeAll(s); assert(s == [S(10), S(10), S(10), S(10), S(10)]); scope(exit) free(s.ptr);
move
(T)(ref T source
, ref T target
);
move
(T)(ref T source
);
source
в цель target
, через разрушающее копирование при необходимости.
source
восстанавливается в своё .init-значение после перемещения в target
, в противном случае оставляется неизменным.
Предварительные условия:
Если source
имеет внутренние указатели, которые указывают на себя, он не может быть перемещён, и будет инициирована ошибка.
T source |
Данные для копирования. |
T target |
Куда копировать. Деструктор, если имеется в наличии, вызывается перед выполнением копирования. |
move
просто выполняет target
= source
:
Object obj1 = new Object; Object obj2 = obj1; Object obj3; move(obj2, obj3); assert(obj3 is obj1); // obj2 не изменился assert(obj2 is obj1);
// Структуры без деструкторов просто копируются struct S1 { int a = 1; int b = 2; } S1 s11 = { 10, 11 }; S1 s12; move(s11, s12); assert(s12 == S1(10, 11)); assert(s11 == s12); // Но структуры с деструкторами или с postblits восстанавливают своё // .init-значение после копирования в target. struct S2 { int a = 1; int b = 2; ~this() pure nothrow @safe @nogc { } } S2 s21 = { 3, 4 }; S2 s22; move(s21, s22); assert(s21 == S2(1, 2)); assert(s22 == S2(3, 4));
struct S { @disable this(this); ~this() pure nothrow @safe @nogc {} } S s1; S s2 = move(s1);
moveEmplace
(T)(ref T source
, ref T target
);
target
неинициализирована. Это более эффективно, поскольку источник source
может быть перенесён на цель без предварительного уничтожения или инициализации.
T source |
значение, перемещаемое в target |
T target |
неинициализированное значение, которое будет заполнено источником source |
static struct Foo { pure nothrow @nogc: this(int* ptr) { _ptr = ptr; } ~this() { if (_ptr) ++*_ptr; } int* _ptr; } int val; Foo foo1 = void; // неинициализировано auto foo2 = Foo(&val); // инициализировано assert(foo2._ptr is &val); // Использование `move(foo2, foo1)` будет иметь непредсказуемый эффект, потому что вызовет деструктор // неинициализированного foo1. // moveEmplace непосредственно перезаписывает foo1, без уничтожения или инициализации его перед этим. moveEmplace(foo2, foo1); assert(foo1._ptr is &val); assert(foo2._ptr is null); assert(val == 0);
moveAll
(Range1, Range2)(Range1 src
, Range2 tgt
)src
.front, tgt
.front))));
src
и соответствующего элемента b в tgt
, в увеличивающемся порядке.
Предварительные условия:
walkLength(src
) <= walkLength(tgt
).
Это предусловие проверяется в assert. Если вы не можете гарантировать наличие достаточного пространства в
tgt
для помещения всего src
, используйте вместо этой функции moveSome.
Вот не согласен я с этим assert. Вполне реальный повод вызвать настоящее исключение. – прим. пер.
Range1 src |
Входной диапазон с перемещаемыми элементами. |
Range2 tgt |
Входной диапазон с элементами, в которые будут перемещены элементы из src . |
tgt
после перемещённых элементов из src
.int[3] a = [ 1, 2, 3 ]; int[5] b; assert(moveAll(a[], b[]) is b[3 .. $]); assert(a[] == b[0 .. 3]); int[3] cmp = [ 1, 2, 3 ]; assert(a[] == cmp[]);
moveEmplaceAll
(Range1, Range2)(Range1 src
, Range2 tgt
)src
.front, tgt
.front))));
tgt
неинициализированы. Использует moveEmplace для перемещения элементов из
src
поверх элементов в tgt
.static struct Foo { ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } int* _ptr; } int[3] refs = [0, 1, 2]; Foo[3] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2])]; Foo[5] dst = void; auto tail = moveEmplaceAll(src[], dst[]); // перемещает 3 значения из src поверх dst assert(tail.length == 2); // возвращает оставшиеся неинициализированные величины initializeAll(tail); import std.algorithm.searching : all; assert(src[].all!(e => e._ptr is null)); assert(dst[0 .. 3].all!(e => e._ptr !is null));
moveSome
(Range1, Range2)(Range1 src
, Range2 tgt
)src
.front, tgt
.front))));
src
и соответствующего элемента b в tgt
, в увеличивающемся порядке, останавливаясь, когда любой диапазон исчерпается.
Range1 src |
Входной диапазон с перемещаемыми элементами. |
Range2 tgt |
Входной диапазон с элементами, которые замещаются элементами из src . |
int[5] a = [ 1, 2, 3, 4, 5 ]; int[3] b; assert(moveSome(a[], b[])[0] is a[3 .. $]); assert(a[0 .. 3] == b); assert(a == [ 1, 2, 3, 4, 5 ]);
moveEmplaceSome
(Range1, Range2)(Range1 src
, Range2 tgt
)src
.front, tgt
.front))));
tgt
неинициализированы. Использует moveEmplace для перемещения элементов из
src
поверх элементов в tgt
.static struct Foo { ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } int* _ptr; } int[4] refs = [0, 1, 2, 3]; Foo[4] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2]), Foo(&refs[3])]; Foo[3] dst = void; auto res = moveEmplaceSome(src[], dst[]); import std.algorithm.searching : all; assert(src[0 .. 3].all!(e => e._ptr is null)); assert(src[3]._ptr !is null); assert(dst[].all!(e => e._ptr !is null));
SwapStrategy
, всегда используют SwapStrategy
.unstable по умолчанию.unstable
semistable
stable
Переместиться к: 2
remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Range range
, Offset offset
)remove
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Range range
, Offset offset
)offset
из диапазона range
и возвращает сокращённый диапазон. При самом простом вызове, удаляется один элемент.
int[] a = [ 3, 5, 7, 8 ]; assert(remove(a, 1) == [ 3, 7, 8 ]); assert(a == [ 3, 7, 8, 8 ]);В случае вверху элемент со смещением 1 удаляется, и
remove
возвращает диапазон, уменьшенный на один элемент. Исходный массив остался той же самой длины, поскольку все функции в std.algorithm измененяют только содержимое, а не топологию. Значение
8 повторилось, поскольку для перемещения элементов была задействована функция move , а при перемещении целых источник просто копируется в назначение. Чтобы заменить a эффектом удаления, просто присвойте a = remove
(a, 1). Срез будет повторно привязан к укокороченному массиву и операция завершается с максимальной эффективностью.
В remove
можно передать множество индексов. В этом случае, элементы с соответствующими индексами полностью удаляются. Индексы должны передаваться в возрастающем порядке, в противном случае вызывается исключение.
int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove(a, 1, 3, 5) == [ 0, 2, 4, 6, 7, 8, 9, 10 ]);(Заметьте, что все индексы ссылаются на места в исходном массиве, а не в массиве, который прогрессивно сокращается.) Наконец, можно передавать любую комбинацию целых смещений и кортежей, сформированных из двух целых смещений.
int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; assert(remove(a, 1, tuple(3, 5), 9) == [ 0, 2, 5, 6, 7, 8, 10 ]);В этом случае, места в позициях 1, 3, 4, и 9 удалены из массива. Кортеж передаётся в диапазон закрытым слева и открытым справа (соответствует встроенным срезам), например, tuple(3, 5) означает индексы 3 и 4, но не 5. Если необходимо удалить некоторые элементы в диапазоне, но порядок остальных элементов не обязательно сохранять, вы можете захотеть передать в
remove
параметр SwapStrategy.unstable.
int[] a = [ 0, 1, 2, 3 ]; assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);В случае выше, элемент с индексом 1 удалён, но заменён последним элементом диапазона. Воспользовавшись ослаблением требования стабильности,
remove
переместила элементы из конца массива в места, предназначенные для удаления. Таким образом, данные меньше перемещались, что улучшило время выполнения функции.
Функция remove
работает на двунаправленных диапазонах, которые содержат присваиваемые lvalue-элементы. Вот стратегия перемещения (перечислено от самой быстрой до самой медленной):
range
.popFront.s | Стратегия обмена, определяющая, необходимо ли сохранить изначальный порядок |
Range range |
Двунаправленный диапазон с примитивом длины length |
Offset offset |
какой(ие) элемент(ы) удалять |
range
после удаления offset
remove
(alias pred, SwapStrategy s = SwapStrategy.stable, Range)(Range range
)range
range
, удаляя элементы, которые удовлетворяют pred. Если s = SwapStrategy.unstable,
элементы перемещаются из правого конца на место удаляемых элементов. Если s = SwapStrategy.stable (по-умолчанию), элементы перемещаются прогрессивно к началу так, так что их относительный порядок сохраняется. Возвращает отфильтрованный диапазон.
Range range |
двунаправленный диапазон с lvalue-элементами |
static immutable base = [1, 2, 3, 2, 4, 2, 5, 2]; int[] arr = base[].dup; // использование строкового предиката assert(remove!("a == 2")(arr) == [ 1, 3, 4, 5 ]); // Оригинальное содержание массива модифицировано, // так что нам нужно восстановить его в исходное состояние. // Тем не менее, длина не изменилась. arr[] = base[]; // использование лямбда-предиката assert(remove!(a => a == 2)(arr) == [ 1, 3, 4, 5 ]);
Переместиться к: 2
reverse
(Range)(Range r
)reverse
(Range)(Range r
)r
на-месте. Выполняет r
.length / 2 операций обмена.
Range r |
двунаправленный диапазон со сменяемыми элементами или диапазон произвольным доступом со свойством длины length |
int[] arr = [ 1, 2, 3 ]; reverse(arr); assert(arr == [ 3, 2, 1 ]);
reverse
(Char)(Char[] s
)Char[] s |
узкая строка |
char[] arr = "hello\U00010143\u0100\U00010143".dup; reverse(arr); assert(arr == "\U00010143\u0100\U00010143olleh");
strip
(Range, E)(Range range
, E element
)range
.front == element
) : bool));
strip
(alias pred, Range)(Range range
)range
.back)) : bool));
stripLeft
(Range, E)(Range range
, E element
)range
.front == element
) : bool));
stripLeft
(alias pred, Range)(Range range
)range
.front)) : bool));
stripRight
(Range, E)(Range range
, E element
)range
.back == element
) : bool));
stripRight
(alias pred, Range)(Range range
)range
.back)) : bool));
strip
позволяет удалить передние, конечные, или как передние, так и конечные элементы element
.
stripLeft
зачистит переднюю сторону диапазона, функция stripRight
зачистит конечную сторону, тогда как функция strip
зачистит как переднюю, так и конечную сторону диапазона.
Заметьте, что функции strip
и stripRight
требуют, чтобы range
был Двунаправленным диапазоном.
Все эти функции имеют по две разновидности: одна принимает целевой элемент element
,
здесь диапазон зачищается до тех пор, пока этот элемент обнаруживается. Другая принимает лямбда-предикат, здесь диапазон зачищается до тех пор, пока предикат возвращает истину.
Range range |
двунаправленный или входной диапазон |
E element |
удаляемые элементы |
element
в начале и концеassert(" foobar ".strip(' ') == "foobar"); assert("00223.444500".strip('0') == "223.4445"); assert("ëëêéüŗōpéêëë".strip('ë') == "êéüŗōpéê"); assert([1, 1, 0, 1, 1].strip(1) == [0]); assert([0.0, 0.01, 0.01, 0.0].strip(0).length == 2);
true
.
assert(" foobar ".strip!(a => a == ' ')() == "foobar"); assert("00223.444500".strip!(a => a == '0')() == "223.4445"); assert("ëëêéüŗōpéêëë".strip!(a => a == 'ë')() == "êéüŗōpéê"); assert([1, 1, 0, 1, 1].strip!(a => a == 1)() == [0]); assert([0.0, 0.01, 0.5, 0.6, 0.01, 0.0].strip!(a => a < 0.4)().length == 2);
assert(" foobar ".stripLeft(' ') == "foobar "); assert("00223.444500".stripLeft('0') == "223.444500"); assert("ůůűniçodêéé".stripLeft('ů') == "űniçodêéé"); assert([1, 1, 0, 1, 1].stripLeft(1) == [0, 1, 1]); assert([0.0, 0.01, 0.01, 0.0].stripLeft(0).length == 3);
true
.
assert(" foobar ".stripLeft!(a => a == ' ')() == "foobar "); assert("00223.444500".stripLeft!(a => a == '0')() == "223.444500"); assert("ůůűniçodêéé".stripLeft!(a => a == 'ů')() == "űniçodêéé"); assert([1, 1, 0, 1, 1].stripLeft!(a => a == 1)() == [0, 1, 1]); assert([0.0, 0.01, 0.10, 0.5, 0.6].stripLeft!(a => a < 0.4)().length == 2);
assert(" foobar ".stripRight(' ') == " foobar"); assert("00223.444500".stripRight('0') == "00223.4445"); assert("ùniçodêéé".stripRight('é') == "ùniçodê"); assert([1, 1, 0, 1, 1].stripRight(1) == [1, 1, 0]); assert([0.0, 0.01, 0.01, 0.0].stripRight(0).length == 3);
true
.
assert(" foobar ".stripRight!(a => a == ' ')() == " foobar"); assert("00223.444500".stripRight!(a => a == '0')() == "00223.4445"); assert("ùniçodêéé".stripRight!(a => a == 'é')() == "ùniçodê"); assert([1, 1, 0, 1, 1].stripRight!(a => a == 1)() == [1, 1, 0]); assert([0.0, 0.01, 0.10, 0.5, 0.6].stripRight!(a => a > 0.4)().length == 3);
swap
(T)(ref T lhs
, ref T rhs
)lhs
.proxySwap(rhs
))));
swap
(T)(ref T lhs
, ref T rhs
)lhs
.proxySwap(rhs
))));
lhs
и rhs
. Экземпляры lhs
и rhs
перемещаются в памяти, никогда не вызывая ни opAssign, ни какой-либо другой функции. T
не обязан быть присваиваемым для обмена.
lhs
и rhs
– это ссылки на один и тот же экземпляр, тогда ничего не делается.
lhs
и rhs
должны быть mutable. Если T – структура или объединение, тогда все поля также должны быть mutable (рекурсивно).
T lhs |
Данные, которые нужно обменять с rhs . |
T rhs |
Данные, которые нужно обменять с lhs . |
// Обмен типов POD (простые старые данные): int a = 42, b = 34; swap(a, b); assert(a == 34 && b == 42); // Обмен структур с косвенностью: static struct S { int x; char c; int[] y; } S s1 = { 0, 'z', [ 1, 2 ] }; S s2 = { 42, 'a', [ 4, 6 ] }; swap(s1, s2); assert(s1.x == 42); assert(s1.c == 'a'); assert(s1.y == [ 4, 6 ]); assert(s2.x == 0); assert(s2.c == 'z'); assert(s2.y == [ 1, 2 ]); // Неизменняемые данные нельзя обменивать: immutable int imm1, imm2; static assert(!__traits(compiles, swap(imm1, imm2)));
// Не-копируемые типы всё ещё можно менять. static struct NoCopy { this(this) { assert(0); } int n; string s; } NoCopy nc1, nc2; nc1.n = 127; nc1.s = "abc"; nc2.n = 513; nc2.s = "uvwxyz"; swap(nc1, nc2); assert(nc1.n == 513 && nc1.s == "uvwxyz"); assert(nc2.n == 127 && nc2.s == "abc"); swap(nc1, nc1); swap(nc2, nc2); assert(nc1.n == 513 && nc1.s == "uvwxyz"); assert(nc2.n == 127 && nc2.s == "abc"); // Типы, содержащие не-копируемые поля также можно обменивать. static struct NoCopyHolder { NoCopy noCopy; } NoCopyHolder h1, h2; h1.noCopy.n = 31; h1.noCopy.s = "abc"; h2.noCopy.n = 65; h2.noCopy.s = null; swap(h1, h2); assert(h1.noCopy.n == 65 && h1.noCopy.s == null); assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); swap(h1, h1); swap(h2, h2); assert(h1.noCopy.n == 65 && h1.noCopy.s == null); assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); // Типы с const нельзя обменивать. const NoCopy const1, const2; static assert(!__traits(compiles, swap(const1, const2)));
swapAt
(R)(auto ref R r
, size_t i1
, size_t i2
);
r
два элемента, определённых своими индексами i1
и i2
.
R r |
диапазон с обмениваемыми элементами |
size_t i1 |
первый индекс |
size_t i2 |
второй индекс |
import std.algorithm.comparison : equal; auto a = [1, 2, 3]; a.swapAt(1, 2); assert(a.equal([1, 3, 2]));
swapRanges
(Range1, Range2)(Range1 r1
, Range2 r2
)r1
с элементами в r2
.
Возвращает кортеж, содержащий оставшиеся части r1
и r2
, которые не были заменены (один из них будет пустым). Диапазоны могут быть разных типов, но должны иметь один и тот же тип элементов, и поддерживать обмен.
Range1 r1 |
входной диапазон с обмениваемыми элементами |
Range2 r2 |
входной диапазон с обмениваемыми элементами |
r1
и r2
, которые не были замененыint[] a = [ 100, 101, 102, 103 ]; int[] b = [ 0, 1, 2, 3 ]; auto c = swapRanges(a[1 .. 3], b[2 .. 4]); assert(c[0].empty && c[1].empty); assert(a == [ 100, 2, 3, 103 ]); assert(b == [ 0, 1, 101, 102 ]);
uninitializedFill
(Range, Value)(Range range
, Value value
)range
.front = value
)));
value
.
Предполагает, что элементы диапазона неинициализированны. Это представляет интерес для структур, которые определяют конструкторы копирования (для всех остальных типов, fill и
uninitializedFill
эквивалентны).
Range range |
Входной диапазон, который выводит наружу ссылки на свои элементы и содержит присваиваемые элементы |
Value value |
Присваивается каждому элементу диапазона |
import core.stdc.stdlib : malloc, free; auto s = (cast(int*) malloc(5 * int.sizeof))[0 .. 5]; uninitializedFill(s, 42); assert(s == [ 42, 42, 42, 42, 42 ]); scope(exit) free(s.ptr);