diff mbox series

[4/4] libstdc++: Move-only input iterator support in <memory> algorithms (LWG 3355)

Message ID 20200303163043.2182013-4-ppalka@redhat.com
State New
Headers show
Series [1/4] libstdc++: Fix use of is_nothrow_assignable_v in <bits/ranges_uninitialized.h> | expand

Commit Message

Patrick Palka March 3, 2020, 4:30 p.m. UTC
This adds support for move-only input iterators in the ranges::unitialized_*
algorithms defined in <memory>, as per LWG 3355.  The only changes needed are to
add calls to std::move in the appropriate places and to use operator-() instead
of ranges::distance() because the latter cannot be used with a move-only
iterator with a sized sentinel as is the case here.  (This issue with
ranges::distance is LWG 3392.)

libstdc++-v3/ChangeLog:

	LWG 3355 The memory algorithms should support move-only input iterators
	introduced by P1207
	* include/bits/ranges_uninitialized.h
	(__uninitialized_copy_fn::operator()): Use std::move to avoid attempting
	to copy __ifirst, which could be a move-only input iterator.  Use
	operator- instead of ranges::distance to compute distance from a sized
	sentinel.
	(__uninitialized_copy_n_fn::operator()): Likewise.
	(__uninitialized_move_fn::operator()): Likewise.
	(__uninitialized_move_n_fn::operator()): Likewise.
	(__uninitialized_destroy_fn::operator()): Use std::move to avoid
	attempting to copy __first.
	(__uninitialized_destroy_n_fn::operator()): Likewise.
	* testsuite/20_util/specialized_algorithms/destroy/constrained.cc:
	Augment test.
	* .../specialized_algorithms/uninitialized_copy/constrained.cc:
	Likewise.
	* .../specialized_algorithms/uninitialized_move/constrained.cc:
	Likewise.
---
 .../include/bits/ranges_uninitialized.h       | 34 ++++++++++---------
 .../destroy/constrained.cc                    | 15 ++++++++
 .../uninitialized_copy/constrained.cc         | 25 ++++++++++++++
 .../uninitialized_move/constrained.cc         | 25 ++++++++++++++
 4 files changed, 83 insertions(+), 16 deletions(-)

Comments

Jonathan Wakely March 3, 2020, 9:38 p.m. UTC | #1
On 03/03/20 11:30 -0500, Patrick Palka wrote:
>This adds support for move-only input iterators in the ranges::unitialized_*
>algorithms defined in <memory>, as per LWG 3355.  The only changes needed are to
>add calls to std::move in the appropriate places and to use operator-() instead
>of ranges::distance() because the latter cannot be used with a move-only
>iterator with a sized sentinel as is the case here.  (This issue with
>ranges::distance is LWG 3392.)
>
>libstdc++-v3/ChangeLog:
>
>	LWG 3355 The memory algorithms should support move-only input iterators
>	introduced by P1207
>	* include/bits/ranges_uninitialized.h
>	(__uninitialized_copy_fn::operator()): Use std::move to avoid attempting
>	to copy __ifirst, which could be a move-only input iterator.  Use
>	operator- instead of ranges::distance to compute distance from a sized
>	sentinel.
>	(__uninitialized_copy_n_fn::operator()): Likewise.
>	(__uninitialized_move_fn::operator()): Likewise.
>	(__uninitialized_move_n_fn::operator()): Likewise.
>	(__uninitialized_destroy_fn::operator()): Use std::move to avoid
>	attempting to copy __first.
>	(__uninitialized_destroy_n_fn::operator()): Likewise.
>	* testsuite/20_util/specialized_algorithms/destroy/constrained.cc:
>	Augment test.
>	* .../specialized_algorithms/uninitialized_copy/constrained.cc:
>	Likewise.
>	* .../specialized_algorithms/uninitialized_move/constrained.cc:
>	Likewise.

