mirror of
https://github.com/dlang/phobos.git
synced 2025-05-11 23:05:34 +03:00
Support multi-arg opApply/range for each.
std.algorithm.iteration.each can now be called with a lambda taking >2 args. This should work for any input range that returns a tuple and any type with a non-templated opApply that takes a multi-arg delegate. Determining the arity of a templated opApply still poses a problem, so that case is not supported. This also adds support for `each` with two ref args. When given a binary function that takes two args by ref, std.algorithm.iteration.each should use both args by ref. It was previously discarding ref on the first arg, assuming it was for an index. Resolves #15358.
This commit is contained in:
parent
e280cb6c62
commit
ed03b22bc0
1 changed files with 70 additions and 2 deletions
|
@ -848,6 +848,8 @@ See_Also: $(XREF range,tee)
|
|||
template each(alias pred = "a")
|
||||
{
|
||||
import std.meta : AliasSeq;
|
||||
import std.traits : Parameters;
|
||||
|
||||
alias BinaryArgs = AliasSeq!(pred, "i", "a");
|
||||
|
||||
enum isRangeUnaryIterable(R) =
|
||||
|
@ -868,7 +870,7 @@ template each(alias pred = "a")
|
|||
|
||||
enum isForeachBinaryIterable(R) =
|
||||
is(typeof((R r) {
|
||||
foreach (i, ref a; r)
|
||||
foreach (ref i, ref a; r)
|
||||
cast(void)binaryFun!BinaryArgs(i, a);
|
||||
}));
|
||||
|
||||
|
@ -911,10 +913,32 @@ template each(alias pred = "a")
|
|||
}
|
||||
else // if (isForeachBinaryIterable!Iterable)
|
||||
{
|
||||
foreach (i, ref e; r)
|
||||
foreach (ref i, ref e; r)
|
||||
cast(void)binaryFun!BinaryArgs(i, e);
|
||||
}
|
||||
}
|
||||
|
||||
// opApply with >2 parameters. count the delegate args.
|
||||
// only works if it is not templated (otherwise we cannot count the args)
|
||||
void each(Iterable)(Iterable r)
|
||||
if (!isRangeIterable!Iterable && !isForeachIterable!Iterable &&
|
||||
__traits(compiles, Parameters!(Parameters!(r.opApply))))
|
||||
{
|
||||
auto dg(Parameters!(Parameters!(r.opApply)) params) {
|
||||
pred(params);
|
||||
return 0; // tells opApply to continue iteration
|
||||
}
|
||||
r.opApply(&dg);
|
||||
}
|
||||
|
||||
// range interface with >2 parameters.
|
||||
void each(Range)(Range range)
|
||||
if (!isRangeIterable!Range && !isForeachIterable!Range &&
|
||||
__traits(compiles, typeof(range.front).length))
|
||||
{
|
||||
for (auto r = range; !r.empty; r.popFront())
|
||||
pred(r.front.expand);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -953,6 +977,50 @@ unittest
|
|||
})));
|
||||
}
|
||||
|
||||
// binary foreach with two ref args
|
||||
unittest
|
||||
{
|
||||
import std.range : lockstep;
|
||||
|
||||
auto a = [ 1, 2, 3 ];
|
||||
auto b = [ 2, 3, 4 ];
|
||||
|
||||
a.lockstep(b).each!((ref x, ref y) { ++x; ++y; });
|
||||
|
||||
assert(a == [ 2, 3, 4 ]);
|
||||
assert(b == [ 3, 4, 5 ]);
|
||||
}
|
||||
|
||||
// #15358: application of `each` with >2 args (opApply)
|
||||
unittest
|
||||
{
|
||||
import std.range : lockstep;
|
||||
auto a = [0,1,2];
|
||||
auto b = [3,4,5];
|
||||
auto c = [6,7,8];
|
||||
|
||||
lockstep(a, b, c).each!((ref x, ref y, ref z) { ++x; ++y; ++z; });
|
||||
|
||||
assert(a == [1,2,3]);
|
||||
assert(b == [4,5,6]);
|
||||
assert(c == [7,8,9]);
|
||||
}
|
||||
|
||||
// #15358: application of `each` with >2 args (range interface)
|
||||
unittest
|
||||
{
|
||||
import std.range : zip;
|
||||
auto a = [0,1,2];
|
||||
auto b = [3,4,5];
|
||||
auto c = [6,7,8];
|
||||
|
||||
int[] res;
|
||||
|
||||
zip(a, b, c).each!((x, y, z) { res ~= x + y + z; });
|
||||
|
||||
assert(res == [9, 12, 15]);
|
||||
}
|
||||
|
||||
/**
|
||||
$(D auto filter(Range)(Range rs) if (isInputRange!(Unqual!Range));)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue