Date
2020-11-20.00:00:00
Message id
11629

Content

Prior to the application of P1862R1, the part of split_view::outer-iterator::operator++ that searches for the pattern is specified as:

do {
  const auto [b, p] = ranges::mismatch(current, end, pbegin, pend);
  if (p == pend) {
    current = b; // The pattern matched; skip it
    break;
  }
} while (++current != end);

P1862R1, trying to accommodate move-only iterators, respecified this as

do {
  auto [b, p] = ranges::mismatch(std::move(current), end, pbegin, pend);
  current = std::move(b);
  if (p == pend) {
    break; // The pattern matched; skip it
  }
} while (++current != end);

but this is not correct, because if the pattern didn't match, it advances current to the point of first mismatch, skipping elements before that point. This is totally wrong if the pattern contains more than one element.

Consider std::views::split("xxyx"sv, "xy"sv):

  • at the beginning, current points to the first 'x'

  • ranges::mismatch produces [iterator to second 'x', iterator to 'y' in pattern]

  • current now points to second 'x'

  • we increment current in the condition, so it now points to 'y'

At this point there's no way we can find the "xy" in the middle. In fact, in this particular example, we'll increment past the end of the source range at the end of the third iteration.