range-v3 icon indicating copy to clipboard operation
range-v3 copied to clipboard

`zip` does not satisfy the semantic requirements of `bidirectional_iterator` when the ranges have different lengths

Open sarah-quinones opened this issue 4 years ago • 3 comments

forward_iterator requires equality_comparable, which says that equality must be transitive. this can be violated if we obtain the end iterator and decrement it until we reach the beginning of the range.

#include <range/v3/view/zip.hpp>
#include <ranges>

auto main() -> int {
  int a1[] = {0, 1, 2, 3, 4};
  int a3[] = {0, 1, 2, 3, 4, 5};

  auto rng = ranges::views::zip(a1, a3);
  static_assert(std::ranges::random_access_range<decltype(rng)>);
  auto it1 = rng.begin(); // 0, 0
  auto it2 = rng.end();   // 4, 5
  while (it1 != it2) {
    --it2;
  }
  // it2 is now 0, 1
  auto it3 = it1;
  ++it3; // 1, 1

  assert(it1 == it2);
  assert(it2 == it3);
  assert(it1 != it3);
}

sarah-quinones avatar Dec 17 '20 02:12 sarah-quinones

The situation is worse, the values pointed to by it2 as it's decremented are not in the zipped range at all. Maybe zip shouldn't be a common range?

dvirtz avatar Dec 29 '20 15:12 dvirtz

For random access , I would expect to either have a runtime check, that both ranges have the same size or just the min of the two. Consequently rng.end() should point at (5/(one-past-4)). Harder to say what should happen for cases, where the bases are bidirectional ranges.

MikeGitb avatar Dec 31 '20 22:12 MikeGitb

one potential solution would be to "align" the end iterators (and maybe cache the result?) when end is computed, if the ranges are all sized.
if the ranges aren't sized, their zipped range could be a forward range instead.

sarah-quinones avatar Jan 01 '21 15:01 sarah-quinones