| @safe unittest | |
| { | |
| import std.range.primitives; | |
| struct A {} | |
| struct B | |
| { | |
| void popFront(); | |
| @property bool empty(); | |
| @property int front(); | |
| } | |
| static assert(!isInputRange!A); | |
| static assert( isInputRange!B); | |
| static assert( isInputRange!(int[])); | |
| static assert( isInputRange!(char[])); | |
| static assert(!isInputRange!(char[4])); | |
| static assert( isInputRange!(inout(int)[])); | |
| static assert(!isInputRange!(int[], string)); | |
| static assert( isInputRange!(int[], int)); | |
| static assert( isInputRange!(int[], const int)); | |
| static assert(!isInputRange!(int[], immutable int)); | |
| static assert(!isInputRange!(const(int)[], int)); | |
| static assert( isInputRange!(const(int)[], const int)); | |
| static assert(!isInputRange!(const(int)[], immutable int)); | |
| static assert(!isInputRange!(immutable(int)[], int)); | |
| static assert( isInputRange!(immutable(int)[], const int)); | |
| static assert( isInputRange!(immutable(int)[], immutable int)); | |
| static struct NotDefaultConstructible | |
| { | |
| @disable this(); | |
| void popFront(); | |
| @property bool empty(); | |
| @property int front(); | |
| } | |
| static assert( isInputRange!NotDefaultConstructible); | |
| static struct NotDefaultConstructibleOrCopyable | |
| { | |
| @disable this(); | |
| @disable this(this); | |
| void popFront(); | |
| @property bool empty(); | |
| @property int front(); | |
| } | |
| static assert(isInputRange!NotDefaultConstructibleOrCopyable); | |
| static struct Frontless | |
| { | |
| void popFront(); | |
| @property bool empty(); | |
| } | |
| static assert(!isInputRange!Frontless); | |
| static struct VoidFront | |
| { | |
| void popFront(); | |
| @property bool empty(); | |
| void front(); | |
| } | |
| static assert(!isInputRange!VoidFront); | |
| } | |
| @safe pure unittest | |
| { | |
| import std.range.primitives; | |
| import std.traits : isSomeChar; | |
| static struct A | |
| { | |
| string data; | |
| void put(C)(C c) | |
| if (isSomeChar!C) | |
| { | |
| data ~= c; | |
| } | |
| } | |
| static assert(isOutputRange!(A, char)); | |
| auto a = A(); | |
| put(a, "Hello"); | |
| assert(a.data == "Hello"); | |
| } | |
| @safe pure nothrow unittest | |
| { | |
| import std.range.primitives; | |
| int[] a = [1, 2, 3], b = [10, 20]; | |
| auto c = a; | |
| put(a, b); | |
| assert(c == [10, 20, 3]); | |
| // at this point, a was advanced twice, so it only contains | |
| // its last element while c represents the whole array | |
| assert(a == [3]); | |
| } | |
| @safe pure unittest | |
| { | |
| import std.range.primitives; | |
| // the elements must be mutable, so using string or const(char)[] | |
| // won't compile | |
| char[] s1 = new char[13]; | |
| auto r1 = s1; | |
| put(r1, "Hello, World!"w); | |
| assert(s1 == "Hello, World!"); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| void myprint(scope const(char)[] s) { } | |
| static assert(isOutputRange!(typeof(&myprint), char)); | |
| static assert( isOutputRange!(char[], char)); | |
| static assert( isOutputRange!(dchar[], wchar)); | |
| static assert( isOutputRange!(dchar[], dchar)); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| static assert(!isForwardRange!(int)); | |
| static assert( isForwardRange!(int[])); | |
| static assert( isForwardRange!(inout(int)[])); | |
| static assert( isForwardRange!(int[], const int)); | |
| static assert(!isForwardRange!(int[], immutable int)); | |
| static assert(!isForwardRange!(const(int)[], int)); | |
| static assert( isForwardRange!(const(int)[], const int)); | |
| static assert(!isForwardRange!(const(int)[], immutable int)); | |
| static assert(!isForwardRange!(immutable(int)[], int)); | |
| static assert( isForwardRange!(immutable(int)[], const int)); | |
| static assert( isForwardRange!(immutable(int)[], immutable int)); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| alias R = int[]; | |
| R r = [0,1]; | |
| static assert(isForwardRange!R); // is forward range | |
| r.popBack(); // can invoke popBack | |
| auto t = r.back; // can get the back of the range | |
| auto w = r.front; | |
| static assert(is(typeof(t) == typeof(w))); // same type for front and back | |
| // Checking the element type | |
| static assert( isBidirectionalRange!(int[], const int)); | |
| static assert(!isBidirectionalRange!(int[], immutable int)); | |
| static assert(!isBidirectionalRange!(const(int)[], int)); | |
| static assert( isBidirectionalRange!(const(int)[], const int)); | |
| static assert(!isBidirectionalRange!(const(int)[], immutable int)); | |
| static assert(!isBidirectionalRange!(immutable(int)[], int)); | |
| static assert( isBidirectionalRange!(immutable(int)[], const int)); | |
| static assert( isBidirectionalRange!(immutable(int)[], immutable int)); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.traits : isAggregateType, isAutodecodableString; | |
| alias R = int[]; | |
| // range is finite and bidirectional or infinite and forward. | |
| static assert(isBidirectionalRange!R || | |
| isForwardRange!R && isInfinite!R); | |
| R r = [0,1]; | |
| auto e = r[1]; // can index | |
| auto f = r.front; | |
| static assert(is(typeof(e) == typeof(f))); // same type for indexed and front | |
| static assert(!(isAutodecodableString!R && !isAggregateType!R)); // narrow strings cannot be indexed as ranges | |
| static assert(hasLength!R || isInfinite!R); // must have length or be infinite | |
| // $ must work as it does with arrays if opIndex works with $ | |
| static if (is(typeof(r[$]))) | |
| { | |
| static assert(is(typeof(f) == typeof(r[$]))); | |
| // $ - 1 doesn't make sense with infinite ranges but needs to work | |
| // with finite ones. | |
| static if (!isInfinite!R) | |
| static assert(is(typeof(f) == typeof(r[$ - 1]))); | |
| } | |
| // Checking the element type | |
| static assert( isRandomAccessRange!(int[], const int)); | |
| static assert(!isRandomAccessRange!(int[], immutable int)); | |
| static assert(!isRandomAccessRange!(const(int)[], int)); | |
| static assert( isRandomAccessRange!(const(int)[], const int)); | |
| static assert(!isRandomAccessRange!(const(int)[], immutable int)); | |
| static assert(!isRandomAccessRange!(immutable(int)[], int)); | |
| static assert( isRandomAccessRange!(immutable(int)[], const int)); | |
| static assert( isRandomAccessRange!(immutable(int)[], immutable int)); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.algorithm.iteration : map; | |
| import std.range : iota, repeat; | |
| static struct HasPostblit | |
| { | |
| this(this) {} | |
| } | |
| auto nonMobile = map!"a"(repeat(HasPostblit.init)); | |
| static assert(!hasMobileElements!(typeof(nonMobile))); | |
| static assert( hasMobileElements!(int[])); | |
| static assert( hasMobileElements!(inout(int)[])); | |
| static assert( hasMobileElements!(typeof(iota(1000)))); | |
| static assert( hasMobileElements!( string)); | |
| static assert( hasMobileElements!(dstring)); | |
| static assert( hasMobileElements!( char[])); | |
| static assert( hasMobileElements!(dchar[])); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.range : iota; | |
| // Standard arrays: returns the type of the elements of the array | |
| static assert(is(ElementType!(int[]) == int)); | |
| // Accessing .front retrieves the decoded dchar | |
| static assert(is(ElementType!(char[]) == dchar)); // rvalue | |
| static assert(is(ElementType!(dchar[]) == dchar)); // lvalue | |
| // Ditto | |
| static assert(is(ElementType!(string) == dchar)); | |
| static assert(is(ElementType!(dstring) == immutable(dchar))); | |
| // For ranges it gets the type of .front. | |
| auto range = iota(0, 10); | |
| static assert(is(ElementType!(typeof(range)) == int)); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.range : iota; | |
| // internally the range stores the encoded type | |
| static assert(is(ElementEncodingType!(char[]) == char)); | |
| static assert(is(ElementEncodingType!(wstring) == immutable(wchar))); | |
| static assert(is(ElementEncodingType!(byte[]) == byte)); | |
| auto range = iota(0, 10); | |
| static assert(is(ElementEncodingType!(typeof(range)) == int)); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| static assert(!hasSwappableElements!(const int[])); | |
| static assert(!hasSwappableElements!(const(int)[])); | |
| static assert(!hasSwappableElements!(inout(int)[])); | |
| static assert( hasSwappableElements!(int[])); | |
| static assert(!hasSwappableElements!( string)); | |
| static assert(!hasSwappableElements!(dstring)); | |
| static assert(!hasSwappableElements!( char[])); | |
| static assert( hasSwappableElements!(dchar[])); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| static assert(!hasAssignableElements!(const int[])); | |
| static assert(!hasAssignableElements!(const(int)[])); | |
| static assert( hasAssignableElements!(int[])); | |
| static assert(!hasAssignableElements!(inout(int)[])); | |
| static assert(!hasAssignableElements!( string)); | |
| static assert(!hasAssignableElements!(dstring)); | |
| static assert(!hasAssignableElements!( char[])); | |
| static assert( hasAssignableElements!(dchar[])); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.range : iota, chain; | |
| static assert( hasLvalueElements!(int[])); | |
| static assert( hasLvalueElements!(const(int)[])); | |
| static assert( hasLvalueElements!(inout(int)[])); | |
| static assert( hasLvalueElements!(immutable(int)[])); | |
| static assert(!hasLvalueElements!(typeof(iota(3)))); | |
| static assert(!hasLvalueElements!( string)); | |
| static assert( hasLvalueElements!(dstring)); | |
| static assert(!hasLvalueElements!( char[])); | |
| static assert( hasLvalueElements!(dchar[])); | |
| auto c = chain([1, 2, 3], [4, 5, 6]); | |
| static assert( hasLvalueElements!(typeof(c))); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| static assert(!hasLength!(char[])); | |
| static assert( hasLength!(int[])); | |
| static assert( hasLength!(inout(int)[])); | |
| struct A { size_t length() { return 0; } } | |
| struct B { @property size_t length() { return 0; } } | |
| static assert( hasLength!(A)); | |
| static assert( hasLength!(B)); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.range : Repeat; | |
| static assert(!isInfinite!(int[])); | |
| static assert( isInfinite!(Repeat!(int))); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.range : takeExactly; | |
| static assert( hasSlicing!(int[])); | |
| static assert( hasSlicing!(const(int)[])); | |
| static assert(!hasSlicing!(const int[])); | |
| static assert( hasSlicing!(inout(int)[])); | |
| static assert(!hasSlicing!(inout int [])); | |
| static assert( hasSlicing!(immutable(int)[])); | |
| static assert(!hasSlicing!(immutable int[])); | |
| static assert(!hasSlicing!string); | |
| static assert( hasSlicing!dstring); | |
| enum rangeFuncs = "@property int front();" ~ | |
| "void popFront();" ~ | |
| "@property bool empty();" ~ | |
| "@property auto save() { return this; }" ~ | |
| "@property size_t length();"; | |
| struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); } | |
| struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); } | |
| struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); } | |
| struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); } | |
| static assert(!hasSlicing!(A)); | |
| static assert( hasSlicing!(B)); | |
| static assert( hasSlicing!(C)); | |
| static assert(!hasSlicing!(D)); | |
| struct InfOnes | |
| { | |
| enum empty = false; | |
| void popFront() {} | |
| @property int front() { return 1; } | |
| @property InfOnes save() { return this; } | |
| auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); } | |
| auto opSlice(size_t i, Dollar d) { return this; } | |
| struct Dollar {} | |
| Dollar opDollar() const { return Dollar.init; } | |
| } | |
| static assert(hasSlicing!InfOnes); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.range : iota; | |
| assert(10.iota.walkLength == 10); | |
| // iota has a length function, and therefore the | |
| // doesn't have to be walked, and the upTo | |
| // parameter is ignored | |
| assert(10.iota.walkLength(5) == 10); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| int[] a = [ 1, 2, 3, 4, 5 ]; | |
| a.popFrontN(2); | |
| assert(a == [ 3, 4, 5 ]); | |
| a.popFrontN(7); | |
| assert(a == [ ]); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.algorithm.comparison : equal; | |
| import std.range : iota; | |
| auto LL = iota(1L, 7L); | |
| auto r = popFrontN(LL, 2); | |
| assert(equal(LL, [3L, 4L, 5L, 6L])); | |
| assert(r == 2); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| int[] a = [ 1, 2, 3, 4, 5 ]; | |
| a.popBackN(2); | |
| assert(a == [ 1, 2, 3 ]); | |
| a.popBackN(7); | |
| assert(a == [ ]); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.algorithm.comparison : equal; | |
| import std.range : iota; | |
| auto LL = iota(1L, 7L); | |
| auto r = popBackN(LL, 2); | |
| assert(equal(LL, [1L, 2L, 3L, 4L])); | |
| assert(r == 2); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| import std.algorithm.comparison : equal; | |
| import std.algorithm.iteration : filterBidirectional; | |
| auto a = [1, 2, 3]; | |
| a.popFrontExactly(1); | |
| assert(a == [2, 3]); | |
| a.popBackExactly(1); | |
| assert(a == [2]); | |
| string s = "日本語"; | |
| s.popFrontExactly(1); | |
| assert(s == "本語"); | |
| s.popBackExactly(1); | |
| assert(s == "本"); | |
| auto bd = filterBidirectional!"true"([1, 2, 3]); | |
| bd.popFrontExactly(1); | |
| assert(bd.equal([2, 3])); | |
| bd.popBackExactly(1); | |
| assert(bd.equal([2])); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| auto a = [ 1, 2, 3 ]; | |
| assert(moveFront(a) == 1); | |
| assert(a.length == 3); | |
| // define a perfunctory input range | |
| struct InputRange | |
| { | |
| enum bool empty = false; | |
| enum int front = 7; | |
| void popFront() {} | |
| int moveFront() { return 43; } | |
| } | |
| InputRange r; | |
| // calls r.moveFront | |
| assert(moveFront(r) == 43); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| struct TestRange | |
| { | |
| int payload = 5; | |
| @property bool empty() { return false; } | |
| @property TestRange save() { return this; } | |
| @property ref int front() return { return payload; } | |
| @property ref int back() return { return payload; } | |
| void popFront() { } | |
| void popBack() { } | |
| } | |
| static assert(isBidirectionalRange!TestRange); | |
| TestRange r; | |
| auto x = moveBack(r); | |
| assert(x == 5); | |
| } | |
| @safe unittest | |
| { | |
| import std.range.primitives; | |
| auto a = [1,2,3,4]; | |
| foreach (idx, it; a) | |
| { | |
| assert(it == moveAt(a, idx)); | |
| } | |
| } | |
| @safe pure nothrow unittest | |
| { | |
| import std.range.primitives; | |
| auto a = [ 1, 2, 3 ]; | |
| assert(!a.empty); | |
| assert(a[3 .. $].empty); | |
| int[string] b; | |
| assert(b.empty); | |
| b["zero"] = 0; | |
| assert(!b.empty); | |
| } | |
| @safe pure nothrow unittest | |
| { | |
| import std.range.primitives; | |
| auto a = [ 1, 2, 3 ]; | |
| auto b = a.save; | |
| assert(b is a); | |
| } | |
| @safe pure nothrow unittest | |
| { | |
| import std.range.primitives; | |
| auto a = [ 1, 2, 3 ]; | |
| a.popFront(); | |
| assert(a == [ 2, 3 ]); | |
| } | |
| @safe pure nothrow unittest | |
| { | |
| import std.range.primitives; | |
| auto a = [ 1, 2, 3 ]; | |
| a.popBack(); | |
| assert(a == [ 1, 2 ]); | |
| } | |
| @safe pure nothrow unittest | |
| { | |
| import std.range.primitives; | |
| int[] a = [ 1, 2, 3 ]; | |
| assert(a.front == 1); | |
| } | |
| @safe pure nothrow unittest | |
| { | |
| import std.range.primitives; | |
| int[] a = [ 1, 2, 3 ]; | |
| assert(a.back == 3); | |
| a.back += 4; | |
| assert(a.back == 7); | |
| } | |