mirror of
https://github.com/dlang/phobos.git
synced 2025-04-28 22:21:09 +03:00
Move each() to std.algorithm.iteration.
This commit is contained in:
parent
5cae4f0cb5
commit
fa803294a6
2 changed files with 144 additions and 141 deletions
|
@ -676,6 +676,150 @@ unittest
|
|||
auto m = immutable(S).init.repeat().map!"a".save;
|
||||
}
|
||||
|
||||
// each
|
||||
/**
|
||||
Eagerly iterates over $(D r) and calls $(D pred) over _each element.
|
||||
|
||||
Params:
|
||||
pred = predicate to apply to each element of the range
|
||||
r = range or iterable over which each iterates
|
||||
|
||||
Example:
|
||||
---
|
||||
void deleteOldBackups()
|
||||
{
|
||||
import std.algorithm, std.datetime, std.file;
|
||||
auto cutoff = Clock.currTime() - 7.days;
|
||||
dirEntries("", "*~", SpanMode.depth)
|
||||
.filter!(de => de.timeLastModified < cutoff)
|
||||
.each!remove();
|
||||
}
|
||||
---
|
||||
|
||||
If the range supports it, the value can be mutated in place. Examples:
|
||||
---
|
||||
arr.each!((ref a) => a++);
|
||||
arr.each!"a++";
|
||||
---
|
||||
|
||||
If no predicate is specified, $(D each) will default to doing nothing
|
||||
but consuming the entire range. $(D .front) will be evaluated, but this
|
||||
can be avoided by explicitly specifying a predicate lambda with a
|
||||
$(D lazy) parameter.
|
||||
|
||||
$(D each) also supports $(D opApply)-based iterators, so it will work
|
||||
with e.g. $(XREF parallelism, parallel).
|
||||
|
||||
See_Also: $(XREF range,tee)
|
||||
|
||||
*/
|
||||
template each(alias pred = "a")
|
||||
{
|
||||
import std.typetuple : TypeTuple;
|
||||
alias BinaryArgs = TypeTuple!(pred, "i", "a");
|
||||
|
||||
enum isRangeUnaryIterable(R) =
|
||||
is(typeof(unaryFun!pred(R.init.front)));
|
||||
|
||||
enum isRangeBinaryIterable(R) =
|
||||
is(typeof(binaryFun!BinaryArgs(0, R.init.front)));
|
||||
|
||||
enum isRangeIterable(R) =
|
||||
isInputRange!R &&
|
||||
(isRangeUnaryIterable!R || isRangeBinaryIterable!R);
|
||||
|
||||
enum isForeachUnaryIterable(R) =
|
||||
is(typeof((R r) {
|
||||
foreach (ref a; r)
|
||||
cast(void)unaryFun!pred(a);
|
||||
}));
|
||||
|
||||
enum isForeachBinaryIterable(R) =
|
||||
is(typeof((R r) {
|
||||
foreach (i, ref a; r)
|
||||
cast(void)binaryFun!BinaryArgs(i, a);
|
||||
}));
|
||||
|
||||
enum isForeachIterable(R) =
|
||||
(!isForwardRange!R || isDynamicArray!R) &&
|
||||
(isForeachUnaryIterable!R || isForeachBinaryIterable!R);
|
||||
|
||||
void each(Range)(Range r)
|
||||
if (isRangeIterable!Range && !isForeachIterable!Range)
|
||||
{
|
||||
debug(each) pragma(msg, "Using while for ", Range.stringof);
|
||||
static if (isRangeUnaryIterable!Range)
|
||||
{
|
||||
while (!r.empty)
|
||||
{
|
||||
cast(void)unaryFun!pred(r.front);
|
||||
r.popFront();
|
||||
}
|
||||
}
|
||||
else // if (isRangeBinaryIterable!Range)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (!r.empty)
|
||||
{
|
||||
cast(void)binaryFun!BinaryArgs(i, r.front);
|
||||
r.popFront();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void each(Iterable)(Iterable r)
|
||||
if (isForeachIterable!Iterable)
|
||||
{
|
||||
debug(each) pragma(msg, "Using foreach for ", Iterable.stringof);
|
||||
static if (isForeachUnaryIterable!Iterable)
|
||||
{
|
||||
foreach (ref e; r)
|
||||
cast(void)unaryFun!pred(e);
|
||||
}
|
||||
else // if (isForeachBinaryIterable!Iterable)
|
||||
{
|
||||
foreach (i, ref e; r)
|
||||
cast(void)binaryFun!BinaryArgs(i, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
import std.range : iota;
|
||||
|
||||
long[] arr;
|
||||
// Note: each over arrays should resolve to the
|
||||
// foreach variant, but as this is a performance
|
||||
// improvement it is not unit-testable.
|
||||
iota(5).each!(n => arr ~= n);
|
||||
assert(arr == [0, 1, 2, 3, 4]);
|
||||
|
||||
// in-place mutation
|
||||
arr.each!((ref n) => n++);
|
||||
assert(arr == [1, 2, 3, 4, 5]);
|
||||
|
||||
// by-ref lambdas should not be allowed for non-ref ranges
|
||||
static assert(!is(typeof(arr.map!(n => n).each!((ref n) => n++))));
|
||||
|
||||
// default predicate (walk / consume)
|
||||
auto m = arr.map!(n => n);
|
||||
(&m).each();
|
||||
assert(m.empty);
|
||||
|
||||
// in-place mutation with index
|
||||
arr[] = 0;
|
||||
arr.each!"a=i"();
|
||||
assert(arr == [0, 1, 2, 3, 4]);
|
||||
|
||||
// opApply iterators
|
||||
static assert(is(typeof({
|
||||
import std.parallelism;
|
||||
arr.parallel.each!"a++";
|
||||
})));
|
||||
}
|
||||
|
||||
/**
|
||||
$(D auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range));)
|
||||
|
||||
|
|
|
@ -375,147 +375,6 @@ package template algoFormat()
|
|||
alias algoFormat = format;
|
||||
}
|
||||
|
||||
// each
|
||||
/**
|
||||
Eagerly iterates over $(D r) and calls $(D pred) over _each element.
|
||||
|
||||
Params:
|
||||
pred = predicate to apply to each element of the range
|
||||
r = range or iterable over which each iterates
|
||||
|
||||
Example:
|
||||
---
|
||||
void deleteOldBackups()
|
||||
{
|
||||
import std.algorithm, std.datetime, std.file;
|
||||
auto cutoff = Clock.currTime() - 7.days;
|
||||
dirEntries("", "*~", SpanMode.depth)
|
||||
.filter!(de => de.timeLastModified < cutoff)
|
||||
.each!remove();
|
||||
}
|
||||
---
|
||||
|
||||
If the range supports it, the value can be mutated in place. Examples:
|
||||
---
|
||||
arr.each!((ref a) => a++);
|
||||
arr.each!"a++";
|
||||
---
|
||||
|
||||
If no predicate is specified, $(D each) will default to doing nothing
|
||||
but consuming the entire range. $(D .front) will be evaluated, but this
|
||||
can be avoided by explicitly specifying a predicate lambda with a
|
||||
$(D lazy) parameter.
|
||||
|
||||
$(D each) also supports $(D opApply)-based iterators, so it will work
|
||||
with e.g. $(XREF parallelism, parallel).
|
||||
|
||||
See_Also: $(XREF range,tee)
|
||||
|
||||
*/
|
||||
template each(alias pred = "a")
|
||||
{
|
||||
alias BinaryArgs = TypeTuple!(pred, "i", "a");
|
||||
|
||||
enum isRangeUnaryIterable(R) =
|
||||
is(typeof(unaryFun!pred(R.init.front)));
|
||||
|
||||
enum isRangeBinaryIterable(R) =
|
||||
is(typeof(binaryFun!BinaryArgs(0, R.init.front)));
|
||||
|
||||
enum isRangeIterable(R) =
|
||||
isInputRange!R &&
|
||||
(isRangeUnaryIterable!R || isRangeBinaryIterable!R);
|
||||
|
||||
enum isForeachUnaryIterable(R) =
|
||||
is(typeof((R r) {
|
||||
foreach (ref a; r)
|
||||
cast(void)unaryFun!pred(a);
|
||||
}));
|
||||
|
||||
enum isForeachBinaryIterable(R) =
|
||||
is(typeof((R r) {
|
||||
foreach (i, ref a; r)
|
||||
cast(void)binaryFun!BinaryArgs(i, a);
|
||||
}));
|
||||
|
||||
enum isForeachIterable(R) =
|
||||
(!isForwardRange!R || isDynamicArray!R) &&
|
||||
(isForeachUnaryIterable!R || isForeachBinaryIterable!R);
|
||||
|
||||
void each(Range)(Range r)
|
||||
if (isRangeIterable!Range && !isForeachIterable!Range)
|
||||
{
|
||||
debug(each) pragma(msg, "Using while for ", Range.stringof);
|
||||
static if (isRangeUnaryIterable!Range)
|
||||
{
|
||||
while (!r.empty)
|
||||
{
|
||||
cast(void)unaryFun!pred(r.front);
|
||||
r.popFront();
|
||||
}
|
||||
}
|
||||
else // if (isRangeBinaryIterable!Range)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (!r.empty)
|
||||
{
|
||||
cast(void)binaryFun!BinaryArgs(i, r.front);
|
||||
r.popFront();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void each(Iterable)(Iterable r)
|
||||
if (isForeachIterable!Iterable)
|
||||
{
|
||||
debug(each) pragma(msg, "Using foreach for ", Iterable.stringof);
|
||||
static if (isForeachUnaryIterable!Iterable)
|
||||
{
|
||||
foreach (ref e; r)
|
||||
cast(void)unaryFun!pred(e);
|
||||
}
|
||||
else // if (isForeachBinaryIterable!Iterable)
|
||||
{
|
||||
foreach (i, ref e; r)
|
||||
cast(void)binaryFun!BinaryArgs(i, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
long[] arr;
|
||||
// Note: each over arrays should resolve to the
|
||||
// foreach variant, but as this is a performance
|
||||
// improvement it is not unit-testable.
|
||||
iota(5).each!(n => arr ~= n);
|
||||
assert(arr == [0, 1, 2, 3, 4]);
|
||||
|
||||
// in-place mutation
|
||||
arr.each!((ref n) => n++);
|
||||
assert(arr == [1, 2, 3, 4, 5]);
|
||||
|
||||
// by-ref lambdas should not be allowed for non-ref ranges
|
||||
static assert(!is(typeof(arr.map!(n => n).each!((ref n) => n++))));
|
||||
|
||||
// default predicate (walk / consume)
|
||||
auto m = arr.map!(n => n);
|
||||
(&m).each();
|
||||
assert(m.empty);
|
||||
|
||||
// in-place mutation with index
|
||||
arr[] = 0;
|
||||
arr.each!"a=i"();
|
||||
assert(arr == [0, 1, 2, 3, 4]);
|
||||
|
||||
// opApply iterators
|
||||
static assert(is(typeof({
|
||||
import std.parallelism;
|
||||
arr.parallel.each!"a++";
|
||||
})));
|
||||
}
|
||||
|
||||
/**
|
||||
Forwards function arguments with saving ref-ness.
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue