mirror of
https://github.com/dlang/phobos.git
synced 2025-05-07 19:49:36 +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;
|
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));)
|
$(D auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range));)
|
||||||
|
|
||||||
|
|
|
@ -375,147 +375,6 @@ package template algoFormat()
|
||||||
alias algoFormat = format;
|
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.
|
Forwards function arguments with saving ref-ness.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue