Commit 144dfc68 by Patrick Palka

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

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
that has 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.
parent 26af9cd8
2020-03-04 Patrick Palka <ppalka@redhat.com> 2020-03-04 Patrick Palka <ppalka@redhat.com>
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.
* testsuite/util/testsuite_iterators.h (test_range::get_iterator): Make * testsuite/util/testsuite_iterators.h (test_range::get_iterator): Make
protected instead of private. protected instead of private.
(test_sized_range_sized_sent): New. (test_sized_range_sized_sent): New.
......
...@@ -272,9 +272,10 @@ namespace ranges ...@@ -272,9 +272,10 @@ namespace ranges
&& is_nothrow_assignable_v<_OutType&, && is_nothrow_assignable_v<_OutType&,
iter_reference_t<_Iter>>) iter_reference_t<_Iter>>)
{ {
auto __d1 = ranges::distance(__ifirst, __ilast); auto __d1 = __ilast - __ifirst;
auto __d2 = ranges::distance(__ofirst, __olast); auto __d2 = __olast - __ofirst;
return ranges::copy_n(__ifirst, std::min(__d1, __d2), __ofirst); return ranges::copy_n(std::move(__ifirst), std::min(__d1, __d2),
__ofirst);
} }
else else
{ {
...@@ -283,7 +284,7 @@ namespace ranges ...@@ -283,7 +284,7 @@ namespace ranges
++__ofirst, (void)++__ifirst) ++__ofirst, (void)++__ifirst)
::new (__detail::__voidify(*__ofirst)) _OutType(*__ifirst); ::new (__detail::__voidify(*__ofirst)) _OutType(*__ifirst);
__guard.release(); __guard.release();
return {__ifirst, __ofirst}; return {std::move(__ifirst), __ofirst};
} }
} }
...@@ -319,8 +320,9 @@ namespace ranges ...@@ -319,8 +320,9 @@ namespace ranges
&& is_nothrow_assignable_v<_OutType&, && is_nothrow_assignable_v<_OutType&,
iter_reference_t<_Iter>>) iter_reference_t<_Iter>>)
{ {
auto __d = ranges::distance(__ofirst, __olast); auto __d = __olast - __ofirst;
return ranges::copy_n(__ifirst, std::min(__n, __d), __ofirst); return ranges::copy_n(std::move(__ifirst), std::min(__n, __d),
__ofirst);
} }
else else
{ {
...@@ -329,7 +331,7 @@ namespace ranges ...@@ -329,7 +331,7 @@ namespace ranges
++__ofirst, (void)++__ifirst, (void)--__n) ++__ofirst, (void)++__ifirst, (void)--__n)
::new (__detail::__voidify(*__ofirst)) _OutType(*__ifirst); ::new (__detail::__voidify(*__ofirst)) _OutType(*__ifirst);
__guard.release(); __guard.release();
return {__ifirst, __ofirst}; return {std::move(__ifirst), __ofirst};
} }
} }
}; };
...@@ -357,10 +359,10 @@ namespace ranges ...@@ -357,10 +359,10 @@ namespace ranges
&& is_nothrow_assignable_v<_OutType&, && is_nothrow_assignable_v<_OutType&,
iter_rvalue_reference_t<_Iter>>) iter_rvalue_reference_t<_Iter>>)
{ {
auto __d1 = ranges::distance(__ifirst, __ilast); auto __d1 = __ilast - __ifirst;
auto __d2 = ranges::distance(__ofirst, __olast); auto __d2 = __olast - __ofirst;
auto [__in, __out] 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); std::min(__d1, __d2), __ofirst);
return {std::move(__in).base(), __out}; return {std::move(__in).base(), __out};
} }
...@@ -372,7 +374,7 @@ namespace ranges ...@@ -372,7 +374,7 @@ namespace ranges
::new (__detail::__voidify(*__ofirst)) ::new (__detail::__voidify(*__ofirst))
_OutType(ranges::iter_move(__ifirst)); _OutType(ranges::iter_move(__ifirst));
__guard.release(); __guard.release();
return {__ifirst, __ofirst}; return {std::move(__ifirst), __ofirst};
} }
} }
...@@ -409,9 +411,9 @@ namespace ranges ...@@ -409,9 +411,9 @@ namespace ranges
&& is_nothrow_assignable_v<_OutType&, && is_nothrow_assignable_v<_OutType&,
iter_rvalue_reference_t<_Iter>>) iter_rvalue_reference_t<_Iter>>)
{ {
auto __d = ranges::distance(__ofirst, __olast); auto __d = __olast - __ofirst;
auto [__in, __out] 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); std::min(__n, __d), __ofirst);
return {std::move(__in).base(), __out}; return {std::move(__in).base(), __out};
} }
...@@ -423,7 +425,7 @@ namespace ranges ...@@ -423,7 +425,7 @@ namespace ranges
::new (__detail::__voidify(*__ofirst)) ::new (__detail::__voidify(*__ofirst))
_OutType(ranges::iter_move(__ifirst)); _OutType(ranges::iter_move(__ifirst));
__guard.release(); __guard.release();
return {__ifirst, __ofirst}; return {std::move(__ifirst), __ofirst};
} }
} }
}; };
...@@ -524,7 +526,7 @@ namespace ranges ...@@ -524,7 +526,7 @@ namespace ranges
__destroy_fn::operator()(_Iter __first, _Sent __last) const noexcept __destroy_fn::operator()(_Iter __first, _Sent __last) const noexcept
{ {
if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>) if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>)
return ranges::next(__first, __last); return ranges::next(std::move(__first), __last);
else else
{ {
for (; __first != __last; ++__first) for (; __first != __last; ++__first)
...@@ -549,7 +551,7 @@ namespace ranges ...@@ -549,7 +551,7 @@ namespace ranges
operator()(_Iter __first, iter_difference_t<_Iter> __n) const noexcept operator()(_Iter __first, iter_difference_t<_Iter> __n) const noexcept
{ {
if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>) if constexpr (is_trivially_destructible_v<iter_value_t<_Iter>>)
return ranges::next(__first, __n); return ranges::next(std::move(__first), __n);
else else
{ {
for (; __n > 0; ++__first, (void)--__n) for (; __n > 0; ++__first, (void)--__n)
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
#include <testsuite_iterators.h> #include <testsuite_iterators.h>
using __gnu_test::test_range;
using __gnu_test::input_iterator_wrapper_nocopy;
namespace ranges = std::ranges; namespace ranges = std::ranges;
struct X struct X
...@@ -69,6 +72,18 @@ test01() ...@@ -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 int
main() main()
{ {
......
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
using __gnu_test::test_input_range; using __gnu_test::test_input_range;
using __gnu_test::test_forward_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; namespace ranges = std::ranges;
...@@ -150,6 +153,28 @@ test02() ...@@ -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 int
main() main()
{ {
......
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
using __gnu_test::test_input_range; using __gnu_test::test_input_range;
using __gnu_test::test_forward_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; namespace ranges = std::ranges;
...@@ -160,6 +163,28 @@ test02() ...@@ -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 int
main() main()
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment