diff --git a/std/algorithm.d b/std/algorithm.d index 501957f7048..4dd39ae567b 100644 --- a/std/algorithm.d +++ b/std/algorithm.d @@ -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 ]; @@ -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) @@ -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 diff --git a/std/array.d b/std/array.d index 8cab16d0b26..0996255ce0e 100644 --- a/std/array.d +++ b/std/array.d @@ -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)) @@ -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)) diff --git a/std/range.d b/std/range.d index 7b45aaaa050..fc96eba1c3c 100644 --- a/std/range.d +++ b/std/range.d @@ -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).)) */ @@ -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 @@ -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; @@ -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) { @@ -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 ]; @@ -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)) @@ -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() { @@ -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 @@ -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")