diff mbox series

[3/3] libstdc++: Fix split_view::_OuterIter::operator++ [LWG 3505]

Message ID 20210329184915.3921422-3-ppalka@redhat.com
State New
Headers show
Series [1/3] libstdc++: Fix elements_view::operator* and operator[] [LWG 3502] | expand

Commit Message

Patrick Palka March 29, 2021, 6:49 p.m. UTC
libstdc++-v3/ChangeLog:

	* include/std/ranges (__detail::find): Define.
	(split_view::_OuterIter::operator++): Apply proposed resolution
	of LWG 3505.
	* testsuite/std/ranges/adaptors/split.cc (test10): New test.
---
 libstdc++-v3/include/std/ranges               | 28 ++++++++++++++++---
 .../testsuite/std/ranges/adaptors/split.cc    | 12 ++++++++
 2 files changed, 36 insertions(+), 4 deletions(-)

Comments

Jonathan Wakely April 1, 2021, 2:03 p.m. UTC | #1
On 29/03/21 14:49 -0400, Patrick Palka via Libstdc++ wrote:
>libstdc++-v3/ChangeLog:
>
>	* include/std/ranges (__detail::find): Define.
>	(split_view::_OuterIter::operator++): Apply proposed resolution
>	of LWG 3505.
>	* testsuite/std/ranges/adaptors/split.cc (test10): New test.

OK, thanks.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 9077271e4e6..baec8c0efef 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -982,6 +982,16 @@  namespace views::__adaptor
   // having to include that entire header.
   namespace __detail
   {
+    template<typename _Iter, typename _Sent, typename _Tp>
+      constexpr _Iter
+      find(_Iter __first, _Sent __last, const _Tp& __value)
+      {
+	while (__first != __last
+	       && !(bool)(*__first == __value))
+	  ++__first;
+	return __first;
+      }
+
     template<typename _Iter, typename _Sent, typename _Pred>
       constexpr _Iter
       find_if(_Iter __first, _Sent __last, _Pred __pred)
@@ -2656,21 +2666,31 @@  namespace views::__adaptor
 	  constexpr _OuterIter&
 	  operator++()
 	  {
+	    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+	    // 3505. split_view::outer-iterator::operator++ misspecified
 	    const auto __end = ranges::end(_M_parent->_M_base);
 	    if (__current() == __end)
 	      return *this;
 	    const auto [__pbegin, __pend] = subrange{_M_parent->_M_pattern};
 	    if (__pbegin == __pend)
 	      ++__current();
+	    else if constexpr (__detail::__tiny_range<_Pattern>)
+	      {
+		__current() = __detail::find(std::move(__current()), __end,
+					     *__pbegin);
+		if (__current() != __end)
+		  ++__current();
+	      }
 	    else
 	      do
 		{
 		  auto [__b, __p]
-		    = __detail::mismatch(std::move(__current()), __end,
-					 __pbegin, __pend);
-		  __current() = std::move(__b);
+		    = __detail::mismatch(__current(), __end, __pbegin, __pend);
 		  if (__p == __pend)
-		    break;
+		    {
+		      __current() = __b;
+		      break;
+		    }
 		} while (++__current() != __end);
 	    return *this;
 	  }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
index b9fb3728708..9d2cfa8632a 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
@@ -182,6 +182,17 @@  test09()
   static_assert(requires { adapt2(s); });
 }
 
+void
+test10()
+{
+  // LWG 3505
+  auto to_string = [] (auto r) {
+    return std::string(r.begin(), ranges::next(r.begin(), r.end()));
+  };
+  auto v = "xxyx"sv | views::split("xy"sv) | views::transform(to_string);
+  VERIFY( ranges::equal(v, (std::string_view[]){"x", "x"}) );
+}
+
 int
 main()
 {
@@ -194,4 +205,5 @@  main()
   test07();
   test08();
   test09();
+  test10();
 }