On Sunday, 11 January 2015 at 18:01:09 UTC, bearophile wrote:
Nordlöw:
Is doCopy really needed as an argument here?
Couldn't this be inferred from the mutability of T instead?
doCopy is useful, if it's true all the permutation arrays are
distinct and dup-ped, otherwise they are all different. It's
true by default, so casual users of that generator will avoid
bugs. You can set it to false to speed up your code.
Later I have refined the idea, you can see it here, that allows
true @nogc code when needed:
struct CartesianPower(bool doCopy=true, T) {
T[] items;
uint repeat;
T[] row;
uint i, maxN;
this(T[] items_, in uint repeat_, T[] buffer) pure nothrow
@safe @nogc {
this.items = items_;
this.repeat = repeat_;
row = buffer[0 .. repeat];
row[] = items[0];
maxN = items.length ^^ repeat;
}
static if (doCopy) {
@property T[] front() pure nothrow @safe @nogc {
return row.dup;
}
} else {
@property T[] front() pure nothrow @safe @nogc {
return row;
}
}
@property bool empty() pure nothrow @safe @nogc {
return i >= maxN;
}
void popFront() pure nothrow @safe @nogc {
i++;
if (empty)
return;
uint n = i;
size_t count = repeat - 1;
while (n) {
row[count] = items[n % items.length];
count--;
n /= items.length;
}
}
}
auto cartesianPower(bool doCopy=true, T)(T[] items, in uint
repeat)
pure nothrow @safe {
return CartesianPower!(doCopy, T)(items, repeat, new
T[repeat]);
}
auto cartesianPower(bool doCopy=true, T)(T[] items, in uint
repeat, T[] buffer)
pure nothrow @safe @nogc {
if (buffer.length >= repeat) {
return CartesianPower!(doCopy, T)(items, repeat,
buffer);
} else {
// Is this correct in presence of chaining?
static immutable err = new Error("buffer.length <
repeat");
throw err;
}
}
void main() @nogc {
import core.stdc.stdio;
int[3] items = [10, 20, 30];
int[4] buf;
foreach (p; cartesianPower!false(items, 4, buf))
printf("(%d, %d, %d, %d)\n", p[0], p[1], p[2], p[3]);
}
Bye,
bearophile
Nice! PR anyone?