| Function Name | Description |
|---|---|
| bringToFront | Ifa = [1, 2, 3] andb = [4, 5, 6, 7],bringToFront(a, b) leavesa = [4, 5, 6] andb = [7, 1, 2, 3]. |
| copy | Copies a range to another. Ifa = [1, 2, 3] andb = new int[5], thencopy(a, b) leavesb = [1, 2, 3, 0, 0] and returnsb[3 .. $]. |
| fill | Fills a range with a pattern, e.g., ifa = new int[3], thenfill(a, 4) leavesa = [4, 4, 4] andfill(a, [3, 4]) leavesa = [3, 4, 3]. |
| initializeAll | Ifa = [1.2, 3.4], theninitializeAll(a) leavesa = [double.init, double.init]. |
| move | move(a, b) movesa intob.move(a) readsa destructively when necessary. |
| moveEmplace | Similar tomove but assumestarget is uninitialized. |
| moveAll | Moves all elements from one range to another. |
| moveEmplaceAll | Similar tomoveAll but assumes all elements intarget are uninitialized. |
| moveSome | Moves as many elements as possible from one range to another. |
| moveEmplaceSome | Similar tomoveSome but assumes all elements intarget are uninitialized. |
| remove | Removes elements from a range in-place, and returns the shortened range. |
| reverse | Ifa = [1, 2, 3],reverse(a) changes it to[3, 2, 1]. |
| strip | Strips all leading and trailing elements equal to a value, or that satisfy a predicate. Ifa = [1, 1, 0, 1, 1], thenstrip(a, 1) andstrip!(e => e == 1)(a) returns[0]. |
| stripLeft | Strips all leading elements equal to a value, or that satisfy a predicate. Ifa = [1, 1, 0, 1, 1], thenstripLeft(a, 1) andstripLeft!(e => e == 1)(a) returns[0, 1, 1]. |
| stripRight | Strips all trailing elements equal to a value, or that satisfy a predicate. Ifa = [1, 1, 0, 1, 1], thenstripRight(a, 1) andstripRight!(e => e == 1)(a) returns[1, 1, 0]. |
| swap | Swaps two values. |
| swapAt | Swaps two values by indices. |
| swapRanges | Swaps all elements of two ranges. |
| uninitializedFill | Fills a range (assumed uninitialized) with a value. |
Sourcestd/algorithm/mutation.d
bringToFront(InputRange, ForwardRange)(InputRangefront, ForwardRangeback)bringToFront takes two rangesfront andback, which maybe of different types. Considering the concatenation offront andback one unified range,bringToFront rotates that unifiedrange such that all elements inback are brought to the beginningof the unified range. The relative ordering of elements infrontandback, respectively, remains unchanged.bringToFront function treats strings at the code unitlevel and it is not concerned with Unicode character integrity.bringToFront is designed as a function for moving elementsin ranges, not as a string function.PerformsΟ(max(front.length, back.length)) evaluations ofswap.ThebringToFront function can rotate elements in one buffer left or right, swapbuffers of equal length, and even move elements across disjointbuffers of different types and different lengths.PreconditionsEitherfront andback are disjoint, orback isreachable fromfront andfront is not reachable fromback.
InputRangefront | aninput range |
ForwardRangeback | aforward range |
back.bringToFront is for rotating elements in abuffer. For example:auto arr = [4, 5, 6, 7, 1, 2, 3];auto p =bringToFront(arr[0 .. 4], arr[4 .. $]);writeln(p);// arr.length - 4writeln(arr);// [1, 2, 3, 4, 5, 6, 7]
front range may actually "step over" thebackrange. This is very useful with forward ranges that cannot computecomfortably right-bounded subranges likearr[0 .. 4] above. Inthe example below,r2 is a right subrange ofr1.import std.algorithm.comparison : equal;import std.container : SList;import std.range.primitives : popFrontN;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 ]));
import std.string : representation;auto ar = representation("a".dup);auto br = representation("ç".dup);bringToFront(ar, br);auto a =cast(char[]) ar;auto b =cast(char[]) br;// Illegal UTF-8writeln(a);// "\303"// Illegal UTF-8writeln(b);// "\247a"
copy(SourceRange, TargetRange)(SourceRangesource, TargetRangetarget)source intotarget and returns theremaining (unfilled) part oftarget.Preconditionstarget shall have enough room to accommodatethe entirety ofsource.
SourceRangesource | aninput range |
TargetRangetarget | an output range |
int[] a = [ 1, 5 ];int[] b = [ 9, 8 ];int[] buf =newint[](a.length + b.length + 10);auto rem = a.copy(buf);// copy a into bufrem = b.copy(rem);// copy b into remainder of bufwriteln(buf[0 .. a.length + b.length]);// [1, 5, 9, 8]assert(rem.length == 10);// unused slots in buf
float[] src = [ 1.0f, 5 ];double[] dest =newdouble[src.length];src.copy(dest);
import std.range;int[] src = [ 1, 5, 8, 9, 10 ];auto dest =newint[](3);src.take(dest.length).copy(dest);writeln(dest);// [1, 5, 8]
import std.algorithm.iteration : filter;int[] src = [ 1, 5, 8, 9, 10, 1, 2, 0 ];auto dest =newint[src.length];auto rem = src .filter!(a => (a & 1) == 1) .copy(dest);writeln(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);writeln(dest);// [0, 0, 1, 2, 4]
fill(Range, Value)(auto ref Rangerange, auto ref Valuevalue)range.front =value)) || isSomeChar!Value && is(typeof(range[] =value)));fill(InputRange, ForwardRange)(InputRangerange, ForwardRangefiller)value to each element of input rangerange.value to fill therange,afillerforward rangecan be provided. The length offiller andrange do not need to match, butfiller must not be empty.Rangerange | Aninput range that exposes references to its elements and has assignable elements |
Valuevalue | Assigned to each element of range |
ForwardRangefiller | Aforward range representing the fill pattern. |
filler is empty.int[] a = [ 1, 2, 3, 4 ];fill(a, 5);writeln(a);// [5, 5, 5, 5]
int[] a = [ 1, 2, 3, 4, 5 ];int[] b = [ 8, 9 ];fill(a, b);writeln(a);// [8, 9, 8, 9, 8]
initializeAll(Range)(Rangerange)initializeAll(Range)(Rangerange)range with their.init value.Assumes that the elements of the range are uninitialized.Rangerange | Aninput range that exposes references to its elements and has assignable elements |
import core.stdc.stdlib : malloc, free;struct S{int a = 10;}auto s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5];initializeAll(s);writeln(s);// [S(10), S(10), S(10), S(10), S(10)]scope(exit) free(s.ptr);
move(T)(ref Tsource, ref Ttarget)target = T.init));move(T)(ref Tsource, ref Ttarget)move(T)(ref return scope Tsource);source intotarget, via a destructive copy when necessary.PreconditionsIf source has internal pointers that point to itself and doesn't defineopPostMove, it cannot be moved, and will trigger an assertion failure.
Tsource | Data to copy. |
Ttarget | Where to copy into. The destructor, if any, is invoked before the copy is performed. |
move just performstarget =source:Object obj1 =new Object;Object obj2 = obj1;Object obj3;move(obj2, obj3);assert(obj3is obj1);// obj2 unchangedassert(obj2is obj1);
// Structs without destructors are simply copiedstruct S1{int a = 1;int b = 2;}S1 s11 = { 10, 11 };S1 s12;move(s11, s12);writeln(s12);// S1(10, 11)writeln(s11);// s12// But structs with destructors or postblits are reset to their .init value// after copying to the target.struct S2{int a = 1;int b = 2; ~this()purenothrow @safe @nogc { }}S2 s21 = { 3, 4 };S2 s22;move(s21, s22);writeln(s21);// S2(1, 2)writeln(s22);// S2(3, 4)
struct S{int a = 1; @disablethis(this); ~this()purenothrow @safe @nogc {}}S s1;s1.a = 2;S s2 =move(s1);writeln(s1.a);// 1writeln(s2.a);// 2
struct S{int a;void opPostMove(constref S old) { writeln(a);// old.a a++; }}S s1;s1.a = 41;S s2 =move(s1);writeln(s2.a);// 42
moveEmplace(T)(ref Tsource, ref Ttarget);target is uninitialized. This is more efficient becausesource can be blitted overtarget without destroying or initializing it first.Tsource | value to be moved into target |
Ttarget | uninitialized value to be filled by source |
staticstruct Foo{purenothrow @nogc:this(int* ptr) { _ptr = ptr; } ~this() {if (_ptr) ++*_ptr; }int* _ptr;}int val;Foo foo1 =void;// uninitializedauto foo2 = Foo(&val);// initializedassert(foo2._ptris &val);// Using `move(foo2, foo1)` would have an undefined effect because it would destroy// the uninitialized foo1.// moveEmplace directly overwrites foo1 without destroying or initializing it first.moveEmplace(foo2, foo1);assert(foo1._ptris &val);assert(foo2._ptrisnull);writeln(val);// 0
moveAll(InputRange1, InputRange2)(InputRange1src, InputRange2tgt)src.front,tgt.front))));src and the correspondingelementb intgt, in increasing order.PreconditionswalkLength(src) <= walkLength(tgt).This precondition will be asserted. If you cannot ensure there is enough room intgt to accommodate all ofsrc usemoveSome instead.
InputRange1src | Aninput range with movable elements. |
InputRange2tgt | Aninput range with elements that elements fromsrc can be moved into. |
tgt after all elements fromsrc havebeen moved.int[3] a = [ 1, 2, 3 ];int[5] b;assert(moveAll(a[], b[])is b[3 .. $]);writeln(a[]);// b[0 .. 3]int[3] cmp = [ 1, 2, 3 ];writeln(a[]);// cmp[]
moveEmplaceAll(InputRange1, InputRange2)(InputRange1src, InputRange2tgt)src.front,tgt.front))));tgt are uninitialized. UsesmoveEmplace to move elements fromsrc over elements fromtgt.staticstruct Foo{ ~this()purenothrow @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[]);// move 3 value from src over dstassert(tail.length == 2);// returns remaining uninitialized valuesinitializeAll(tail);import std.algorithm.searching : all;assert(src[].all!(e => e._ptrisnull));assert(dst[0 .. 3].all!(e => e._ptr !isnull));
moveSome(InputRange1, InputRange2)(InputRange1src, InputRange2tgt)src.front,tgt.front))));src and the correspondingelementb intgt, in increasing order, stopping when either range has beenexhausted.InputRange1src | Aninput range with movable elements. |
InputRange2tgt | Aninput range with elements that elements fromsrc can be moved into. |
int[5] a = [ 1, 2, 3, 4, 5 ];int[3] b;assert(moveSome(a[], b[])[0]is a[3 .. $]);writeln(a[0 .. 3]);// bwriteln(a);// [1, 2, 3, 4, 5]
moveEmplaceSome(InputRange1, InputRange2)(InputRange1src, InputRange2tgt)src.front,tgt.front))));tgt are uninitialized. UsesmoveEmplace to move elements fromsrc over elements fromtgt.staticstruct Foo{ ~this()purenothrow @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[]);writeln(res.length);// 2import std.algorithm.searching : all;assert(src[0 .. 3].all!(e => e._ptrisnull));assert(src[3]._ptr !isnull);assert(dst[].all!(e => e._ptr !isnull));
SwapStrategy: int;SwapStrategy allchooseSwapStrategy.unstable as the default.int[] a = [0, 1, 2, 3];writeln(remove!(SwapStrategy.stable)(a, 1));// [0, 2, 3]a = [0, 1, 2, 3];writeln(remove!(SwapStrategy.unstable)(a, 1));// [0, 3, 2]
import std.algorithm.sorting : partition;// Put stuff greater than 3 on the leftauto arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];writeln(partition!(a => a > 3,SwapStrategy.stable)(arr));// [1, 2, 3]writeln(arr);// [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];writeln(partition!(a => a > 3,SwapStrategy.semistable)(arr));// [2, 3, 1]writeln(arr);// [4, 5, 6, 7, 8, 9, 10, 2, 3, 1]arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];writeln(partition!(a => a > 3,SwapStrategy.unstable)(arr));// [3, 2, 1]writeln(arr);// [10, 9, 8, 4, 5, 6, 7, 3, 2, 1]
unstablesemistablestableremove(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Rangerange, Offsetoffset)remove(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Rangerange, Offsetoffset)range and returns the shortenedrange.import std.algorithm.mutation;string[] a = ["a","b","c","d" ];a = a.remove(1);// remove element at offset 1assert(a == ["a","c","d"]);
remove does not change the length of the original range directly;instead, it returns the shortened range. If its return value is not assigned tothe original range, the original range will retain its original length, thoughits contents will have changed:import std.algorithm.mutation;int[] a = [ 3, 5, 7, 8 ];assert(remove(a, 1) == [ 3, 7, 8 ]);assert(a == [ 3, 7, 8, 8 ]);
remove to it, as shown in the first example.remove. In that case,elements at the respective indices are all removed. The indices mustbe passed in increasing order, otherwise an exception occurs.import std.algorithm.mutation;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 ]);
import std.algorithm.mutation, std.typecons;int[] a = [ 3, 4, 5, 6, 7];// remove elements at indices 1 and 2assert(remove(a, tuple(1, 3)) == [ 3, 6, 7 ]);
import std.algorithm.mutation, std.typecons;int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];a =remove(a, 1, tuple(3, 5), 9);assert(a == [ 0, 2, 5, 6, 7, 8, 10 ]);
remove.import std.algorithm.mutation;int[] a = [ 0, 1, 2, 3 ];assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);
remove moved elements from the endof the array over the slots to be removed. This way there is less datamovement to be done which improves the execution time of the function.remove works on bidirectional ranges that have assignablelvalue elements. The moving strategy is (listed from fastest to slowest):range.popFront.range; a given element is nevermoved several times, but more elements are moved than in the previouscases.| s | a SwapStrategy to determine if the original order needs to be preserved |
Rangerange | abidirectional range with a length member |
Offsetoffset | which element(s) to remove |
range with 1 or more elements removed.import std.typecons : tuple;auto a = [ 0, 1, 2, 3, 4, 5 ];writeln(remove!(SwapStrategy.stable)(a, 1));// [0, 2, 3, 4, 5]a = [ 0, 1, 2, 3, 4, 5 ];writeln(remove!(SwapStrategy.stable)(a, 1, 3));// [0, 2, 4, 5]a = [ 0, 1, 2, 3, 4, 5 ];writeln(remove!(SwapStrategy.stable)(a, 1, tuple(3, 6)));// [0, 2]a = [ 0, 1, 2, 3, 4, 5 ];writeln(remove!(SwapStrategy.unstable)(a, 1));// [0, 5, 2, 3, 4]a = [ 0, 1, 2, 3, 4, 5 ];writeln(remove!(SwapStrategy.unstable)(a, tuple(1, 4)));// [0, 5, 4]
import std.typecons : tuple;// Delete an indexwriteln([4, 5, 6].remove(1));// [4, 6]// Delete multiple indiceswriteln([4, 5, 6, 7, 8].remove(1, 3));// [4, 6, 8]// Use an indices rangewriteln([4, 5, 6, 7, 8].remove(tuple(1, 3)));// [4, 7, 8]// Use an indices range and individual indiceswriteln([4, 5, 6, 7, 8].remove(0, tuple(1, 3), 4));// [7]
writeln([5, 6, 7, 8].remove!(SwapStrategy.stable)(1));// [5, 7, 8]writeln([5, 6, 7, 8].remove!(SwapStrategy.unstable)(1));// [5, 8, 7]
remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)(Rangerange);range by removingelements that satisfypred. Ifs = SwapStrategy.unstable,elements are moved from the right end of the range over the elementsto eliminate. Ifs = SwapStrategy.stable (the default),elements are moved progressively to front such that their relativeorder is preserved. Returns the filtered range.Rangerange | a bidirectional ranges with lvalue elements or mutable character arrays |
staticimmutable base = [1, 2, 3, 2, 4, 2, 5, 2];int[] arr = base[].dup;// using a string-based predicatewriteln(remove!("a == 2")(arr));// [1, 3, 4, 5]// The original array contents have been modified,// so we need to reset it to its original state.// The length is unmodified however.arr[] = base[];// using a lambda predicatewriteln(remove!(a => a == 2)(arr));// [1, 3, 4, 5]
reverse(Range)(Ranger)r in-place. Performsr.length / 2 evaluations ofswap.UTF sequences consisting of multiple code units are preserved properly.Ranger | abidirectional range with either swappable elements, a random access range with a length member, or a narrow string |
rNoteWhen passing a string with unicode modifiers on characters, such as\u0301, this function will not properly keep the position of the modifier. For example, reversingba\u0301d ("bád") will result in d\u0301ab ("d́ab") instead ofda\u0301b ("dáb").
rint[] arr = [ 1, 2, 3 ];writeln(arr.reverse);// [3, 2, 1]
char[] arr ="hello\U00010143\u0100\U00010143".dup;writeln(arr.reverse);// "\U00010143\u0100\U00010143olleh"
strip(Range, E)(Rangerange, Eelement)range.front ==element) : bool));strip(alias pred, Range)(Rangerange)range.back)) : bool));stripLeft(Range, E)(Rangerange, Eelement)range.front ==element) : bool));stripLeft(alias pred, Range)(Rangerange)range.front)) : bool));stripRight(Range, E)(Rangerange, Eelement)range.back ==element) : bool));stripRight(alias pred, Range)(Rangerange)range.back)) : bool));stripLeft function will strip thefront of the range, thestripRight function will strip theback of the range, while thestrip function will strip both thefront andback of the range. Note that thestrip andstripRight functions require the range to be aBidirectionalRange range. All of these functions come in two varieties: one takes a target element, where the range will be stripped as long as this element can be found. The other takes a lambda predicate, where the range will be stripped as long as the predicate returns true.Rangerange | abidirectional range orinput range |
Eelement | the elements to remove |
writeln(" foobar ".strip(' '));// "foobar"writeln("00223.444500".strip('0'));// "223.4445"writeln("ëëêéüŗōpéêëë".strip('ë'));// "êéüŗōpéê"writeln([1, 1, 0, 1, 1].strip(1));// [0]writeln([0.0, 0.01, 0.01, 0.0].strip(0).length);// 2
writeln(" foobar ".strip!(a => a == ' ')());// "foobar"writeln("00223.444500".strip!(a => a == '0')());// "223.4445"writeln("ëëêéüŗōpéêëë".strip!(a => a == 'ë')());// "êéüŗōpéê"writeln([1, 1, 0, 1, 1].strip!(a => a == 1)());// [0]writeln([0.0, 0.01, 0.5, 0.6, 0.01, 0.0].strip!(a => a < 0.4)().length);// 2
writeln(" foobar ".stripLeft(' '));// "foobar "writeln("00223.444500".stripLeft('0'));// "223.444500"writeln("ůůűniçodêéé".stripLeft('ů'));// "űniçodêéé"writeln([1, 1, 0, 1, 1].stripLeft(1));// [0, 1, 1]writeln([0.0, 0.01, 0.01, 0.0].stripLeft(0).length);// 3
writeln(" foobar ".stripLeft!(a => a == ' ')());// "foobar "writeln("00223.444500".stripLeft!(a => a == '0')());// "223.444500"writeln("ůůűniçodêéé".stripLeft!(a => a == 'ů')());// "űniçodêéé"writeln([1, 1, 0, 1, 1].stripLeft!(a => a == 1)());// [0, 1, 1]writeln([0.0, 0.01, 0.10, 0.5, 0.6].stripLeft!(a => a < 0.4)().length);// 2
writeln(" foobar ".stripRight(' '));// " foobar"writeln("00223.444500".stripRight('0'));// "00223.4445"writeln("ùniçodêéé".stripRight('é'));// "ùniçodê"writeln([1, 1, 0, 1, 1].stripRight(1));// [1, 1, 0]writeln([0.0, 0.01, 0.01, 0.0].stripRight(0).length);// 3
writeln(" foobar ".stripRight!(a => a == ' ')());// " foobar"writeln("00223.444500".stripRight!(a => a == '0')());// "00223.4445"writeln("ùniçodêéé".stripRight!(a => a == 'é')());// "ùniçodê"writeln([1, 1, 0, 1, 1].stripRight!(a => a == 1)());// [1, 1, 0]writeln([0.0, 0.01, 0.10, 0.5, 0.6].stripRight!(a => a > 0.4)().length);// 3
swap(T)(ref Tlhs, ref Trhs)lhs.proxySwap(rhs))));swap(T)(ref Tlhs, ref Trhs)lhs.proxySwap(rhs))));lhs andrhs. The instanceslhs andrhs are moved inmemory, without ever callingopAssign, nor any other function.Tneed not be assignable at all to be swapped.lhs andrhs reference the same instance, then nothing is done.lhs andrhs must be mutable. IfT is a struct or union, thenits fields must also all be (recursively) mutable.Tlhs | Data to be swapped withrhs. |
Trhs | Data to be swapped withlhs. |
// Swapping POD (plain old data) types:int a = 42, b = 34;swap(a, b);assert(a == 34 && b == 42);// Swapping structs with indirection:staticstruct S {int x;char c;int[] y; }S s1 = { 0, 'z', [ 1, 2 ] };S s2 = { 42, 'a', [ 4, 6 ] };swap(s1, s2);writeln(s1.x);// 42writeln(s1.c);// 'a'writeln(s1.y);// [4, 6]writeln(s2.x);// 0writeln(s2.c);// 'z'writeln(s2.y);// [1, 2]// Immutables cannot be swapped:immutableint imm1 = 1, imm2 = 2;staticassert(!__traits(compiles,swap(imm1, imm2)));int c = imm1 + 0;int d = imm2 + 0;swap(c, d);writeln(c);// 2writeln(d);// 1
// Non-copyable types can still be swapped.staticstruct 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");// Types containing non-copyable fields can also be swapped.staticstruct 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 types cannot be swapped.const NoCopy const1, const2;assert(const1.n == 0 && const2.n == 0);staticassert(!__traits(compiles,swap(const1, const2)));
swapAt(R)(auto ref Rr, size_ti1, size_ti2);r,specified by their indicesi1 andi2.Rr | a range with swappable elements |
size_ti1 | first index |
size_ti2 | second index |
import std.algorithm.comparison : equal;auto a = [1, 2, 3];a.swapAt(1, 2);assert(a.equal([1, 3, 2]));
swapRanges(InputRange1, InputRange2)(InputRange1r1, InputRange2r2)r1 with successive elements inr2.Returns a tuple containing the remainder portions ofr1 andr2 that were not swapped (one of them will be empty). The ranges maybe of different types but must have the same element type and supportswapping.InputRange1r1 | aninput range with swappable elements |
InputRange2r2 | aninput range with swappable elements |
import std.range : empty;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);writeln(a);// [100, 2, 3, 103]writeln(b);// [0, 1, 101, 102]
uninitializedFill(Range, Value)(Rangerange, Valuevalue)range.front =value)));range withvalue.Assumes that the elements of the range are uninitialized.This is of interest for structs thatdefine copy constructors (for all other types,fill anduninitializedFill are equivalent).Rangerange | Aninput range that exposes references to its elements and has assignable elements |
Valuevalue | Assigned to each element of range |
import core.stdc.stdlib : malloc, free;auto s = (cast(int*) malloc(5 *int.sizeof))[0 .. 5];uninitializedFill(s, 42);writeln(s);// [42, 42, 42, 42, 42]scope(exit) free(s.ptr);