| 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 | |
| } | |