116 changes: 99 additions & 17 deletions std/range/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -1783,18 +1783,20 @@ if (isInputRange!(Unqual!Range) &&
{
private alias R = Unqual!Range;

// User accessible in read and write
/// User accessible in read and write
public R source;

private size_t _maxAvailable;

alias Source = R;

/// Range primitives
@property bool empty()
{
return _maxAvailable == 0 || source.empty;
}

/// ditto
@property auto ref front()
{
assert(!empty,
Expand All @@ -1803,6 +1805,7 @@ if (isInputRange!(Unqual!Range) &&
return source.front;
}

/// ditto
void popFront()
{
assert(!empty,
Expand All @@ -1813,12 +1816,14 @@ if (isInputRange!(Unqual!Range) &&
}

static if (isForwardRange!R)
/// ditto
@property Take save()
{
return Take(source.save, _maxAvailable);
}

static if (hasAssignableElements!R)
/// ditto
@property auto front(ElementType!R v)
{
assert(!empty,
Expand All @@ -1830,6 +1835,7 @@ if (isInputRange!(Unqual!Range) &&

static if (hasMobileElements!R)
{
/// ditto
auto moveFront()
{
assert(!empty,
Expand All @@ -1841,15 +1847,18 @@ if (isInputRange!(Unqual!Range) &&

static if (isInfinite!R)
{
/// ditto
@property size_t length() const
{
return _maxAvailable;
}

/// ditto
alias opDollar = length;

//Note: Due to Take/hasSlicing circular dependency,
//This needs to be a restrained template.
/// ditto
auto opSlice()(size_t i, size_t j)
if (hasSlicing!R)
{
Expand All @@ -1861,6 +1870,7 @@ if (isInputRange!(Unqual!Range) &&
}
else static if (hasLength!R)
{
/// ditto
@property size_t length()
{
import std.algorithm : min;
Expand All @@ -1872,6 +1882,7 @@ if (isInputRange!(Unqual!Range) &&

static if (isRandomAccessRange!R)
{
/// ditto
void popBack()
{
assert(!empty,
Expand All @@ -1880,6 +1891,7 @@ if (isInputRange!(Unqual!Range) &&
--_maxAvailable;
}

/// ditto
@property auto ref back()
{
assert(!empty,
Expand All @@ -1888,6 +1900,7 @@ if (isInputRange!(Unqual!Range) &&
return source[this.length - 1];
}

/// ditto
auto ref opIndex(size_t index)
{
assert(index < length,
Expand All @@ -1898,6 +1911,7 @@ if (isInputRange!(Unqual!Range) &&

static if (hasAssignableElements!R)
{
/// ditto
@property auto back(ElementType!R v)
{
// This has to return auto instead of void because of Bug 4706.
Expand All @@ -1907,6 +1921,7 @@ if (isInputRange!(Unqual!Range) &&
source[this.length - 1] = v;
}

/// ditto
void opIndexAssign(ElementType!R v, size_t index)
{
assert(index < length,
Expand All @@ -1918,6 +1933,7 @@ if (isInputRange!(Unqual!Range) &&

static if (hasMobileElements!R)
{
/// ditto
auto moveBack()
{
assert(!empty,
Expand All @@ -1926,6 +1942,7 @@ if (isInputRange!(Unqual!Range) &&
return source.moveAt(this.length - 1);
}

/// ditto
auto moveAt(size_t index)
{
assert(index < length,
Expand All @@ -1936,23 +1953,17 @@ if (isInputRange!(Unqual!Range) &&
}
}

// Nonstandard
/**
Access to maximal length of the range.
Note: the actual length of the range depends on the underlying range.
If it has fewer elements, it will stop before maxLength is reached.
*/
@property size_t maxLength() const
{
return _maxAvailable;
}
}

// This template simply aliases itself to R and is useful for consistency in
// generic code.
template Take(R)
if (isInputRange!(Unqual!R) &&
((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
{
alias Take = R;
}

// take for finite ranges with slicing
/// ditto
Take!R take(R)(R input, size_t n)
if (isInputRange!(Unqual!R) && !isInfinite!(Unqual!R) && hasSlicing!(Unqual!R) &&
Expand All @@ -1964,6 +1975,17 @@ if (isInputRange!(Unqual!R) && !isInfinite!(Unqual!R) && hasSlicing!(Unqual!R) &
return input[0 .. min(n, input.length)];
}

/**
This template simply aliases itself to R and is useful for consistency in
generic code.
*/
template Take(R)
if (isInputRange!(Unqual!R) &&
((!isInfinite!(Unqual!R) && hasSlicing!(Unqual!R)) || is(R T == Take!T)))
{
alias Take = R;
}

///
@safe unittest
{
Expand Down Expand Up @@ -1991,15 +2013,15 @@ if (isInputRange!(Unqual!R) && !isInfinite!(Unqual!R) && hasSlicing!(Unqual!R) &
assert(equal(t, [ 1, 2, 3 ]));
}

// take(take(r, n1), n2)
/// ditto
Take!R take(R)(R input, size_t n)
if (is(R T == Take!T))
{
import std.algorithm : min;
return R(input.source, min(n, input._maxAvailable));
}

// Regular take for input ranges
/// ditto
Take!(R) take(R)(R input, size_t n)
if (isInputRange!(Unqual!R) && (isInfinite!(Unqual!R) || !hasSlicing!(Unqual!R) && !is(R T == Take!T)))
{
Expand Down Expand Up @@ -2887,13 +2909,28 @@ private:
UT _value;

public:
/// Range primitives
@property inout(T) front() inout { return _value; }

/// ditto
@property inout(T) back() inout { return _value; }

/// ditto
enum bool empty = false;

/// ditto
void popFront() {}

/// ditto
void popBack() {}

/// ditto
@property auto save() inout { return this; }

/// ditto
inout(T) opIndex(size_t) inout { return _value; }

/// ditto
auto opSlice(size_t i, size_t j)
in
{
Expand All @@ -2904,7 +2941,11 @@ public:
return this.takeExactly(j - i);
}
private static struct DollarToken {}

/// ditto
enum opDollar = DollarToken.init;

/// ditto
auto opSlice(size_t, DollarToken) inout { return this; }
}

Expand Down Expand Up @@ -3055,14 +3096,17 @@ private:
alias fun = Fun[0];

public:
/// Range primitives
enum empty = false;

/// ditto
auto ref front() @property
{
return fun();
}

void popFront() { }
/// ditto
void popFront() {}
}

@safe unittest
Expand Down Expand Up @@ -3111,19 +3155,22 @@ struct Cycle(R)
private R _original;
private size_t _index;

/// Range primitives
this(R input, size_t index = 0)
{
_original = input;
_index = index % _original.length;
}

/// ditto
@property auto ref front()
{
return _original[_index];
}

static if (is(typeof((cast(const R)_original)[_index])))
{
/// ditto
@property auto ref front() const
{
return _original[_index];
Expand All @@ -3132,21 +3179,25 @@ struct Cycle(R)

static if (hasAssignableElements!R)
{
/// ditto
@property auto front(ElementType!R val)
{
_original[_index] = val;
}
}

/// ditto
enum bool empty = false;

/// ditto
void popFront()
{
++_index;
if (_index >= _original.length)
_index = 0;
}

/// ditto
auto ref opIndex(size_t n)
{
return _original[(n + _index) % _original.length];
Expand All @@ -3155,6 +3206,7 @@ struct Cycle(R)
static if (is(typeof((cast(const R)_original)[_index])) &&
is(typeof((cast(const R)_original).length)))
{
/// ditto
auto ref opIndex(size_t n) const
{
return _original[(n + _index) % _original.length];
Expand All @@ -3163,21 +3215,26 @@ struct Cycle(R)

static if (hasAssignableElements!R)
{
/// ditto
auto opIndexAssign(ElementType!R val, size_t n)
{
_original[(n + _index) % _original.length] = val;
}
}

/// ditto
@property Cycle save()
{
//No need to call _original.save, because Cycle never actually modifies _original
return Cycle(_original, _index);
}

private static struct DollarToken {}

/// ditto
enum opDollar = DollarToken.init;

/// ditto
auto opSlice(size_t i, size_t j)
in
{
Expand All @@ -3188,6 +3245,7 @@ struct Cycle(R)
return this[i .. $].takeExactly(j - i);
}

/// ditto
auto opSlice(size_t i, DollarToken)
{
return typeof(this)(_original, _index + i);
Expand All @@ -3198,19 +3256,22 @@ struct Cycle(R)
private R _original;
private R _current;

/// ditto
this(R input)
{
_original = input;
_current = input.save;
}

/// ditto
@property auto ref front()
{
return _current.front;
}

static if (is(typeof((cast(const R)_current).front)))
{
/// ditto
@property auto ref front() const
{
return _current.front;
Expand All @@ -3219,21 +3280,25 @@ struct Cycle(R)

static if (hasAssignableElements!R)
{
/// ditto
@property auto front(ElementType!R val)
{
return _current.front = val;
}
}

/// ditto
enum bool empty = false;

/// ditto
void popFront()
{
_current.popFront();
if (_current.empty)
_current = _original.save;
}

/// ditto
@property Cycle save()
{
//No need to call _original.save, because Cycle never actually modifies _original
Expand All @@ -3245,12 +3310,14 @@ struct Cycle(R)
}
}

/// ditto
template Cycle(R)
if (isInfinite!R)
{
alias Cycle = R;
}

///
struct Cycle(R)
if (isStaticArray!R)
{
Expand All @@ -3259,12 +3326,15 @@ struct Cycle(R)
private size_t _index;

nothrow:

/// Range primitives
this(ref R input, size_t index = 0) @system
{
_ptr = input.ptr;
_index = index % R.length;
}

/// ditto
@property ref inout(ElementType) front() inout @safe
{
static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
Expand All @@ -3274,15 +3344,18 @@ nothrow:
return trustedPtrIdx(_ptr, _index);
}

/// ditto
enum bool empty = false;

/// ditto
void popFront() @safe
{
++_index;
if (_index >= R.length)
_index = 0;
}

/// ditto
ref inout(ElementType) opIndex(size_t n) inout @safe
{
static ref auto trustedPtrIdx(typeof(_ptr) p, size_t idx) @trusted
Expand All @@ -3292,14 +3365,17 @@ nothrow:
return trustedPtrIdx(_ptr, n + _index);
}

/// ditto
@property inout(Cycle) save() inout @safe
{
return this;
}

private static struct DollarToken {}
/// ditto
enum opDollar = DollarToken.init;

/// ditto
auto opSlice(size_t i, size_t j) @safe
in
{
Expand All @@ -3310,6 +3386,7 @@ nothrow:
return this[i .. $].takeExactly(j - i);
}

/// ditto
inout(typeof(this)) opSlice(size_t i, DollarToken) inout @safe
{
static auto trustedCtor(typeof(_ptr) p, size_t idx) @trusted
Expand Down Expand Up @@ -3349,12 +3426,14 @@ Cycle!R cycle(R)(R input, size_t index = 0)
return Cycle!R(input, index);
}

/// Ditto
Cycle!R cycle(R)(R input)
if (isInfinite!R)
{
return input;
}

/// Ditto
Cycle!R cycle(R)(ref R input, size_t index = 0) @system
if (isStaticArray!R)
{
Expand Down Expand Up @@ -3553,9 +3632,9 @@ struct Zip(Ranges...)
import std.typecons : Tuple;

alias R = Ranges;
R ranges;
private R ranges;
alias ElementType = Tuple!(staticMap!(.ElementType, R));
StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;
private StoppingPolicy stoppingPolicy = StoppingPolicy.shortest;

/**
Builds an object. Usually this is invoked indirectly by using the
Expand All @@ -3580,6 +3659,7 @@ struct Zip(Ranges...)
}
else
{
///
@property bool empty()
{
import std.exception : enforce;
Expand Down Expand Up @@ -3620,6 +3700,7 @@ struct Zip(Ranges...)

static if (allSatisfy!(isForwardRange, R))
{
///
@property Zip save()
{
//Zip(ranges[0].save, ranges[1].save, ..., stoppingPolicy)
Expand Down Expand Up @@ -4249,6 +4330,7 @@ private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
struct Lockstep(Ranges...)
if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
{
///
this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest)
{
import std.exception : enforce;
Expand Down
8 changes: 2 additions & 6 deletions std/range/primitives.d
Original file line number Diff line number Diff line change
Expand Up @@ -1995,7 +1995,6 @@ arrays. Due to the fact that nonmember functions can be called with
the first argument using the dot notation, $(D array.empty) is
equivalent to $(D empty(array)).
*/

@property bool empty(T)(in T[] a) @safe pure nothrow @nogc
{
return !a.length;
Expand All @@ -2016,7 +2015,6 @@ the first argument using the dot notation, $(D array.save) is
equivalent to $(D save(array)). The function does not duplicate the
content of the array, it simply returns its argument.
*/

@property T[] save(T)(T[] a) @safe pure nothrow @nogc
{
return a;
Expand All @@ -2038,7 +2036,6 @@ equivalent to $(D popFront(array)). For $(GLOSSARY narrow strings),
$(D popFront) automatically advances to the next $(GLOSSARY code
point).
*/

void popFront(T)(ref T[] a) @safe pure nothrow @nogc
if (!isNarrowString!(T[]) && !is(T[] == void[]))
{
Expand All @@ -2061,7 +2058,7 @@ version(unittest)
static assert(!is(typeof({ void[] a; popFront(a); })));
}

// Specialization for narrow strings. The necessity of
/// ditto
void popFront(C)(ref C[] str) @trusted pure nothrow
if (isNarrowString!(C[]))
{
Expand Down Expand Up @@ -2137,7 +2134,6 @@ the first argument using the dot notation, $(D array.popBack) is
equivalent to $(D popBack(array)). For $(GLOSSARY narrow strings), $(D
popFront) automatically eliminates the last $(GLOSSARY code point).
*/

void popBack(T)(ref T[] a) @safe pure nothrow @nogc
if (!isNarrowString!(T[]) && !is(T[] == void[]))
{
Expand All @@ -2160,7 +2156,7 @@ version(unittest)
static assert(!is(typeof({ void[] a; popBack(a); })));
}

// Specialization for arrays of char
/// ditto
void popBack(T)(ref T[] a) @safe pure
if (isNarrowString!(T[]))
{
Expand Down