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.
This commit is contained in:
parent
26af9cd8af
commit
144dfc68d0
@ -1,5 +1,25 @@
|
||||
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
|
||||
protected instead of private.
|
||||
(test_sized_range_sized_sent): New.
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user