Enum member std.range.primitives.hasSlicing
Returns true if R offers a slicing operator with integral boundaries
that returns a forward range type.
enum hasSlicing(R)
= isForwardRange!R && !(isAutodecodableString!R && !isAggregateType!R) && is(ReturnType!((R r) => r[1..1] .length) == size_t) && (is(typeof(lvalueOf!R[1..1]) == R) || isInfinite!R) && (!is(typeof(lvalueOf!R[0..__dollar])) || is(typeof(lvalueOf!R[0..__dollar]) == R)) && (!is(typeof(lvalueOf!R[0..__dollar])) || isInfinite!R || is(typeof(lvalueOf!R[0..__dollar - 1]) == R)) && is(typeof((ref R r)
{
static assert(isForwardRange!(typeof(r[1..2])));
}
));
For finite ranges, the result of opSlice must be of the same type as the
original range type. If the range defines opDollar, then it must support
subtraction.
For infinite ranges, when not using opDollar, the result of
opSlice must be the result of take or takeExactly on the
original range (they both return the same type for infinite ranges). However,
when using opDollar, the result of opSlice must be that of the
original range type.
The following expression must be true for hasSlicing to be true:
isForwardRange!R
&& !isNarrowString!R
&& is(ReturnType!((R r) => r[1 .. 1] .length) == size_t)
&& (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R)
&& (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R))
&& (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R
|| is(typeof(lvalueOf!R[0 .. $ - 1]) == R))
&& is(typeof((ref R r)
{
static assert(isForwardRange!(typeof(r[1 .. 2])));
}));
Example
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);
Authors
Andrei Alexandrescu, David Simcha, and Jonathan M Davis. Credit for some of the ideas in building this module goes to Leonardo Maffi.