Skip to content

Commit 5629d49

Browse files
committed
Reapply "[libc++][ranges]Refactor copy{,_backward} and move{,_backward}"
This reverts commit a6e1080. Fix the conditions when the `memmove` optimization can be applied and refactor them out into a reusable type trait, fix and significantly expand the tests. Differential Revision: https://reviews.llvm.org/D139235
1 parent 7c3ea2d commit 5629d49

39 files changed

+1505
-468
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set(files
99
__algorithm/copy.h
1010
__algorithm/copy_backward.h
1111
__algorithm/copy_if.h
12+
__algorithm/copy_move_common.h
1213
__algorithm/copy_n.h
1314
__algorithm/count.h
1415
__algorithm/count_if.h
@@ -587,6 +588,7 @@ set(files
587588
__type_traits/is_abstract.h
588589
__type_traits/is_aggregate.h
589590
__type_traits/is_allocator.h
591+
__type_traits/is_always_bitcastable.h
590592
__type_traits/is_arithmetic.h
591593
__type_traits/is_array.h
592594
__type_traits/is_assignable.h

libcxx/include/__algorithm/copy.h

Lines changed: 27 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -9,103 +9,55 @@
99
#ifndef _LIBCPP___ALGORITHM_COPY_H
1010
#define _LIBCPP___ALGORITHM_COPY_H
1111

12-
#include <__algorithm/unwrap_iter.h>
13-
#include <__algorithm/unwrap_range.h>
12+
#include <__algorithm/copy_move_common.h>
13+
#include <__algorithm/iterator_operations.h>
1414
#include <__config>
15-
#include <__iterator/iterator_traits.h>
16-
#include <__iterator/reverse_iterator.h>
17-
#include <__type_traits/enable_if.h>
18-
#include <__type_traits/is_copy_constructible.h>
19-
#include <__type_traits/is_same.h>
20-
#include <__type_traits/is_trivially_copy_assignable.h>
21-
#include <__type_traits/is_trivially_copyable.h>
22-
#include <__type_traits/remove_const.h>
2315
#include <__utility/move.h>
2416
#include <__utility/pair.h>
25-
#include <cstring>
2617

2718
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2819
# pragma GCC system_header
2920
#endif
3021

3122
_LIBCPP_BEGIN_NAMESPACE_STD
3223

33-
// copy
24+
struct __copy_loop {
25+
template <class _InIter, class _Sent, class _OutIter>
26+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
27+
operator()(_InIter __first, _Sent __last, _OutIter __result) const {
28+
while (__first != __last) {
29+
*__result = *__first;
30+
++__first;
31+
++__result;
32+
}
3433

35-
template <class _InIter, class _Sent, class _OutIter>
36-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
37-
pair<_InIter, _OutIter> __copy_impl(_InIter __first, _Sent __last, _OutIter __result) {
38-
while (__first != __last) {
39-
*__result = *__first;
40-
++__first;
41-
++__result;
34+
return std::make_pair(std::move(__first), std::move(__result));
4235
}
43-
return pair<_InIter, _OutIter>(std::move(__first), std::move(__result));
44-
}
36+
};
4537

46-
template <class _InValueT,
47-
class _OutValueT,
48-
class = __enable_if_t<is_same<__remove_const_t<_InValueT>, _OutValueT>::value
49-
&& is_trivially_copy_assignable<_OutValueT>::value> >
50-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
51-
pair<_InValueT*, _OutValueT*> __copy_impl(_InValueT* __first, _InValueT* __last, _OutValueT* __result) {
52-
if (__libcpp_is_constant_evaluated()
53-
// TODO: Remove this once GCC supports __builtin_memmove during constant evaluation
54-
#ifndef _LIBCPP_COMPILER_GCC
55-
&& !is_trivially_copyable<_InValueT>::value
56-
#endif
57-
)
58-
return std::__copy_impl<_InValueT*, _InValueT*, _OutValueT*>(__first, __last, __result);
59-
const size_t __n = static_cast<size_t>(__last - __first);
60-
if (__n > 0)
61-
::__builtin_memmove(__result, __first, __n * sizeof(_OutValueT));
62-
return std::make_pair(__first + __n, __result + __n);
63-
}
38+
struct __copy_trivial {
39+
// At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer.
40+
template <class _In, class _Out,
41+
__enable_if_t<__can_lower_copy_assignment_to_memmove<_In, _Out>::value, int> = 0>
42+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
43+
operator()(_In* __first, _In* __last, _Out* __result) const {
44+
return std::__copy_trivial_impl(__first, __last, __result);
45+
}
46+
};
6447

65-
template <class _InIter, class _OutIter,
66-
__enable_if_t<is_same<__remove_const_t<__iter_value_type<_InIter> >, __iter_value_type<_OutIter> >::value
67-
&& __is_cpp17_contiguous_iterator<typename _InIter::iterator_type>::value
68-
&& __is_cpp17_contiguous_iterator<typename _OutIter::iterator_type>::value
69-
&& is_trivially_copy_assignable<__iter_value_type<_OutIter> >::value
70-
&& __is_reverse_iterator<_InIter>::value
71-
&& __is_reverse_iterator<_OutIter>::value, int> = 0>
72-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
48+
template <class _AlgPolicy, class _InIter, class _Sent, class _OutIter>
7349
pair<_InIter, _OutIter>
74-
__copy_impl(_InIter __first, _InIter __last, _OutIter __result) {
75-
auto __first_base = std::__unwrap_iter(__first.base());
76-
auto __last_base = std::__unwrap_iter(__last.base());
77-
auto __result_base = std::__unwrap_iter(__result.base());
78-
auto __result_first = __result_base - (__first_base - __last_base);
79-
std::__copy_impl(__last_base, __first_base, __result_first);
80-
return std::make_pair(__last, _OutIter(std::__rewrap_iter(__result.base(), __result_first)));
81-
}
82-
83-
template <class _InIter, class _Sent, class _OutIter,
84-
__enable_if_t<!(is_copy_constructible<_InIter>::value
85-
&& is_copy_constructible<_Sent>::value
86-
&& is_copy_constructible<_OutIter>::value), int> = 0 >
87-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
88-
pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) {
89-
return std::__copy_impl(std::move(__first), std::move(__last), std::move(__result));
90-
}
91-
92-
template <class _InIter, class _Sent, class _OutIter,
93-
__enable_if_t<is_copy_constructible<_InIter>::value
94-
&& is_copy_constructible<_Sent>::value
95-
&& is_copy_constructible<_OutIter>::value, int> = 0>
9650
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
97-
pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) {
98-
auto __range = std::__unwrap_range(__first, __last);
99-
auto __ret = std::__copy_impl(std::move(__range.first), std::move(__range.second), std::__unwrap_iter(__result));
100-
return std::make_pair(
101-
std::__rewrap_range<_Sent>(__first, __ret.first), std::__rewrap_iter(__result, __ret.second));
51+
__copy(_InIter __first, _Sent __last, _OutIter __result) {
52+
return std::__dispatch_copy_or_move<_AlgPolicy, __copy_loop, __copy_trivial>(
53+
std::move(__first), std::move(__last), std::move(__result));
10254
}
10355

10456
template <class _InputIterator, class _OutputIterator>
10557
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
10658
_OutputIterator
10759
copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
108-
return std::__copy(__first, __last, __result).second;
60+
return std::__copy<_ClassicAlgPolicy>(__first, __last, __result).second;
10961
}
11062

11163
_LIBCPP_END_NAMESPACE_STD

libcxx/include/__algorithm/copy_backward.h

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,52 +9,64 @@
99
#ifndef _LIBCPP___ALGORITHM_COPY_BACKWARD_H
1010
#define _LIBCPP___ALGORITHM_COPY_BACKWARD_H
1111

12-
#include <__algorithm/copy.h>
12+
#include <__algorithm/copy_move_common.h>
1313
#include <__algorithm/iterator_operations.h>
14-
#include <__algorithm/ranges_copy.h>
15-
#include <__algorithm/unwrap_iter.h>
16-
#include <__concepts/same_as.h>
1714
#include <__config>
18-
#include <__iterator/iterator_traits.h>
19-
#include <__iterator/reverse_iterator.h>
20-
#include <__ranges/subrange.h>
15+
#include <__type_traits/is_copy_constructible.h>
2116
#include <__utility/move.h>
2217
#include <__utility/pair.h>
23-
#include <cstring>
24-
#include <type_traits>
2518

2619
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2720
# pragma GCC system_header
2821
#endif
2922

3023
_LIBCPP_BEGIN_NAMESPACE_STD
3124

32-
template <class _AlgPolicy, class _InputIterator, class _OutputIterator,
33-
__enable_if_t<is_same<_AlgPolicy, _ClassicAlgPolicy>::value, int> = 0>
34-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InputIterator, _OutputIterator>
35-
__copy_backward(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
36-
auto __ret = std::__copy(
37-
__unconstrained_reverse_iterator<_InputIterator>(__last),
38-
__unconstrained_reverse_iterator<_InputIterator>(__first),
39-
__unconstrained_reverse_iterator<_OutputIterator>(__result));
40-
return pair<_InputIterator, _OutputIterator>(__ret.first.base(), __ret.second.base());
41-
}
25+
template <class _AlgPolicy>
26+
struct __copy_backward_loop {
27+
template <class _InIter, class _Sent, class _OutIter>
28+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
29+
operator()(_InIter __first, _Sent __last, _OutIter __result) const {
30+
auto __last_iter = _IterOps<_AlgPolicy>::next(__first, __last);
31+
auto __original_last_iter = __last_iter;
32+
33+
while (__first != __last_iter) {
34+
*--__result = *--__last_iter;
35+
}
36+
37+
return std::make_pair(std::move(__original_last_iter), std::move(__result));
38+
}
39+
};
4240

43-
#if _LIBCPP_STD_VER > 17
44-
template <class _AlgPolicy, class _Iter1, class _Sent1, class _Iter2,
45-
__enable_if_t<is_same<_AlgPolicy, _RangeAlgPolicy>::value, int> = 0>
46-
_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter1, _Iter2> __copy_backward(_Iter1 __first, _Sent1 __last, _Iter2 __result) {
47-
auto __last_iter = _IterOps<_AlgPolicy>::next(__first, std::move(__last));
48-
auto __reverse_range = std::__reverse_range(std::ranges::subrange(std::move(__first), __last_iter));
49-
auto __ret = ranges::copy(std::move(__reverse_range), std::make_reverse_iterator(__result));
50-
return std::make_pair(__last_iter, __ret.out.base());
41+
struct __copy_backward_trivial {
42+
// At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer.
43+
template <class _In, class _Out,
44+
__enable_if_t<__can_lower_copy_assignment_to_memmove<_In, _Out>::value, int> = 0>
45+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
46+
operator()(_In* __first, _In* __last, _Out* __result) const {
47+
return std::__copy_backward_trivial_impl(__first, __last, __result);
48+
}
49+
};
50+
51+
template <class _AlgPolicy, class _BidirectionalIterator1, class _Sentinel, class _BidirectionalIterator2>
52+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
53+
pair<_BidirectionalIterator1, _BidirectionalIterator2>
54+
__copy_backward(_BidirectionalIterator1 __first, _Sentinel __last, _BidirectionalIterator2 __result) {
55+
return std::__dispatch_copy_or_move<_AlgPolicy, __copy_backward_loop<_AlgPolicy>, __copy_backward_trivial>(
56+
std::move(__first), std::move(__last), std::move(__result));
5157
}
52-
#endif // _LIBCPP_STD_VER > 17
5358

5459
template <class _BidirectionalIterator1, class _BidirectionalIterator2>
55-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIterator2
56-
copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) {
57-
return std::__copy_backward<_ClassicAlgPolicy>(__first, __last, __result).second;
60+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
61+
_BidirectionalIterator2
62+
copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last,
63+
_BidirectionalIterator2 __result)
64+
{
65+
static_assert(std::is_copy_constructible<_BidirectionalIterator1>::value &&
66+
std::is_copy_constructible<_BidirectionalIterator1>::value, "Iterators must be copy constructible.");
67+
68+
return std::__copy_backward<_ClassicAlgPolicy>(
69+
std::move(__first), std::move(__last), std::move(__result)).second;
5870
}
5971

6072
_LIBCPP_END_NAMESPACE_STD

0 commit comments

Comments
 (0)