blob: 3f38d60b8596e2837adb7a6f43f2e6adaaf0ad0d [file] [log] [blame]
@safe unittest
{
import std.algorithm.mutation;
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 ]);
}
@safe unittest
{
import std.algorithm.mutation;
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 ]));
}
@safe unittest
{
import std.algorithm.mutation;
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 ]));
}
@safe unittest
{
import std.algorithm.mutation;
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-8
assert(a == "\303");
// Illegal UTF-8
assert(b == "\247a");
}
@safe unittest
{
import std.algorithm.mutation;
int[] a = [ 1, 5 ];
int[] b = [ 9, 8 ];
int[] buf = new int[](a.length + b.length + 10);
auto rem = a.copy(buf); // copy a into buf
rem = b.copy(rem); // copy b into remainder of buf
assert(buf[0 .. a.length + b.length] == [1, 5, 9, 8]);
assert(rem.length == 10); // unused slots in buf
}
@safe unittest
{
import std.algorithm.mutation;
float[] src = [ 1.0f, 5 ];
double[] dest = new double[src.length];
src.copy(dest);
}
@safe unittest
{
import std.algorithm.mutation;
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 ]);
}
@safe unittest
{
import std.algorithm.mutation;
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 ]);
}
@safe unittest
{
import std.algorithm.mutation;
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]);
}
@safe unittest
{
import std.algorithm.mutation;
int[] a = [ 1, 2, 3, 4 ];
fill(a, 5);
assert(a == [ 5, 5, 5, 5 ]);
}
@safe unittest
{
import std.algorithm.mutation;
int[] a = [ 1, 2, 3, 4, 5 ];
int[] b = [ 8, 9 ];
fill(a, b);
assert(a == [ 8, 9, 8, 9, 8 ]);
}
@system unittest
{
import std.algorithm.mutation;
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);
}
@safe unittest
{
import std.algorithm.mutation;
Object obj1 = new Object;
Object obj2 = obj1;
Object obj3;
move(obj2, obj3);
assert(obj3 is obj1);
// obj2 unchanged
assert(obj2 is obj1);
}
pure nothrow @safe @nogc unittest
{
import std.algorithm.mutation;
// Structs without destructors are simply copied
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);
// 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() pure nothrow @safe @nogc { }
}
S2 s21 = { 3, 4 };
S2 s22;
move(s21, s22);
assert(s21 == S2(1, 2));
assert(s22 == S2(3, 4));
}
pure nothrow @safe @nogc unittest
{
import std.algorithm.mutation;
struct S
{
int a = 1;
@disable this(this);
~this() pure nothrow @safe @nogc {}
}
S s1;
s1.a = 2;
S s2 = move(s1);
assert(s1.a == 1);
assert(s2.a == 2);
}
pure nothrow @safe @nogc unittest
{
import std.algorithm.mutation;
struct S
{
int a;
void opPostMove(const ref S old)
{
assert(a == old.a);
a++;
}
}
S s1;
s1.a = 41;
S s2 = move(s1);
assert(s2.a == 42);
}
pure nothrow @nogc @system unittest
{
import std.algorithm.mutation;
static struct Foo
{
pure nothrow @nogc:
this(int* ptr) { _ptr = ptr; }
~this() { if (_ptr) ++*_ptr; }
int* _ptr;
}
int val;
Foo foo1 = void; // uninitialized
auto foo2 = Foo(&val); // initialized
assert(foo2._ptr is &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._ptr is &val);
assert(foo2._ptr is null);
assert(val == 0);
}
pure nothrow @safe @nogc unittest
{
import std.algorithm.mutation;
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[]);
}
pure nothrow @nogc @system unittest
{
import std.algorithm.mutation;
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[]); // move 3 value from src over dst
assert(tail.length == 2); // returns remaining uninitialized values
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));
}
pure nothrow @safe @nogc unittest
{
import std.algorithm.mutation;
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 ]);
}
pure nothrow @nogc @system unittest
{
import std.algorithm.mutation;
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[]);
assert(res.length == 2);
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));
}
@safe unittest
{
import std.algorithm.mutation;
int[] a = [0, 1, 2, 3];
assert(remove!(SwapStrategy.stable)(a, 1) == [0, 2, 3]);
a = [0, 1, 2, 3];
assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 3, 2]);
}
@safe unittest
{
import std.algorithm.mutation;
import std.algorithm.sorting : partition;
// Put stuff greater than 3 on the left
auto arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert(partition!(a => a > 3, SwapStrategy.stable)(arr) == [1, 2, 3]);
assert(arr == [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]);
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert(partition!(a => a > 3, SwapStrategy.semistable)(arr) == [2, 3, 1]);
assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1]);
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert(partition!(a => a > 3, SwapStrategy.unstable)(arr) == [3, 2, 1]);
assert(arr == [10, 9, 8, 4, 5, 6, 7, 3, 2, 1]);
}
@safe pure unittest
{
import std.algorithm.mutation;
import std.typecons : tuple;
auto a = [ 0, 1, 2, 3, 4, 5 ];
assert(remove!(SwapStrategy.stable)(a, 1) == [ 0, 2, 3, 4, 5 ]);
a = [ 0, 1, 2, 3, 4, 5 ];
assert(remove!(SwapStrategy.stable)(a, 1, 3) == [ 0, 2, 4, 5] );
a = [ 0, 1, 2, 3, 4, 5 ];
assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 6)) == [ 0, 2 ]);
a = [ 0, 1, 2, 3, 4, 5 ];
assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 5, 2, 3, 4]);
a = [ 0, 1, 2, 3, 4, 5 ];
assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4)) == [0, 5, 4]);
}
@safe pure unittest
{
import std.algorithm.mutation;
import std.typecons : tuple;
// Delete an index
assert([4, 5, 6].remove(1) == [4, 6]);
// Delete multiple indices
assert([4, 5, 6, 7, 8].remove(1, 3) == [4, 6, 8]);
// Use an indices range
assert([4, 5, 6, 7, 8].remove(tuple(1, 3)) == [4, 7, 8]);
// Use an indices range and individual indices
assert([4, 5, 6, 7, 8].remove(0, tuple(1, 3), 4) == [7]);
}
@safe pure unittest
{
import std.algorithm.mutation;
assert([5, 6, 7, 8].remove!(SwapStrategy.stable)(1) == [5, 7, 8]);
assert([5, 6, 7, 8].remove!(SwapStrategy.unstable)(1) == [5, 8, 7]);
}
@safe unittest
{
import std.algorithm.mutation;
static immutable base = [1, 2, 3, 2, 4, 2, 5, 2];
int[] arr = base[].dup;
// using a string-based predicate
assert(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 predicate
assert(remove!(a => a == 2)(arr) == [ 1, 3, 4, 5 ]);
}
@safe unittest
{
import std.algorithm.mutation;
int[] arr = [ 1, 2, 3 ];
assert(arr.reverse == [ 3, 2, 1 ]);
}
@safe unittest
{
import std.algorithm.mutation;
char[] arr = "hello\U00010143\u0100\U00010143".dup;
assert(arr.reverse == "\U00010143\u0100\U00010143olleh");
}
@safe pure unittest
{
import std.algorithm.mutation;
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);
}
@safe pure unittest
{
import std.algorithm.mutation;
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);
}
@safe pure unittest
{
import std.algorithm.mutation;
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);
}
@safe pure unittest
{
import std.algorithm.mutation;
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);
}
@safe pure unittest
{
import std.algorithm.mutation;
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);
}
@safe pure unittest
{
import std.algorithm.mutation;
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);
}
@safe unittest
{
import std.algorithm.mutation;
// Swapping POD (plain old data) types:
int a = 42, b = 34;
swap(a, b);
assert(a == 34 && b == 42);
// Swapping structs with indirection:
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 ]);
// Immutables cannot be swapped:
immutable int imm1 = 1, imm2 = 2;
static assert(!__traits(compiles, swap(imm1, imm2)));
int c = imm1 + 0;
int d = imm2 + 0;
swap(c, d);
assert(c == 2);
assert(d == 1);
}
@safe unittest
{
import std.algorithm.mutation;
// Non-copyable types can still be swapped.
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");
// Types containing non-copyable fields can also be swapped.
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 types cannot be swapped.
const NoCopy const1, const2;
assert(const1.n == 0 && const2.n == 0);
static assert(!__traits(compiles, swap(const1, const2)));
}
pure @safe nothrow unittest
{
import std.algorithm.mutation;
import std.algorithm.comparison : equal;
auto a = [1, 2, 3];
a.swapAt(1, 2);
assert(a.equal([1, 3, 2]));
}
@safe unittest
{
import std.algorithm.mutation;
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);
assert(a == [ 100, 2, 3, 103 ]);
assert(b == [ 0, 1, 101, 102 ]);
}
nothrow @system unittest
{
import std.algorithm.mutation;
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);
}