OK, thanks.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/bits/ranges_uninitialized.h b/libstdc++-v3/include/bits/ranges_uninitialized.h
index f97a07a9b4a..d758078fc03 100644
--- a/libstdc++-v3/include/bits/ranges_uninitialized.h
+++ b/libstdc++-v3/include/bits/ranges_uninitialized.h
@@ -272,9 +272,10 @@  namespace ranges
 		      && is_nothrow_assignable_v<_OutType&,
 						 iter_reference_t<_Iter>>)
 	  {
-	    auto __d1 = ranges::distance(__ifirst, __ilast);
-	    auto __d2 = ranges::distance(__ofirst, __olast);
-	    return ranges::copy_n(__ifirst, std::min(__d1, __d2), __ofirst);
+	    auto __d1 = __ilast - __ifirst;
+	    auto __d2 = __olast - __ofirst;
+	    return ranges::copy_n(std::move(__ifirst), std::min(__d1, __d2),
+				  __ofirst);
 	  }
 	else
 	  {
@@ -283,7 +284,7 @@  namespace ranges
 		 ++__ofirst, (void)++__ifirst)
 	      ::new (__detail::__voidify(*__ofirst)) _OutType(*__ifirst);
 	    __guard.release();
-	    return {__ifirst, __ofirst};
+	    return {std::move(__ifirst), __ofirst};
 	  }
       }
 
@@ -319,8 +320,9 @@  namespace ranges
 		      && is_nothrow_assignable_v<_OutType&,
 						 iter_reference_t<_Iter>>)
 	  {
-	    auto __d = ranges::distance(__ofirst, __olast);
-	    return ranges::copy_n(__ifirst, std::min(__n, __d), __ofirst);
+	    auto __d = __olast - __ofirst;
+	    return ranges::copy_n(std::move(__ifirst), std::min(__n, __d),
+				  __ofirst);
 	  }
 	else
 	  {
@@ -329,7 +331,7 @@  namespace ranges
 		 ++__ofirst, (void)++__ifirst, (void)--__n)
 	      ::new (__detail::__voidify(*__ofirst)) _OutType(*__ifirst);
 	    __guard.release();
-	    return {__ifirst, __ofirst};
+	    return {std::move(__ifirst), __ofirst};
 	  }
       }
   };
@@ -357,10 +359,10 @@  namespace ranges
 		      && is_nothrow_assignable_v<_OutType&,
 						 iter_rvalue_reference_t<_Iter>>)
 	  {
-	    auto __d1 = ranges::distance(__ifirst, __ilast);
-	    auto __d2 = ranges::distance(__ofirst, __olast);
+	    auto __d1 = __ilast - __ifirst;
+	    auto __d2 = __olast - __ofirst;
 	    auto [__in, __out]
-	      = ranges::copy_n(std::make_move_iterator(__ifirst),
+	      = ranges::copy_n(std::make_move_iterator(std::move(__ifirst)),
 			       std::min(__d1, __d2), __ofirst);
 	    return {std::move(__in).base(), __out};
 	  }
@@ -372,7 +374,7 @@  namespace ranges
 	      ::new (__detail::__voidify(*__ofirst))
 		    _OutType(ranges::iter_move(__ifirst));
 	    __guard.release();
-	    return {__ifirst, __ofirst};
+	    return {std::move(__ifirst), __ofirst};
 	  }
       }
 
@@ -409,9 +411,9 @@  namespace ranges
 		      && is_nothrow_assignable_v<_OutType&,
 						 iter_rvalue_reference_t<_Iter>>)
 	  {
-	    auto __d = ranges::distance(__ofirst, __olast);
+	    auto __d = __olast - __ofirst;
 	    auto [__in, __out]
-	      = ranges::copy_n(std::make_move_iterator(__ifirst),
+	      = ranges::copy_n(std::make_move_iterator(std::move(__ifirst)),
 			       std::min(__n, __d), __ofirst);
 	    return {std::move(__in).base(), __out};
 	  }
@@ -423,7 +425,7 @@  namespace ranges
 	      ::new (__detail::__voidify(*__ofirst))
 		    _OutType(ranges::iter_move(__ifirst));
 	    __guard.release();
-	    return {__ifirst, __ofirst};
+	    return {std::move(__ifirst), __ofirst};
 	  }
       }
   };
