Skip to content

Commit a5f64d0

Browse files
committed
[libc++] Merge the implementations of ranges::copy_n and std::copy_n
1 parent bb78728 commit a5f64d0

File tree

4 files changed

+75
-72
lines changed

4 files changed

+75
-72
lines changed

libcxx/include/__algorithm/copy_n.h

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,63 @@
1010
#define _LIBCPP___ALGORITHM_COPY_N_H
1111

1212
#include <__algorithm/copy.h>
13+
#include <__algorithm/iterator_operations.h>
1314
#include <__config>
1415
#include <__iterator/iterator_traits.h>
1516
#include <__type_traits/enable_if.h>
1617
#include <__utility/convert_to_integral.h>
18+
#include <__utility/move.h>
19+
#include <__utility/pair.h>
1720

1821
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1922
# pragma GCC system_header
2023
#endif
2124

25+
_LIBCPP_PUSH_MACROS
26+
#include <__undef_macros>
27+
2228
_LIBCPP_BEGIN_NAMESPACE_STD
2329

30+
template <class _AlgPolicy,
31+
class _InIter,
32+
class _OutIter,
33+
__enable_if_t<__has_random_access_iterator_category<_InIter>::value, int> = 0>
34+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InIter, _OutIter>
35+
__copy_n(_InIter __first, typename _IterOps<_AlgPolicy>::template __difference_type<_InIter> __n, _OutIter __result) {
36+
return std::__copy(__first, __first + __n, std::move(__result));
37+
}
38+
39+
template <class _AlgPolicy,
40+
class _InIter,
41+
class _OutIter,
42+
__enable_if_t<!__has_random_access_iterator_category<_InIter>::value, int> = 0>
43+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InIter, _OutIter>
44+
__copy_n(_InIter __first, typename _IterOps<_AlgPolicy>::template __difference_type<_InIter> __n, _OutIter __result) {
45+
while (__n != 0) {
46+
*__result = *__first;
47+
++__first;
48+
++__result;
49+
--__n;
50+
}
51+
return std::make_pair(std::move(__first), std::move(__result));
52+
}
53+
54+
// The InputIterator case is handled specially here because it's been written in a way to avoid incrementing __first
55+
// if not absolutely required. This was done to allow its use with istream_iterator and we want to avoid breaking
56+
// people, at least currently.
57+
// See https://github.com/llvm/llvm-project/commit/99847d2bf132854fffa019bab19818768102ccad
2458
template <class _InputIterator,
2559
class _Size,
2660
class _OutputIterator,
27-
__enable_if_t<__has_input_iterator_category<_InputIterator>::value &&
28-
!__has_random_access_iterator_category<_InputIterator>::value,
29-
int> = 0>
30-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
31-
copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) {
32-
typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize;
33-
_IntegralSize __n = __orig_n;
34-
if (__n > 0) {
61+
__enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0>
62+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
63+
copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) {
64+
using _IntegralSize = decltype(std::__convert_to_integral(__n));
65+
_IntegralSize __converted = __n;
66+
if (__converted > 0) {
3567
*__result = *__first;
3668
++__result;
37-
for (--__n; __n > 0; --__n) {
69+
for (--__converted; __converted > 0; --__converted) {
3870
++__first;
3971
*__result = *__first;
4072
++__result;
@@ -46,15 +78,17 @@ copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) {
4678
template <class _InputIterator,
4779
class _Size,
4880
class _OutputIterator,
49-
__enable_if_t<__has_random_access_iterator_category<_InputIterator>::value, int> = 0>
50-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
51-
copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) {
52-
typedef typename iterator_traits<_InputIterator>::difference_type difference_type;
53-
typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize;
54-
_IntegralSize __n = __orig_n;
55-
return std::copy(__first, __first + difference_type(__n), __result);
81+
__enable_if_t<!__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0>
82+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
83+
copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) {
84+
using _IntegralSize = decltype(std::__convert_to_integral(__n));
85+
_IntegralSize __converted = __n;
86+
return std::__copy_n<_ClassicAlgPolicy>(__first, __iterator_difference_type<_InputIterator>(__converted), __result)
87+
.second;
5688
}
5789

5890
_LIBCPP_END_NAMESPACE_STD
5991

92+
_LIBCPP_POP_MACROS
93+
6094
#endif // _LIBCPP___ALGORITHM_COPY_N_H

libcxx/include/__algorithm/iterator_operations.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ struct _IterOps<_ClassicAlgPolicy> {
219219
template <class _AlgPolicy, class _Iter>
220220
using __policy_iter_diff_t _LIBCPP_NODEBUG = typename _IterOps<_AlgPolicy>::template __difference_type<_Iter>;
221221

222+
template <class _AlgPolicy, class _Iter>
223+
using __policy_value_type _LIBCPP_NODEBUG = typename _IterOps<_AlgPolicy>::template __value_type<_Iter>;
224+
222225
_LIBCPP_END_NAMESPACE_STD
223226

224227
_LIBCPP_POP_MACROS

libcxx/include/__algorithm/ranges_copy_n.h

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,12 @@
99
#ifndef _LIBCPP___ALGORITHM_RANGES_COPY_N_H
1010
#define _LIBCPP___ALGORITHM_RANGES_COPY_N_H
1111

12-
#include <__algorithm/copy.h>
12+
#include <__algorithm/copy_n.h>
1313
#include <__algorithm/in_out_result.h>
1414
#include <__algorithm/iterator_operations.h>
15-
#include <__algorithm/ranges_copy.h>
1615
#include <__config>
17-
#include <__functional/identity.h>
1816
#include <__iterator/concepts.h>
1917
#include <__iterator/incrementable_traits.h>
20-
#include <__iterator/unreachable_sentinel.h>
21-
#include <__iterator/wrap_iter.h>
2218
#include <__utility/move.h>
2319

2420
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -37,32 +33,13 @@ namespace ranges {
3733
template <class _Ip, class _Op>
3834
using copy_n_result = in_out_result<_Ip, _Op>;
3935

40-
// TODO: Merge this with copy_n
4136
struct __copy_n {
42-
template <class _InIter, class _DiffType, class _OutIter>
43-
_LIBCPP_HIDE_FROM_ABI constexpr static copy_n_result<_InIter, _OutIter>
44-
__go(_InIter __first, _DiffType __n, _OutIter __result) {
45-
while (__n != 0) {
46-
*__result = *__first;
47-
++__first;
48-
++__result;
49-
--__n;
50-
}
51-
return {std::move(__first), std::move(__result)};
52-
}
53-
54-
template <random_access_iterator _InIter, class _DiffType, random_access_iterator _OutIter>
55-
_LIBCPP_HIDE_FROM_ABI constexpr static copy_n_result<_InIter, _OutIter>
56-
__go(_InIter __first, _DiffType __n, _OutIter __result) {
57-
auto __ret = std::__copy(__first, __first + __n, __result);
58-
return {__ret.first, __ret.second};
59-
}
60-
6137
template <input_iterator _Ip, weakly_incrementable _Op>
6238
requires indirectly_copyable<_Ip, _Op>
6339
_LIBCPP_HIDE_FROM_ABI constexpr copy_n_result<_Ip, _Op>
6440
operator()(_Ip __first, iter_difference_t<_Ip> __n, _Op __result) const {
65-
return __go(std::move(__first), __n, std::move(__result));
41+
auto __res = std::__copy_n<_RangeAlgPolicy>(std::move(__first), __n, std::move(__result));
42+
return {std::move(__res.first), std::move(__res.second)};
6643
}
6744
};
6845

libcxx/include/__vector/vector.h

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
#include <__algorithm/copy.h>
1313
#include <__algorithm/copy_n.h>
1414
#include <__algorithm/fill_n.h>
15+
#include <__algorithm/iterator_operations.h>
1516
#include <__algorithm/max.h>
1617
#include <__algorithm/min.h>
1718
#include <__algorithm/move.h>
1819
#include <__algorithm/move_backward.h>
19-
#include <__algorithm/ranges_copy_n.h>
2020
#include <__algorithm/rotate.h>
2121
#include <__assert>
2222
#include <__config>
@@ -314,15 +314,15 @@ class vector {
314314
is_constructible<value_type, typename iterator_traits<_ForwardIterator>::reference>::value,
315315
int> = 0>
316316
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(_ForwardIterator __first, _ForwardIterator __last) {
317-
__assign_with_size(__first, __last, std::distance(__first, __last));
317+
__assign_with_size<_ClassicAlgPolicy>(__first, __last, std::distance(__first, __last));
318318
}
319319

320320
#if _LIBCPP_STD_VER >= 23
321321
template <_ContainerCompatibleRange<_Tp> _Range>
322322
_LIBCPP_HIDE_FROM_ABI constexpr void assign_range(_Range&& __range) {
323323
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
324324
auto __n = static_cast<size_type>(ranges::distance(__range));
325-
__assign_with_size(ranges::begin(__range), ranges::end(__range), __n);
325+
__assign_with_size<_RangeAlgPolicy>(ranges::begin(__range), ranges::end(__range), __n);
326326

327327
} else {
328328
__assign_with_sentinel(ranges::begin(__range), ranges::end(__range));
@@ -518,15 +518,15 @@ class vector {
518518
int> = 0>
519519
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator
520520
insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last) {
521-
return __insert_with_size(__position, __first, __last, std::distance(__first, __last));
521+
return __insert_with_size<_ClassicAlgPolicy>(__position, __first, __last, std::distance(__first, __last));
522522
}
523523

524524
#if _LIBCPP_STD_VER >= 23
525525
template <_ContainerCompatibleRange<_Tp> _Range>
526526
_LIBCPP_HIDE_FROM_ABI constexpr iterator insert_range(const_iterator __position, _Range&& __range) {
527527
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
528528
auto __n = static_cast<size_type>(ranges::distance(__range));
529-
return __insert_with_size(__position, ranges::begin(__range), ranges::end(__range), __n);
529+
return __insert_with_size<_RangeAlgPolicy>(__position, ranges::begin(__range), ranges::end(__range), __n);
530530

531531
} else {
532532
return __insert_with_sentinel(__position, ranges::begin(__range), ranges::end(__range));
@@ -619,12 +619,13 @@ class vector {
619619
// The `_Iterator` in `*_with_size` functions can be input-only only if called from `*_range` (since C++23).
620620
// Otherwise, `_Iterator` is a forward iterator.
621621

622-
template <class _Iterator, class _Sentinel>
622+
template <class _AlgPolicy, class _Iterator, class _Sentinel>
623623
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
624624
__assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n);
625625

626-
template <class _Iterator,
627-
__enable_if_t<!is_same<decltype(*std::declval<_Iterator&>())&&, value_type&&>::value, int> = 0>
626+
template <class _AlgPolicy,
627+
class _Iterator,
628+
__enable_if_t<!is_same<__policy_value_type<_AlgPolicy, _Iterator>, value_type>::value, int> = 0>
628629
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
629630
__insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) {
630631
for (pointer __end_position = __position + __n; __position != __end_position; ++__position, (void)++__first) {
@@ -633,25 +634,19 @@ class vector {
633634
}
634635
}
635636

636-
template <class _Iterator,
637-
__enable_if_t<is_same<decltype(*std::declval<_Iterator&>())&&, value_type&&>::value, int> = 0>
637+
template <class _AlgPolicy,
638+
class _Iterator,
639+
__enable_if_t<is_same<__policy_value_type<_AlgPolicy, _Iterator>, value_type>::value, int> = 0>
638640
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
639641
__insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) {
640-
#if _LIBCPP_STD_VER >= 23
641-
if constexpr (!forward_iterator<_Iterator>) { // Handles input-only sized ranges for insert_range
642-
ranges::copy_n(std::move(__first), __n, __position);
643-
} else
644-
#endif
645-
{
646-
std::copy_n(__first, __n, __position);
647-
}
642+
std::__copy_n<_AlgPolicy>(std::move(__first), __n, __position);
648643
}
649644

650645
template <class _InputIterator, class _Sentinel>
651646
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator
652647
__insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last);
653648

654-
template <class _Iterator, class _Sentinel>
649+
template <class _AlgPolicy, class _Iterator, class _Sentinel>
655650
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator
656651
__insert_with_size(const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n);
657652

@@ -1039,20 +1034,14 @@ vector<_Tp, _Allocator>::__assign_with_sentinel(_Iterator __first, _Sentinel __l
10391034
}
10401035

10411036
template <class _Tp, class _Allocator>
1042-
template <class _Iterator, class _Sentinel>
1037+
template <class _AlgPolicy, class _Iterator, class _Sentinel>
10431038
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
10441039
vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n) {
10451040
size_type __new_size = static_cast<size_type>(__n);
10461041
if (__new_size <= capacity()) {
10471042
if (__new_size > size()) {
1048-
#if _LIBCPP_STD_VER >= 23
1049-
auto __mid = ranges::copy_n(std::move(__first), size(), this->__begin_).in;
1043+
auto __mid = std::__copy_n<_AlgPolicy>(std::move(__first), size(), this->__begin_).first;
10501044
__construct_at_end(std::move(__mid), std::move(__last), __new_size - size());
1051-
#else
1052-
_Iterator __mid = std::next(__first, size());
1053-
std::copy(__first, __mid, this->__begin_);
1054-
__construct_at_end(__mid, __last, __new_size - size());
1055-
#endif
10561045
} else {
10571046
pointer __m = std::__copy(std::move(__first), __last, this->__begin_).second;
10581047
this->__destruct_at_end(__m);
@@ -1326,7 +1315,7 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
13261315
}
13271316

13281317
template <class _Tp, class _Allocator>
1329-
template <class _Iterator, class _Sentinel>
1318+
template <class _AlgPolicy, class _Iterator, class _Sentinel>
13301319
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator
13311320
vector<_Tp, _Allocator>::__insert_with_size(
13321321
const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n) {
@@ -1347,12 +1336,12 @@ vector<_Tp, _Allocator>::__insert_with_size(
13471336
__construct_at_end(__m, __last, __n - __dx);
13481337
if (__dx > 0) {
13491338
__move_range(__p, __old_last, __p + __n);
1350-
__insert_assign_n_unchecked(__first, __dx, __p);
1339+
__insert_assign_n_unchecked<_AlgPolicy>(__first, __dx, __p);
13511340
}
13521341
}
13531342
} else {
13541343
__move_range(__p, __old_last, __p + __n);
1355-
__insert_assign_n_unchecked(std::move(__first), __n, __p);
1344+
__insert_assign_n_unchecked<_AlgPolicy>(std::move(__first), __n, __p);
13561345
}
13571346
} else {
13581347
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);

0 commit comments

Comments
 (0)