@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); }