Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions std/algorithm.d
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ Example:
int[] arr = [ 1, 2, 3, 4, 5 ];
// Sum all elements
auto small = filter!("a < 3")(arr);
assert(small == [ 1, 2 ]);
assert(equal(small, [ 1, 2 ]));
// In combination with chain() to span multiple ranges
int[] a = [ 3, -2, 400 ];
int[] b = [ 100, -101, 102 ];
Expand All @@ -800,7 +800,7 @@ assert(equal(r, [ 3, 400, 100, 102 ]));
// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = filter!("cast(int) a != a")(chain(c, a, b));
assert(r1 == [ 2.5 ]);
assert(equal(r1, [ 2.5 ]));
----
*/
template filter(alias pred)
Expand Down Expand Up @@ -5366,7 +5366,7 @@ unittest

/**
Reduces the length of the bidirectional range $(D range) by only
keeping elements that satisfy $(D pred). If $(s =
keeping elements that satisfy $(D pred). If $(D s =
SwapStrategy.unstable), elements are moved from the right end of the
range over the elements to eliminate. If $(D s = SwapStrategy.stable)
(the default), elements are moved progressively to front such that
Expand Down
14 changes: 14 additions & 0 deletions std/array.d
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,13 @@ unittest
/**
Inserts $(D stuff) (which must be an input range or a single item) in
$(D array) at position $(D pos).

Example:
---
int[] a = [ 1, 2, 3, 4 ];
a.insert(2, [ 1, 2 ]);
assert(a == [ 1, 2, 1, 2, 3, 4 ]);
---
*/
void insert(T, Range)(ref T[] array, size_t pos, Range stuff)
if (isInputRange!Range && is(ElementEncodingType!Range : T))
Expand Down Expand Up @@ -819,6 +826,13 @@ unittest
Replaces elements from $(D array) with indices ranging from $(D from)
(inclusive) to $(D to) (exclusive) with the range $(D stuff). Expands
or shrinks the array as needed.

Example:
---
int[] a = [ 1, 2, 3, 4 ];
a.replace(1, 3, [ 9, 9, 9 ]);
assert(a == [ 1, 9, 9, 9, 4 ]);
---
*/
void replace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
if (isDynamicArray!Range && is(ElementType!Range : T))
Expand Down
79 changes: 54 additions & 25 deletions std/range.d
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ $(UL $(LI $(D r.empty) returns $(D false) iff there is more data
available in the range.) $(LI $(D r.front) returns the current element
in the range. It may return by value or by reference. Calling $(D
r.front) is allowed only if calling $(D r.empty) has, or would have,
returned $(D false).) $(LI $(D r.popFront) advances to the popFront element in
returned $(D false).) $(LI $(D r.popFront) advances to the next element in
the range. Calling $(D r.popFront) is allowed only if calling $(D r.empty)
has, or would have, returned $(D false).))
*/
Expand Down Expand Up @@ -2125,6 +2125,13 @@ unittest
static assert(is(Radial!(immutable int[])));
}

// Detect whether T can be sliced safely, i.e. whether it
// a) can be sliced, and b) is not a narrow string.
private template isSafelySlicable(T)
{
enum isSafelySlicable = hasSlicing!T && !isNarrowString!T;
}

/**
Lazily takes only up to $(D n) elements of a range. This is
particulary useful when using with infinite ranges. If the range
Expand All @@ -2140,8 +2147,8 @@ assert(equal(s, [ 1, 2, 3, 4, 5 ][]));
----
*/
struct Take(Range)
if(isInputRange!(Unqual!Range) &&
(!hasSlicing!(Unqual!Range) || isNarrowString!(Unqual!Range)))
if(isInputRange!(Unqual!Range) && !isSafelySlicable!(Unqual!Range)
&& !is(Unqual!Range T == Take!T))
{
alias Unqual!Range R;
R original;
Expand Down Expand Up @@ -2271,33 +2278,23 @@ public:
}
}

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

/// Ditto
R take(R)(R input, size_t n)
if((isInputRange!(Unqual!R) && (!hasSlicing!(Unqual!R) || isNarrowString!(Unqual!R)))
&& is (R T == Take!T))
Take!(R) take(R)(R input, size_t n)
if(isInputRange!(Unqual!R) && !isSafelySlicable!(Unqual!R)
&& !is(Unqual!R T == Take!T))
{
return R(input.original, min(n, input.maxLength));
return Take!(R)(input, n);
}

/// Ditto
Take!(R) take(R)(R input, size_t n)
if((isInputRange!(Unqual!R) && (!hasSlicing!(Unqual!R) || isNarrowString!(Unqual!R)))
&& !is (R T == Take!T))
// For the case when R can be safely sliced.
template Take(R)
if(isInputRange!(Unqual!R) && isSafelySlicable!(Unqual!R))
{
return Take!(R)(input, n);
alias typeof(R[0 .. 1]) Take;
}

/// Ditto
Take!(R) take(R)(R input, size_t n)
if(isInputRange!(Unqual!R) && hasSlicing!(Unqual!R) && !isNarrowString!(Unqual!R))
if(isInputRange!(Unqual!R) && isSafelySlicable!(Unqual!R))
{
static if (hasLength!R)
{
Expand All @@ -2313,6 +2310,21 @@ if(isInputRange!(Unqual!R) && hasSlicing!(Unqual!R) && !isNarrowString!(Unqual!R
}
}

// For the case when R is a Take struct
template Take(R)
if(isInputRange!(Unqual!R) && !isSafelySlicable!(Unqual!R)
&& is(Unqual!R T == Take!T))
{
alias R Take;
}

Take!(R) take(R)(R input, size_t n)
if(isInputRange!(Unqual!R) && !isSafelySlicable!(Unqual!R)
&& is(Unqual!R T == Take!T))
{
return R(input.original, min(n, input.maxLength));
}

unittest
{
int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
Expand Down Expand Up @@ -2369,6 +2381,23 @@ unittest
static assert(is(Take!(typeof(myRepeat))));
}

unittest
{
// Check that one can declare variables of all Take types,
// and that they match the return type of the corresponding
// take(). (See issue 4464.)
int[] r1;
Take!(int[]) t1;
t1 = take(r1, 1);

string r2;
Take!string t2;
t2 = take(r2, 1);

Take!(Take!string) t3;
t3 = take(t2, 1);
}

/**
Similar to $(XREF range,take), but assumes the length of $(D range) is
at least $(D n). As such, the result of $(D takeExactly(range, n))
Expand Down Expand Up @@ -3023,7 +3052,7 @@ stopping policy.
}

/**
Advances to the popFront element in all controlled ranges.
Advances to the next element in all controlled ranges.
*/
void popFront()
{
Expand Down Expand Up @@ -3583,7 +3612,7 @@ unittest {

/**
Creates a mathematical sequence given the initial values and a
recurrence function that computes the popFront value from the existing
recurrence function that computes the next value from the existing
values. The sequence comes in the form of an infinite forward
range. The type $(D Recurrence) itself is seldom used directly; most
often, recurrences are obtained by calling the function $(D
Expand All @@ -3593,7 +3622,7 @@ When calling $(D recurrence), the function that computes the next
value is specified as a template argument, and the initial values in
the recurrence are passed as regular arguments. For example, in a
Fibonacci sequence, there are two initial values (and therefore a
state size of 2) because computing the popFront Fibonacci value needs the
state size of 2) because computing the next Fibonacci value needs the
past two values.

If the function is passed in string form, the state has name $(D "a")
Expand Down