blob: eb4bc267c8b40b16dc1efe97945b9691af7afac4 [file] [log] [blame]
@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);
}