[gcc(refs/users/ppalka/heads/libstdcxx-constrained-algos)] Make ranges::copy and ranges::move unmoveable-iterator-safe

Patrick Palka ppalka@gcc.gnu.org
Wed Jan 22 22:34:00 GMT 2020


https://gcc.gnu.org/g:9800597b81fc95c3dbe3e46a2657d4bd0fb59921

commit 9800597b81fc95c3dbe3e46a2657d4bd0fb59921
Author: Patrick Palka <ppalka@redhat.com>
Date:   Wed Jan 22 17:07:31 2020 -0500

    Make ranges::copy and ranges::move unmoveable-iterator-safe

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h            | 54 +++++++++++-----------
 .../testsuite/25_algorithms/copy/constrained.cc    | 21 +++++----
 .../testsuite/25_algorithms/move/constrained.cc    | 21 +++++----
 3 files changed, 49 insertions(+), 47 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 6788085..8ea616b 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -816,16 +816,14 @@ namespace ranges
   template<typename _Iter, typename _Out>
   using move_result = copy_result<_Iter, _Out>;
 
-  template<bool _IsMove,
-	   input_iterator _Iter, sentinel_for<_Iter> _Sent,
-	   weakly_incrementable _Out>
+  template<bool _IsMove, typename _Iter, typename _Sent, typename _Out>
     requires (_IsMove
-	      ? indirectly_movable<_Iter, _Out>
-	      : indirectly_copyable<_Iter, _Out>)
+	      ? indirectly_movable<remove_reference_t<_Iter>, _Out>
+	      : indirectly_copyable<remove_reference_t<_Iter>, _Out>)
     constexpr conditional_t<_IsMove,
-			    move_result<_Iter, _Out>,
-			    copy_result<_Iter, _Out>>
-    __copy_or_move(_Iter __first, _Sent __last, _Out __result)
+			    move_result<remove_reference_t<_Iter>, _Out>,
+			    copy_result<remove_reference_t<_Iter>, _Out>>
+    __copy_or_move(_Iter&& __first, _Sent __last, _Out __result)
     {
       // TODO: implement more specializations to be at least on par with
       // std::copy/std::move.
@@ -860,7 +858,7 @@ namespace ranges
 		  __first++;
 		  __result++;
 		}
-	      return {__first, __result};
+	      return {std::move(__first), std::move(__result)};
 	    }
 	}
       else
@@ -874,7 +872,7 @@ namespace ranges
 	      __first++;
 	      __result++;
 	    }
-	  return {__first, __result};
+	  return {std::move(__first), std::move(__result)};
 	}
     }
 
@@ -887,24 +885,24 @@ namespace ranges
       constexpr bool __move_iterator_p = __is_move_iterator<_Iter>::__value;
       if constexpr (__move_iterator_p)
 	{
-	  auto __first_base = __first.base();
-	  auto __last_base = __last.base();
+	  auto __first_base = std::move(__first).base();
+	  auto __last_base = std::move(__last).base();
 	  auto [__in,__out]
-	    = ranges::__copy_or_move<true>(std::__niter_base(__first_base),
-					   std::__niter_base(__last_base),
-					   std::__niter_base(__result));
-	  auto __wrapped_in = std::__niter_wrap(__first_base, __in);
-	  auto __wrapped_out = std::__niter_wrap(__result, __out);
-	  return {move_iterator{__wrapped_in}, __wrapped_out};
+	    = ranges::__copy_or_move<true>(std::__niter_base(std::move(__first_base)),
+					   std::__niter_base(std::move(__last_base)),
+					   std::__niter_base(std::move(__result)));
+	  auto __wrapped_in = std::__niter_wrap(__first_base, std::move(__in));
+	  auto __wrapped_out = std::__niter_wrap(__result, std::move(__out));
+	  return {move_iterator{std::move(__wrapped_in)}, std::move(__wrapped_out)};
 	}
       else
 	{
 	  auto [__in,__out]
-	    = ranges::__copy_or_move<false>(std::__niter_base(__first),
-					    std::__niter_base(__last),
-					    std::__niter_base(__result));
-	  return {std::__niter_wrap(__first, __in),
-		  std::__niter_wrap(__result, __out)};
+	    = ranges::__copy_or_move<false>(std::__niter_base(std::move(__first)),
+					    std::__niter_base(std::move(__last)),
+					    std::__niter_base(std::move(__result)));
+	  return {std::__niter_wrap(std::move(__first), std::move(__in)),
+		  std::__niter_wrap(std::move(__result), std::move(__out))};
 	}
     }
 
@@ -924,13 +922,15 @@ namespace ranges
     move(_Iter __first, _Sent __last, _Out __result)
     {
       if constexpr (__is_move_iterator<_Iter>::__value)
-	return ranges::copy(__first, __last, __result);
+	return ranges::copy(std::move(__first), std::move(__last),
+			    std::move(__result));
       else
 	{
 	  auto [__in, __out]
-	    = ranges::copy(move_iterator<_Iter>{__first},
-			   move_sentinel<_Sent>{__last}, __result);
-	  return {__in.base(), __out};
+	    = ranges::copy(move_iterator<_Iter>{std::move(__first)},
+			   move_sentinel<_Sent>{std::move(__last)},
+			   std::move(__result));
+	  return {std::move(__in).base(), std::move(__out)};
 	}
     }
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc
index f1b94ff..f6cddc5 100644
--- a/libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc
@@ -25,8 +25,8 @@
 using __gnu_test::test_container;
 using __gnu_test::test_range;
 using __gnu_test::input_iterator_wrapper;
+using __gnu_test::output_iterator_wrapper;
 using __gnu_test::forward_iterator_wrapper;
