blob: 03378ce3d668be11824e1b33142adfda68290ed2 [file] [log] [blame]
pure @safe nothrow @nogc unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[5] a = [ 1, 2, 3, 4, 5 ];
int[5] b = [ 5, 4, 3, 2, 1 ];
assert(equal(retro(a[]), b[]));
assert(retro(a[]).source is a[]);
assert(retro(retro(a[])) is a[]);
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][]));
assert(stride(stride(a, 2), 3) == stride(a, 6));
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[] arr1 = [ 1, 2, 3, 4 ];
int[] arr2 = [ 5, 6 ];
int[] arr3 = [ 7 ];
auto s = chain(arr1, arr2, arr3);
assert(s.length == 7);
assert(s[5] == 6);
assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.algorithm.sorting : sort;
int[] arr1 = [5, 2, 8];
int[] arr2 = [3, 7, 9];
int[] arr3 = [1, 4, 6];
// in-place sorting across all of the arrays
auto s = arr1.chain(arr2, arr3).sort;
assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9]));
assert(arr1.equal([1, 2, 3]));
assert(arr2.equal([4, 5, 6]));
assert(arr3.equal([7, 8, 9]));
}
pure @safe nothrow unittest
{
import std.range;
import std.utf : byChar, byCodeUnit;
auto s1 = "string one";
auto s2 = "string two";
// s1 and s2 front is dchar because of auto-decoding
static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar));
auto r1 = s1.chain(s2);
// chains of ranges of the same character type give that same type
static assert(is(typeof(r1.front) == dchar));
auto s3 = "string three".byCodeUnit;
static assert(is(typeof(s3.front) == immutable char));
auto r2 = s1.chain(s3);
// chaining ranges of mixed character types gives `dchar`
static assert(is(typeof(r2.front) == dchar));
// use byChar on character ranges to correctly convert them to UTF-8
auto r3 = s1.byChar.chain(s3);
static assert(is(typeof(r3.front) == immutable char));
}
@safe nothrow pure @nogc unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filter, map;
auto data1 = only(1, 2, 3, 4).filter!(a => a != 3);
auto data2 = only(5, 6, 7, 8).map!(a => a + 1);
// choose() is primarily useful when you need to select one of two ranges
// with different types at runtime.
static assert(!is(typeof(data1) == typeof(data2)));
auto chooseRange(bool pickFirst)
{
// The returned range is a common wrapper type that can be used for
// returning or storing either range without running into a type error.
return choose(pickFirst, data1, data2);
// Simply returning the chosen range without using choose() does not
// work, because map() and filter() return different types.
//return pickFirst ? data1 : data2; // does not compile
}
auto result = chooseRange(true);
assert(result.equal(only(1, 2, 4)));
result = chooseRange(false);
assert(result.equal(only(6, 7, 8, 9)));
}
@safe nothrow pure @nogc unittest
{
import std.range;
auto test()
{
import std.algorithm.comparison : equal;
int[4] sarr1 = [1, 2, 3, 4];
int[2] sarr2 = [5, 6];
int[1] sarr3 = [7];
auto arr1 = sarr1[];
auto arr2 = sarr2[];
auto arr3 = sarr3[];
{
auto s = chooseAmong(0, arr1, arr2, arr3);
auto t = s.save;
assert(s.length == 4);
assert(s[2] == 3);
s.popFront();
assert(equal(t, only(1, 2, 3, 4)));
}
{
auto s = chooseAmong(1, arr1, arr2, arr3);
assert(s.length == 2);
s.front = 8;
assert(equal(s, only(8, 6)));
}
{
auto s = chooseAmong(1, arr1, arr2, arr3);
assert(s.length == 2);
s[1] = 9;
assert(equal(s, only(8, 9)));
}
{
auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3];
assert(s.length == 2);
assert(equal(s, only(2, 3)));
}
{
auto s = chooseAmong(0, arr1, arr2, arr3);
assert(s.length == 4);
assert(s.back == 4);
s.popBack();
s.back = 5;
assert(equal(s, only(1, 2, 5)));
s.back = 3;
assert(equal(s, only(1, 2, 3)));
}
{
uint[5] foo = [1, 2, 3, 4, 5];
uint[5] bar = [6, 7, 8, 9, 10];
auto c = chooseAmong(1, foo[], bar[]);
assert(c[3] == 9);
c[3] = 42;
assert(c[3] == 42);
assert(c.moveFront() == 6);
assert(c.moveBack() == 10);
assert(c.moveAt(4) == 10);
}
{
import std.range : cycle;
auto s = chooseAmong(0, cycle(arr2), cycle(arr3));
assert(isInfinite!(typeof(s)));
assert(!s.empty);
assert(s[100] == 8);
assert(s[101] == 9);
assert(s[0 .. 3].equal(only(8, 9, 8)));
}
return 0;
}
// works at runtime
auto a = test();
// and at compile time
static b = test();
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[] a = [ 1, 2, 3 ];
int[] b = [ 10, 20, 30, 40 ];
auto r = roundRobin(a, b);
assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto interleave(R, E)(R range, E element)
if ((isInputRange!R && hasLength!R) || isForwardRange!R)
{
static if (hasLength!R)
immutable len = range.length;
else
immutable len = range.save.walkLength;
return roundRobin(
range,
element.repeat(len - 1)
);
}
assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[] a = [ 1, 2, 3, 4, 5 ];
assert(equal(radial(a), [ 3, 4, 2, 5, 1 ]));
a = [ 1, 2, 3, 4 ];
assert(equal(radial(a), [ 2, 3, 1, 4 ]));
// If the left end is reached first, the remaining elements on the right
// are concatenated in order:
a = [ 0, 1, 2, 3, 4, 5 ];
assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ]));
// If the right end is reached first, the remaining elements on the left
// are concatenated in reverse order:
assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ]));
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
auto s = take(arr1, 5);
assert(s.length == 5);
assert(s[4] == 5);
assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[] arr2 = [ 1, 2, 3 ];
auto t = take(arr2, 5);
assert(t.length == 3);
assert(equal(t, [ 1, 2, 3 ]));
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto a = [ 1, 2, 3, 4, 5 ];
auto b = takeExactly(a, 3);
assert(equal(b, [1, 2, 3]));
static assert(is(typeof(b.length) == size_t));
assert(b.length == 3);
assert(b.front == 1);
assert(b.back == 3);
}
pure @safe nothrow unittest
{
import std.range;
auto s = takeOne([42, 43, 44]);
static assert(isRandomAccessRange!(typeof(s)));
assert(s.length == 1);
assert(!s.empty);
assert(s.front == 42);
s.front = 43;
assert(s.front == 43);
assert(s.back == 43);
assert(s[0] == 43);
s.popFront();
assert(s.length == 0);
assert(s.empty);
}
pure @safe nothrow @nogc unittest
{
import std.range;
auto range = takeNone!(int[])();
assert(range.length == 0);
assert(range.empty);
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.iteration : filter;
assert(takeNone([42, 27, 19]).empty);
assert(takeNone("dlang.org").empty);
assert(takeNone(filter!"true"([42, 27, 19])).empty);
}
pure @safe nothrow unittest
{
import std.range;
// tail -c n
assert([1, 2, 3].tail(1) == [3]);
assert([1, 2, 3].tail(2) == [2, 3]);
assert([1, 2, 3].tail(3) == [1, 2, 3]);
assert([1, 2, 3].tail(4) == [1, 2, 3]);
assert([1, 2, 3].tail(0).length == 0);
// tail --lines=n
import std.algorithm.comparison : equal;
import std.algorithm.iteration : joiner;
import std.exception : assumeWontThrow;
import std.string : lineSplitter;
assert("one\ntwo\nthree"
.lineSplitter
.tail(2)
.joiner("\n")
.equal("two\nthree")
.assumeWontThrow);
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]);
assert("hello world".drop(6) == "world");
assert("hello world".drop(50).empty);
assert("hello world".take(6).drop(3).equal("lo "));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]);
assert("hello world".dropBack(6) == "hello");
assert("hello world".dropBack(50).empty);
assert("hello world".drop(4).dropBack(4).equal("o w"));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filterBidirectional;
auto a = [1, 2, 3];
assert(a.dropExactly(2) == [3]);
assert(a.dropBackExactly(2) == [1]);
string s = "日本語";
assert(s.dropExactly(2) == "語");
assert(s.dropBackExactly(2) == "æ—¥");
auto bd = filterBidirectional!"true"([1, 2, 3]);
assert(bd.dropExactly(2).equal([3]));
assert(bd.dropBackExactly(2).equal([1]));
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filterBidirectional;
import std.container.dlist : DList;
auto dl = DList!int(9, 1, 2, 3, 9);
assert(dl[].dropOne().dropBackOne().equal([1, 2, 3]));
auto a = [1, 2, 3];
assert(a.dropOne() == [2, 3]);
assert(a.dropBackOne() == [1, 2]);
string s = "日本語";
import std.exception : assumeWontThrow;
assert(assumeWontThrow(s.dropOne() == "本語"));
assert(assumeWontThrow(s.dropBackOne() == "日本"));
auto bd = filterBidirectional!"true"([1, 2, 3]);
assert(bd.dropOne().equal([2, 3]));
assert(bd.dropBackOne().equal([1, 2]));
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert(5.repeat().take(4).equal([5, 5, 5, 5]));
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert(5.repeat(4).equal([5, 5, 5, 5]));
}
@safe pure nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : map;
int i = 1;
auto powersOfTwo = generate!(() => i *= 2)().take(10);
assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"()));
}
@safe pure nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
//Returns a run-time delegate
auto infiniteIota(T)(T low, T high)
{
T i = high;
return (){if (i == high) i = low; return i++;};
}
//adapted as a range.
assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]));
}
@safe unittest
{
import std.range;
import std.format : format;
import std.random : uniform;
auto r = generate!(() => uniform(0, 6)).take(10);
format("%(%s %)", r);
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.range : cycle, take;
// Here we create an infinitive cyclic sequence from [1, 2]
// (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then
// take 5 elements of this sequence (so we have [1, 2, 1, 2, 1])
// and compare them with the expected values for equality.
assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ]));
}
@nogc nothrow pure @safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : map;
// pairwise sum
auto arr = only(0, 1, 2);
auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]";
assert(part1.equal(only(1, 3)));
}
nothrow pure @safe unittest
{
import std.range;
import std.conv : to;
int[] a = [ 1, 2, 3 ];
string[] b = [ "a", "b", "c" ];
string[] result;
foreach (tup; zip(a, b))
{
result ~= tup[0].to!string ~ tup[1];
}
assert(result == [ "1a", "2b", "3c" ]);
size_t idx = 0;
// unpacking tuple elements with foreach
foreach (e1, e2; zip(a, b))
{
assert(e1 == a[idx]);
assert(e2 == b[idx]);
++idx;
}
}
nothrow pure @safe unittest
{
import std.range;
import std.algorithm.sorting : sort;
int[] a = [ 1, 2, 3 ];
string[] b = [ "a", "c", "b" ];
zip(a, b).sort!((t1, t2) => t1[0] > t2[0]);
assert(a == [ 3, 2, 1 ]);
// b is sorted according to a's sorting
assert(b == [ "b", "c", "a" ]);
}
pure @safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.exception : assertThrown;
import std.range.primitives;
import std.typecons : tuple;
auto a = [1, 2, 3];
auto b = [4, 5, 6, 7];
auto shortest = zip(StoppingPolicy.shortest, a, b);
assert(shortest.equal([
tuple(1, 4),
tuple(2, 5),
tuple(3, 6)
]));
auto longest = zip(StoppingPolicy.longest, a, b);
assert(longest.equal([
tuple(1, 4),
tuple(2, 5),
tuple(3, 6),
tuple(0, 7)
]));
auto same = zip(StoppingPolicy.requireSameLength, a, b);
same.popFrontN(3);
assertThrown!Exception(same.popFront);
}
pure @safe unittest
{
import std.range;
int[6] arr1 = [1,2,3,4,5,100];
int[5] arr2 = [6,7,8,9,10];
foreach (ref a, b; lockstep(arr1[], arr2[]))
{
a += b;
}
assert(arr1 == [7,9,11,13,15,100]);
}
pure @safe unittest
{
import std.range;
int[3] arr1 = [1,2,3];
int[3] arr2 = [4,5,6];
foreach (index, a, b; lockstep(arr1[], arr2[]))
{
assert(arr1[index] == a);
assert(arr2[index] == b);
}
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
// The Fibonacci numbers, using function in string form:
// a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]));
// The factorials, using function in lambda form:
auto fac = recurrence!((a,n) => a[n-1] * n)(1);
assert(take(fac, 10).equal([
1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880
]));
// The triangular numbers, using function in explicit form:
static size_t genTriangular(R)(R state, size_t n)
{
return state[n-1] + n;
}
auto tri = recurrence!genTriangular(0);
assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45]));
}
pure @safe nothrow @nogc unittest
{
import std.range;
auto odds = sequence!("a[0] + n * a[1]")(1, 2);
assert(odds.front == 1);
odds.popFront();
assert(odds.front == 3);
odds.popFront();
assert(odds.front == 5);
}
pure @safe nothrow @nogc unittest
{
import std.range;
auto tri = sequence!((a,n) => n*(n+1)/2)();
// Note random access
assert(tri[0] == 0);
assert(tri[3] == 6);
assert(tri[1] == 1);
assert(tri[4] == 10);
assert(tri[2] == 3);
}
@safe nothrow @nogc unittest
{
import std.range;
import std.math.exponential : pow;
import std.math.rounding : round;
import std.math.algebraic : sqrt;
static ulong computeFib(S)(S state, size_t n)
{
// Binet's formula
return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) /
state[2]));
}
auto fib = sequence!computeFib(
(1.0 + sqrt(5.0)) / 2.0, // Golden Ratio
(1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio
sqrt(5.0));
// Note random access with [] operator
assert(fib[1] == 1);
assert(fib[4] == 5);
assert(fib[3] == 3);
assert(fib[2] == 2);
assert(fib[9] == 55);
}
pure @safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.math.operations : isClose;
auto r = iota(0, 10, 1);
assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
assert(3 in r);
assert(r.contains(3)); //Same as above
assert(!(10 in r));
assert(!(-8 in r));
r = iota(0, 11, 3);
assert(equal(r, [0, 3, 6, 9]));
assert(r[2] == 6);
assert(!(2 in r));
auto rf = iota(0.0, 0.5, 0.1);
assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));
}
@safe pure unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.exception : assertThrown;
auto arr = [[1, 2], [3, 4, 5]];
auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged);
assert(r1.equal([1, 3]));
// throws on construction
assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged));
auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged);
assert(r2.equal([1, 3]));
// either assuming or checking for equal lengths makes
// the result a random access range
assert(r2[0] == 1);
static assert(!__traits(compiles, r1[0]));
}
pure @safe nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[][] x = new int[][2];
x[0] = [1, 2];
x[1] = [3, 4];
auto ror = frontTransversal(x);
assert(equal(ror, [ 1, 3 ][]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[][] x = new int[][2];
x[0] = [1, 2];
x[1] = [3, 4];
auto ror = transversal(x, 1);
assert(equal(ror, [ 2, 4 ]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : map;
int[][] y = [[1, 2, 3], [4, 5, 6]];
auto z = y.front.walkLength.iota.map!(i => transversal(y, i));
assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[][] ror = [
[1, 2, 3],
[4, 5, 6]
];
auto xp = transposed(ror);
assert(equal!"a.equal(b)"(xp, [
[1, 4],
[2, 5],
[3, 6]
]));
}
@safe unittest
{
import std.range;
int[][] x = new int[][2];
x[0] = [1, 2];
x[1] = [3, 4];
auto tr = transposed(x);
int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ];
uint i;
foreach (e; tr)
{
assert(array(e) == witness[i++]);
}
}
@safe unittest
{
import std.range;
auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]);
assert(ind.physicalIndex(0) == 1);
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto source = [1, 2, 3, 4, 5];
auto indices = [4, 3, 1, 2, 0, 4];
auto ind = indexed(source, indices);
assert(equal(ind, [5, 4, 2, 3, 1, 5]));
assert(equal(retro(ind), [5, 1, 3, 2, 4, 5]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
auto chunks = chunks(source, 4);
assert(chunks[0] == [1, 2, 3, 4]);
assert(chunks[1] == [5, 6, 7, 8]);
assert(chunks[2] == [9, 10]);
assert(chunks.back == chunks[2]);
assert(chunks.front == chunks[0]);
assert(chunks.length == 3);
assert(equal(retro(array(chunks)), array(retro(chunks))));
}
@system unittest
{
import std.range;
import std.algorithm.comparison : equal;
int i;
// The generator doesn't save state, so it cannot be a forward range.
auto inputRange = generate!(() => ++i).take(10);
// We can still process it in chunks, but it will be single-pass only.
auto chunked = inputRange.chunks(2);
assert(chunked.front.equal([1, 2]));
assert(chunked.front.empty); // Iterating the chunk has consumed it
chunked.popFront;
assert(chunked.front.equal([3, 4]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
auto chunks = evenChunks(source, 3);
assert(chunks[0] == [1, 2, 3, 4]);
assert(chunks[1] == [5, 6, 7]);
assert(chunks[2] == [8, 9, 10]);
}
@safe pure nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert([0, 1, 2, 3].slide(2).equal!equal(
[[0, 1], [1, 2], [2, 3]]
));
assert(5.iota.slide(3).equal!equal(
[[0, 1, 2], [1, 2, 3], [2, 3, 4]]
));
}
@safe pure nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert(6.iota.slide(1, 2).equal!equal(
[[0], [2], [4]]
));
assert(6.iota.slide(2, 4).equal!equal(
[[0, 1], [4, 5]]
));
assert(iota(7).slide(2, 2).equal!equal(
[[0, 1], [2, 3], [4, 5], [6]]
));
assert(iota(12).slide(2, 4).equal!equal(
[[0, 1], [4, 5], [8, 9]]
));
}
@safe pure nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert(3.iota.slide!(No.withPartial)(4).empty);
assert(3.iota.slide!(Yes.withPartial)(4).equal!equal(
[[0, 1, 2]]
));
}
@safe pure nothrow unittest
{
import std.range;
import std.algorithm.iteration : each;
int[dstring] d;
"AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++);
assert(d == ["AG"d: 2, "GA"d: 2]);
}
@safe pure nothrow unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]]));
assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]]));
assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]]));
assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filter, joiner, map;
import std.algorithm.searching : findSplitBefore;
import std.uni : isUpper;
assert(equal(only('♡'), "♡"));
assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]);
assert(only("one", "two", "three").joiner(" ").equal("one two three"));
string title = "The D Programming Language";
assert(title
.filter!isUpper // take the upper case letters
.map!only // make each letter its own range
.joiner(".") // join the ranges together lazily
.equal("T.D.P.L"));
}
pure @safe nothrow unittest
{
import std.range;
import std.array : assocArray;
import std.range : enumerate;
bool[int] aa = true.repeat(3).enumerate(-1).assocArray();
assert(aa[-1]);
assert(aa[0]);
assert(aa[1]);
}
@safe unittest
{
import std.range;
void func1(int a, int b);
void func2(int a, float b);
static assert(isTwoWayCompatible!(func1, int, int));
static assert(isTwoWayCompatible!(func1, short, int));
static assert(!isTwoWayCompatible!(func2, int, float));
void func3(ref int a, ref int b);
static assert( isTwoWayCompatible!(func3, int, int));
static assert(!isTwoWayCompatible!(func3, short, int));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3);
assert(p1.equal([4, 5, 6, 7, 8, 9]));
auto p2 = a.lowerBound!(SearchPolicy.gallop)(4);
assert(p2.equal([0, 1, 2, 3]));
}
@safe pure unittest
{
import std.range;
// create a SortedRange, that's checked strictly
SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]);
}
@safe unittest
{
import std.range;
import std.algorithm.sorting : sort;
int[3] data = [ 1, 2, 3 ];
auto a = assumeSorted(data[]);
assert(a == sort!"a < b"(data[]));
int[] p = a.release();
assert(p == [ 1, 2, 3 ]);
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
auto p = a.lowerBound(4);
assert(equal(p, [ 0, 1, 2, 3 ]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
auto p = a.upperBound(3);
assert(equal(p, [4, 4, 5, 6]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
auto r = a.assumeSorted.equalRange(3);
assert(equal(r, [ 3, 3, 3 ]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
auto r = assumeSorted(a).trisect(3);
assert(equal(r[0], [ 1, 2 ]));
assert(equal(r[1], [ 3, 3, 3 ]));
assert(equal(r[2], [ 4, 4, 5, 6 ]));
}
@safe unittest
{
import std.range;
import std.algorithm.sorting : sort;
auto a = [ 1, 2, 3, 42, 52, 64 ];
auto r = assumeSorted(a);
assert(r.contains(3));
assert(!(32 in r));
auto r1 = sort!"a > b"(a);
assert(3 in r1);
assert(!r1.contains(32));
assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
}
@safe unittest
{
import std.range;
import std.algorithm.mutation : swap;
auto a = [ 1, 2, 3, 42, 52, 64 ];
auto r = assumeSorted(a);
assert(r.contains(42));
swap(a[3], a[5]); // illegal to break sortedness of original range
assert(!r.contains(42)); // passes although it shouldn't
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
static struct S { int i; }
static bool byI(A, B)(A a, B b)
{
static if (is(A == S))
return a.i < b;
else
return a < b.i;
}
auto r = assumeSorted!byI([S(1), S(2), S(3)]);
auto lessThanTwo = r.lowerBound(2);
assert(equal(lessThanTwo, [S(1)]));
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
auto p = assumeSorted(a);
assert(equal(p.lowerBound(4), [0, 1, 2, 3]));
assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4]));
assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5]));
assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6]));
}
@system unittest
{
import std.range;
import std.algorithm.searching : find;
ubyte[] buffer = [1, 9, 45, 12, 22];
auto found1 = find(buffer, 45);
assert(found1 == [45, 12, 22]);
assert(buffer == [1, 9, 45, 12, 22]);
auto wrapped1 = refRange(&buffer);
auto found2 = find(wrapped1, 45);
assert(*found2.ptr == [45, 12, 22]);
assert(buffer == [45, 12, 22]);
auto found3 = find(wrapped1.save, 22);
assert(*found3.ptr == [22]);
assert(buffer == [45, 12, 22]);
string str = "hello world";
auto wrappedStr = refRange(&str);
assert(str.front == 'h');
str.popFrontN(5);
assert(str == " world");
assert(wrappedStr.front == ' ');
assert(*wrappedStr.ptr == " world");
}
@system unittest
{
import std.range;
ubyte[] buffer1 = [1, 2, 3, 4, 5];
ubyte[] buffer2 = [6, 7, 8, 9, 10];
auto wrapped1 = refRange(&buffer1);
auto wrapped2 = refRange(&buffer2);
assert(wrapped1.ptr is &buffer1);
assert(wrapped2.ptr is &buffer2);
assert(wrapped1.ptr !is wrapped2.ptr);
assert(buffer1 != buffer2);
wrapped1 = wrapped2;
//Everything points to the same stuff as before.
assert(wrapped1.ptr is &buffer1);
assert(wrapped2.ptr is &buffer2);
assert(wrapped1.ptr !is wrapped2.ptr);
//But buffer1 has changed due to the assignment.
assert(buffer1 == [6, 7, 8, 9, 10]);
assert(buffer2 == [6, 7, 8, 9, 10]);
buffer2 = [11, 12, 13, 14, 15];
//Everything points to the same stuff as before.
assert(wrapped1.ptr is &buffer1);
assert(wrapped2.ptr is &buffer2);
assert(wrapped1.ptr !is wrapped2.ptr);
//But buffer2 has changed due to the assignment.
assert(buffer1 == [6, 7, 8, 9, 10]);
assert(buffer2 == [11, 12, 13, 14, 15]);
wrapped2 = null;
//The pointer changed for wrapped2 but not wrapped1.
assert(wrapped1.ptr is &buffer1);
assert(wrapped2.ptr is null);
assert(wrapped1.ptr !is wrapped2.ptr);
//buffer2 is not affected by the assignment.
assert(buffer1 == [6, 7, 8, 9, 10]);
assert(buffer2 == [11, 12, 13, 14, 15]);
}
@safe pure unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.format : format;
// 00000011 00001001
ubyte[] arr = [3, 9];
auto r = arr.bitwise;
// iterate through it as with any other range
assert(format("%(%d%)", r) == "1100000010010000");
assert(format("%(%d%)", r.retro).equal("1100000010010000".retro));
auto r2 = r[5 .. $];
// set a bit
r[2] = 1;
assert(arr[0] == 7);
assert(r[5] == r2[0]);
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.random : rndGen;
auto rb = rndGen.bitwise;
static assert(isInfinite!(typeof(rb)));
auto rb2 = rndGen.bitwise;
// Don't forget that structs are passed by value
assert(rb.take(10).equal(rb2.take(10)));
}
@safe nothrow unittest
{
import std.range;
import std.algorithm.iteration : map;
import std.algorithm.mutation : copy;
[4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded
}
@safe unittest
{
import std.range;
import std.csv : csvNextToken;
string line = "a,b,c";
// ignore the first column
line.csvNextToken(nullSink, ',', '"');
line.popFront;
// look at the second column
Appender!string app;
line.csvNextToken(app, ',', '"');
assert(app.data == "b");
}
@safe unittest
{
import std.range;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filter, map;
// Sum values while copying
int[] values = [1, 4, 9, 16, 25];
int sum = 0;
auto newValues = values.tee!(a => sum += a).array;
assert(equal(newValues, values));
assert(sum == 1 + 4 + 9 + 16 + 25);
// Count values that pass the first filter
int count = 0;
auto newValues4 = values.filter!(a => a < 10)
.tee!(a => count++)
.map!(a => a + 1)
.filter!(a => a < 10);
//Fine, equal also evaluates any lazy ranges passed to it.
//count is not 3 until equal evaluates newValues4
assert(equal(newValues4, [2, 5]));
assert(count == 3);
}
@safe pure unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4]));
assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4]));
assert("abc".padLeft('_', 6).equal("___abc"));
}
@safe pure unittest
{
import std.range;
import std.algorithm.comparison : equal;
assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0]));
assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4]));
assert("abc".padRight('_', 6).equal("abc___"));
}
@safe unittest
{
import std.range;
import std.path : chainPath;
import std.range : chain;
void someLibraryMethod(R)(R argument)
if (isSomeFiniteCharInputRange!R)
{
// implementation detail, would iterate over each character of argument
}
someLibraryMethod("simple strings work");
someLibraryMethod(chain("chained", " ", "strings", " ", "work"));
someLibraryMethod(chainPath("chained", "paths", "work"));
// you can also use custom structs implementing a char range
}