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 && !(autodecodeStrings && 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..__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.