From 3f631671f17f44c611c70c59ef3338eab2ab67b3 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Sun, 20 Jun 2021 12:38:43 -0400 Subject: [PATCH] libstdc++: Implement P2210 changes to split_view resolving LWG 3478 This implements the part of P2210R2 "Superior String Splitting" that resolves LWG 3478. libstdc++-v3/ChangeLog: * include/std/ranges (split_view::_OuterIter::__at_end): Check _M_trailing_empty. (split_view::_OuterIter::_M_trailing_empty): Define this data member. (split_view::_OuterIter::operator++): Set _M_trailing_empty appropriately. (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/split.cc (test11): New test. --- libstdc++-v3/include/std/ranges | 21 +++++++++++++++---- .../testsuite/std/ranges/adaptors/100479.cc | 6 +++--- .../testsuite/std/ranges/adaptors/split.cc | 20 ++++++++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 7cb8b2da506..5eba6913517 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.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, iterator_t<_Base>> _M_current; + bool _M_trailing_empty = false; public: using iterator_concept = conditional_t, @@ -2971,7 +2972,10 @@ namespace views::__adaptor // 3505. 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(); @@ -2980,7 +2984,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 @@ -2990,6 +2998,8 @@ namespace views::__adaptor if (__p == __pend) { __current() = __b; + if (__current() == __end) + _M_trailing_empty = true; break; } } while (++__current() != __end); @@ -3012,7 +3022,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 ba10b7baf3f..b16679075c6 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); - 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/split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc index 9d2cfa8632a..215856801ba 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc @@ -193,6 +193,25 @@ test10() VERIFY( ranges::equal(v, (std::string_view[]){"x", "x"}) ); } +void +test11() +{ + // LWG 3478 + auto v = views::split("text"sv, "text"sv); + auto i = v.begin(); + VERIFY( ranges::empty(*i++) ); + VERIFY( ranges::empty(*i++) ); + VERIFY( i == v.end() ); + + static_assert(ranges::distance(views::split(" text "sv, ' ')) == 3); + static_assert(ranges::distance(views::split(" t e x t "sv, ' ')) == 6); + static_assert(ranges::distance(views::split(" text "sv, " "sv)) == 3); + static_assert(ranges::distance(views::split(" text "sv, " "sv)) == 4); + static_assert(ranges::distance(views::split(" text "sv, " "sv)) == 4); + static_assert(ranges::distance(views::split("t"sv, 't')) == 2); + static_assert(ranges::distance(views::split("text"sv, ""sv)) == 4); +} + int main() { @@ -206,4 +225,5 @@ main() test08(); test09(); test10(); + test11(); }