-using __gnu_test::bidirectional_iterator_wrapper;
 
 namespace ranges = std::ranges;
 
@@ -48,8 +48,8 @@ test01()
       int z[3] = { 1, 2, 3 };
       test_container<int, forward_iterator_wrapper> cx(x);
       test_container<char, forward_iterator_wrapper> cy(y);
-      auto [in, out] = ranges::copy(x, y);
-      VERIFY( ranges::equal(x, x+3, y, y+3) && in == x+3 && out == y+3 );
+      auto [in, out] = ranges::copy(cx, ranges::begin(cy));
+      VERIFY( ranges::equal(x, x+3, y, y+3) && in.ptr == x+3 && out.ptr == y+3 );
       VERIFY( ranges::equal(x, z) );
     }
 
@@ -57,10 +57,10 @@ test01()
       char x[3] = { 1, 2, 3 };
       int y[4] = { 0 };
       int z[3] = { 1, 2, 3 };
-      test_range<char, forward_iterator_wrapper> cx(x);
-      test_range<int, forward_iterator_wrapper> cy(y);
-      auto [in, out] = ranges::copy(x, y);
-      VERIFY( ranges::equal(x, x+3, y, y+3) && in == x+3 && out == y+3 );
+      test_range<char, input_iterator_wrapper> rx(x);
+      test_range<int, output_iterator_wrapper> ry(y);
+      auto [in, out] = ranges::copy(rx, ranges::begin(ry));
+      VERIFY( ranges::equal(x, x+3, y, y+3) && in.ptr == x+3 && out.ptr == y+3 );
       VERIFY( ranges::equal(x, z) );
     }
 }
@@ -135,10 +135,11 @@ test04()
   Y x[7] = { 1, 2, 3, 4, 5, 6, 7 };
   Y y[7] = { 0, 0, 0, 0, 0, 0, 0 };
   Y z[7] = { 1, 2, 3, 4, 5, 6, 7 };
-  auto [in, out] = ranges::copy(std::move_iterator{ranges::begin(x)},
-				std::move_sentinel{ranges::end(x)},
+  test_range<Y, input_iterator_wrapper> rx(x);
+  auto [in, out] = ranges::copy(std::move_iterator{ranges::begin(rx)},
+				std::move_sentinel{ranges::end(rx)},
 				ranges::begin(y));
-  VERIFY( ranges::equal(x, y) && in.base() == x+7 && out == y+7 );
+  VERIFY( ranges::equal(x, y) && std::move(in).base().ptr == x+7 && out == y+7 );
   VERIFY( ranges::equal(x, z) );
   for (const auto& v : x)
     VERIFY( v.moved == 1 );
diff --git a/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc
index 7ec1e78..ab4d283 100644
--- a/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc
@@ -25,8 +25,8 @@
 using __gnu_test::test_container;
 using __gnu_test::test_range;
 using __gnu_test::input_iterator_wrapper;
+using __gnu_test::output_iterator_wrapper;
 using __gnu_test::forward_iterator_wrapper;
-using __gnu_test::bidirectional_iterator_wrapper;
 
 namespace ranges = std::ranges;
 
@@ -76,8 +76,8 @@ test01()
       int z[3] = { 1, 2, 3 };
       test_container<int, forward_iterator_wrapper> cx(x);
       test_container<char, forward_iterator_wrapper> cy(y);
-      auto [in, out] = ranges::move(x, y);
-      VERIFY( ranges::equal(x, x+3, y, y+3) && in == x+3 && out == y+3 );
+      auto [in, out] = ranges::move(cx, cy.begin());
+      VERIFY( ranges::equal(x, x+3, y, y+3) && in.ptr == x+3 && out.ptr == y+3 );
       VERIFY( ranges::equal(x, z) );
     }
 
@@ -85,10 +85,10 @@ test01()
       char x[3] = { 1, 2, 3 };
       int y[4] = { 0 };
       int z[3] = { 1, 2, 3 };
-      test_range<char, forward_iterator_wrapper> cx(x);
-      test_range<int, forward_iterator_wrapper> cy(y);
-      auto [in, out] = ranges::move(x, y);
-      VERIFY( ranges::equal(x, x+3, y, y+3) && in == x+3 && out == y+3 );
+      test_range<char, input_iterator_wrapper> cx(x);
+      test_range<int, output_iterator_wrapper> cy(y);
+      auto [in, out] = ranges::move(cx, ranges::begin(cy));
+      VERIFY( ranges::equal(x, x+3, y, y+3) && in.ptr == x+3 && out.ptr == y+3 );
       VERIFY( ranges::equal(x, z) );
     }
 }
@@ -133,11 +133,12 @@ test04()
   X x[] = { {2}, {2}, {6}, {8}, {10} };
   X y[] = { {2}, {6}, {8}, {10}, {11}, {2} };
   X z[] = { {2}, {2}, {6}, {8}, {10} };
-  auto [in, out] = ranges::move(std::move_iterator{ranges::begin(x)},
-				std::move_iterator{ranges::end(x)},
+  test_range<X, input_iterator_wrapper> rx(x);
+  auto [in, out] = ranges::move(std::move_iterator{ranges::begin(rx)},
+				std::move_sentinel{ranges::end(rx)},
 				ranges::begin(y));
   VERIFY( ranges::equal(x, x+5, y, y+5) );
-  VERIFY( in.base() == x+5 );
+  VERIFY( std::move(in).base().ptr == x+5 );
   VERIFY( out == y+5 );
   VERIFY( y[5].i == 2 );
   VERIFY( ranges::equal(x, z) );



More information about the Libstdc++-cvs mailing list