This implements the part of P2210R2 "Superior String Splitting" that resolves LWG 3478 for split_view (now named lazy_split_view).
libstdc++-v3/ChangeLog: * include/std/ranges (lazy_split_view::_OuterIter::__at_end): Check _M_trailing_empty. (lazy_split_view::_OuterIter::_M_trailing_empty): Define this data member. (lazy_split_view::_OuterIter::operator++): Set _M_trailing_empty appropriately. (lazy_split_view::_OuterIter::operator==): Compare _M_trailing_empty. * testsuite/std/ranges/adaptors/100479.cc (test03): Expect two split parts instead of one. * testsuite/std/ranges/adaptors/lazy_split.cc (test11): New test. --- libstdc++-v3/include/std/ranges | 21 +++++++++++++++---- .../testsuite/std/ranges/adaptors/100479.cc | 6 +++--- .../std/ranges/adaptors/lazy_split.cc | 15 +++++++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index cc1ef112ff1..78562924bee 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -2879,7 +2879,7 @@ namespace views::__adaptor constexpr bool __at_end() const - { return __current() == ranges::end(_M_parent->_M_base); } + { return __current() == ranges::end(_M_parent->_M_base) && !_M_trailing_empty; } // [range.lazy.split.outer] p1 // Many of the following specifications refer to the notional member @@ -2909,6 +2909,7 @@ namespace views::__adaptor [[no_unique_address]] __detail::__maybe_present_t<forward_range<_Vp>, iterator_t<_Base>> _M_current; + bool _M_trailing_empty = false; public: using iterator_concept = conditional_t<forward_range<_Base>, @@ -2977,7 +2978,10 @@ namespace views::__adaptor // 3505. lazy_split_view::outer-iterator::operator++ misspecified const auto __end = ranges::end(_M_parent->_M_base); if (__current() == __end) - return *this; + { + _M_trailing_empty = false; + return *this; + } const auto [__pbegin, __pend] = subrange{_M_parent->_M_pattern}; if (__pbegin == __pend) ++__current(); @@ -2986,7 +2990,11 @@ namespace views::__adaptor __current() = ranges::find(std::move(__current()), __end, *__pbegin); if (__current() != __end) - ++__current(); + { + ++__current(); + if (__current() == __end) + _M_trailing_empty = true; + } } else do @@ -2996,6 +3004,8 @@ namespace views::__adaptor if (__p == __pend) { __current() = __b; + if (__current() == __end) + _M_trailing_empty = true; break; } } while (++__current() != __end); @@ -3018,7 +3028,10 @@ namespace views::__adaptor friend constexpr bool operator==(const _OuterIter& __x, const _OuterIter& __y) requires forward_range<_Base> - { return __x._M_current == __y._M_current; } + { + return __x._M_current == __y._M_current + && __x._M_trailing_empty == __y._M_trailing_empty; + } friend constexpr bool operator==(const _OuterIter& __x, default_sentinel_t) diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc index 9899ff92c0b..b8c1e6f4f57 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc @@ -95,11 +95,11 @@ test03() | views::drop_while([](auto) { return false; }) | views::filter([](auto) { return true; }); static_assert(ranges::forward_range<decltype(v)>); - VERIFY( ranges::next(v.begin()) == v.end() ); + VERIFY( ranges::distance(v) == 2 ); auto w = v; - VERIFY( ranges::next(w.begin()) == w.end() ); + VERIFY( ranges::distance(v) == 2 ); auto z = std::move(w); - VERIFY( ranges::next(z.begin()) == z.end() ); + VERIFY( ranges::distance(v) == 2 ); return true; } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc index 12844525d86..133e9a7025b 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc @@ -193,6 +193,20 @@ test10() VERIFY( ranges::equal(v, (std::string_view[]){"x", "x"}) ); } +void +test11() +{ + // LWG 3478 + static_assert(ranges::distance(views::lazy_split("text"sv, "text"sv)) == 2); + static_assert(ranges::distance(views::lazy_split(" text "sv, ' ')) == 3); + static_assert(ranges::distance(views::lazy_split(" t e x t "sv, ' ')) == 6); + static_assert(ranges::distance(views::lazy_split(" text "sv, " "sv)) == 3); + static_assert(ranges::distance(views::lazy_split(" text "sv, " "sv)) == 4); + static_assert(ranges::distance(views::lazy_split(" text "sv, " "sv)) == 4); + static_assert(ranges::distance(views::lazy_split("t"sv, 't')) == 2); + static_assert(ranges::distance(views::lazy_split("text"sv, ""sv)) == 4); +} + int main() { @@ -206,4 +220,5 @@ main() test08(); test09(); test10(); + test11(); } -- 2.32.0.93.g670b81a890