Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Issue 24541 - cartesianProduct should have a length for finite ranges #10657

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 46 additions & 10 deletions std/algorithm/setops.d
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,23 @@ if (!allSatisfy!(isForwardRange, R1, R2) ||
{
assert(canFind(BC, tuple(n[0], n[1])));
}
assert(BC.length == 9);
}

@safe unittest
{
auto A = [ 1, 2, 3 ];
auto B = [ 4, 5, 6 ];
auto AB = cartesianProduct(A, B);
auto len = AB.length;

assert(len == 9);
for (auto i = 0; i < len; i++)
{
assert(AB.length == len - i);
AB.popFront();
}

}

@safe unittest
Expand Down Expand Up @@ -250,6 +267,7 @@ if (!allSatisfy!(isForwardRange, R1, R2) ||
}

// And therefore, by set comprehension, XY == Expected
assert(XY.length == Expected.length);
}

@safe unittest
Expand Down Expand Up @@ -344,6 +362,7 @@ if (!allSatisfy!(isForwardRange, R1, R2) ||
{
assert(canFind(BC, tuple(n[0], n[1])));
}
assert(BC.length == 9);
}

// https://issues.dlang.org/show_bug.cgi?id=13091
Expand Down Expand Up @@ -371,17 +390,26 @@ if (ranges.length >= 2 &&
{
RR ranges;
RR current;
bool empty = true;
size_t length = 0;

this(RR _ranges)
{
length = 1;
ranges = _ranges;
empty = false;
foreach (i, r; ranges)
{
current[i] = r.save;
if (current[i].empty)
empty = true;
current[i] = r.save;
static if (__traits(hasMember, current[i], "length"))
{
length *= current[i].length;
}
else
{
size_t count = 0;
for (auto tmp = r.save; !tmp.empty; tmp.popFront())
++count;
length *= count;
}
}
}
@property auto front()
Expand All @@ -398,11 +426,10 @@ if (ranges.length >= 2 &&
r.popFront();
if (!r.empty) break;

static if (i == 0)
empty = true;
else
static if (i != 0)
r = ranges[i].save; // rollover
}
length--;
}
@property Result save() return scope
{
Expand All @@ -414,6 +441,10 @@ if (ranges.length >= 2 &&
}
return copy;
}
@property bool empty() return scope
{
return length == 0;
}
}
static assert(isForwardRange!Result, Result.stringof ~ " must be a forward"
~ " range");
Expand All @@ -428,13 +459,15 @@ if (ranges.length >= 2 &&
int[] a, b, c, d, e;
auto cprod = cartesianProduct(a,b,c,d,e);
assert(cprod.empty);
assert(cprod.length == 0);
foreach (_; cprod) {} // should not crash

// Test case where only one of the ranges is empty: the result should still
// be empty.
int[] p=[1], q=[];
auto cprod2 = cartesianProduct(p,p,p,q,p);
assert(cprod2.empty);
assert(cprod2.length == 0);
foreach (_; cprod2) {} // should not crash
}

Expand All @@ -443,6 +476,7 @@ if (ranges.length >= 2 &&
// .init value of cartesianProduct should be empty
auto cprod = cartesianProduct([0,0], [1,1], [2,2]);
assert(!cprod.empty);
assert(cprod.length == 8);
assert(cprod.init.empty);
}

Expand Down Expand Up @@ -519,6 +553,7 @@ if (!allSatisfy!(isForwardRange, R1, R2, RR) ||
auto C = [ "x", "y", "z" ];
auto ABC = cartesianProduct(A, B, C);

assert(ABC.length == 27);
assert(ABC.equal([
tuple(1, 'a', "x"), tuple(1, 'a', "y"), tuple(1, 'a', "z"),
tuple(1, 'b', "x"), tuple(1, 'b', "y"), tuple(1, 'b', "z"),
Expand Down Expand Up @@ -584,8 +619,9 @@ pure @safe nothrow @nogc unittest
}
}

assert(SystemRange([1, 2]).cartesianProduct(SystemRange([3, 4]))
.equal([tuple(1, 3), tuple(1, 4), tuple(2, 3), tuple(2, 4)]));
auto cprod = SystemRange([1, 2]).cartesianProduct(SystemRange([3, 4]));
assert(cprod.length == 4);
assert(cprod.equal([tuple(1, 3), tuple(1, 4), tuple(2, 3), tuple(2, 4)]));
}

// largestPartialIntersection
Expand Down
Loading