@@ -524,7 +526,7 @@  namespace ranges
     __destroy_fn::operator()(_Iter __first, _Sent __last) const noexcept
     {
       if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>)
-	return ranges::next(__first, __last);
+	return ranges::next(std::move(__first), __last);
       else
 	{
 	  for (; __first != __last; ++__first)
@@ -549,7 +551,7 @@  namespace ranges
       operator()(_Iter __first, iter_difference_t<_Iter> __n) const noexcept
       {
 	if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>)
-	  return ranges::next(__first, __n);
+	  return ranges::next(std::move(__first), __n);
 	else
 	  {
 	    for (; __n > 0; ++__first, (void)--__n)
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/destroy/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/destroy/constrained.cc
index c04049de0b5..89085d381ed 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/destroy/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/destroy/constrained.cc
@@ -29,6 +29,9 @@ 
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
+using __gnu_test::test_range;
+using __gnu_test::input_iterator_wrapper_nocopy;
+
 namespace ranges = std::ranges;
 
 struct X
@@ -69,6 +72,18 @@  test01()
     }
 }
 
+void
+test02()
+{
+  // LWG 3355
+    {
+      int x[3] = {0};
+      test_range<int, input_iterator_wrapper_nocopy> rx(x);
+      ranges::destroy(rx);
+      ranges::destroy_n(rx.begin(), 3);
+    }
+}
+
 int
 main()
 {
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
index c1a50c45df9..ac5d74558d2 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
@@ -31,6 +31,9 @@ 
 
 using __gnu_test::test_input_range;
 using __gnu_test::test_forward_range;
+using __gnu_test::test_range;
+using __gnu_test::test_sized_range_sized_sent;
+using __gnu_test::input_iterator_wrapper_nocopy;
 
 namespace ranges = std::ranges;
 
@@ -150,6 +153,28 @@  test02()
     }
 }
 
+void
+test03()
+{
+  // LWG 3355
+    {
+      int x[3] = {0};
+      int y[3];
+      test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy> rx(x);
+      ranges::uninitialized_copy(rx, y);
+      ranges::uninitialized_copy_n(rx.begin(), 3, y, y+3);
+    }
+
+    {
+      int x[3] = {0};
+      int y[3];
+      test_range<int, input_iterator_wrapper_nocopy> rx(x);
+      test_forward_range<int> ry(y);
+      ranges::uninitialized_copy(rx, y);
+      ranges::uninitialized_copy_n(rx.begin(), 3, ry.begin(), ry.end());
+    }
+}
+
 int
 main()
 {
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
index a7d6fd39b38..6b3544edc55 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
@@ -31,6 +31,9 @@ 
 
 using __gnu_test::test_input_range;
 using __gnu_test::test_forward_range;
+using __gnu_test::test_range;
+using __gnu_test::test_sized_range_sized_sent;
+using __gnu_test::input_iterator_wrapper_nocopy;
 
 namespace ranges = std::ranges;
 
@@ -160,6 +163,28 @@  test02()
     }
 }
 
+void
+test03()
+{
+  // LWG 3355
+    {
+      int x[3] = {0};
+      int y[3];
+      test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy> rx(x);
+      ranges::uninitialized_move(rx, y);
+      ranges::uninitialized_move_n(rx.begin(), 3, y, y+3);
+    }
+
+    {
+      int x[3] = {0};
+      int y[3];
+      test_range<int, input_iterator_wrapper_nocopy> rx(x);
+      test_forward_range<int> ry(y);
+      ranges::uninitialized_move(rx, y);
+      ranges::uninitialized_move_n(rx.begin(), 3, ry.begin(), ry.end());
+    }
+}
+
 int
 main()
 {