Enum std.range.primitives.member hasSlicing
Returns true
if R
offers a slicing operator with integral boundaries
that returns a forward range type.
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 code must compile for
to be hasSlicing
true
:
R r = void; static if(isInfinite!R) typeof(take(r, 1)) s = r[1 .. 2]; else { static assert(is(typeof(r[1 .. 2]) == R)); R s = r[1 .. 2]; } s = r[1 .. 2]; static if(is(typeof(r[0 .. $]))) { static assert(is(typeof(r[0 .. $]) == R)); R t = r[0 .. $]; t = r[0 .. $]; static if(!isInfinite!R) { static assert(is(typeof(r[0 .. $ - 1]) == R)); R u = r[0 .. $ - 1]; u = r[0 .. $ - 1]; } } static assert(isForwardRange!(typeof(r[1 .. 2]))); static assert(hasLength!(typeof(r[1 .. 2])));
Declaration
enum hasSlicing(R) = isForwardRange!R && !isNarrowString!R && is(typeof((inout int = 0) { R r = R.init; static if (isInfinite!R) { typeof(r[1..1]) s = r[1..2]; } else { static assert(is(typeof(r[1..2]) == R)); R s = r[1..2]; } s = r[1..2]; static if (is(typeof(r[0..__dollar]))) { static assert(is(typeof(r[0..__dollar]) == R)); R t = r[0..__dollar]; t = r[0..__dollar]; static if (!isInfinite!R) { static assert(is(typeof(r[0..__dollar - 1]) == R)); R u = r[0..__dollar - 1]; u = r[0..__dollar - 1]; } } static assert(isForwardRange!(typeof(r[1..2]))); static assert(hasLength!(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.