tcbrindle / flux

A C++20 library for sequence-orientated programming
https://tristanbrindle.com/flux/
Boost Software License 1.0
441 stars 28 forks source link

cartesian_product::last() sometimes returns wrongly-initialised cursor if one of the source sequences is empty #177

Closed tcbrindle closed 4 months ago

tcbrindle commented 4 months ago

Given

auto seq = flux::cartesian_product(std::array{1, 2, 3}, flux::empty<int>);

then

assert(seq.is_empty()); // passes 
assert(seq.size() == 0); // passes
assert(seq.is_last(seq.first())); // passes
// But...
assert(seq.first() == seq.last()); // fails!

https://flux.godbolt.org/z/ocMKarfvx

(Note that if the first source sequence of cartesian_product is empty, then all four assertions pass as expected. This only shows up if the first source is non-empty, but one of the other sources is empty.)

The specification for C++23 cartesian_product_view::end() handles this by returning (in Flux terms) tuple{first(base0), first(base1), ...} if any base (from index 1 up) is empty, and tuple{last(base0), first(base1), ...} otherwise. At the moment, we unconditionally return the latter in cartesian_product_adaptor::last(), but we should change this to match the ranges behaviour.