[libcxx-commits] [libcxx] [libc++] Merge the implementations of ranges::copy_n and std::copy_n and fix vector::insert to assign (PR #157444)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Nov 24 08:46:32 PST 2025
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/157444
>From a5f64d012dbbd3cbc77c3f9575681bac8df65e71 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 8 Sep 2025 15:05:23 +0200
Subject: [PATCH] [libc++] Merge the implementations of ranges::copy_n and
std::copy_n
---
libcxx/include/__algorithm/copy_n.h | 66 ++++++++++++++-----
.../include/__algorithm/iterator_operations.h | 3 +
libcxx/include/__algorithm/ranges_copy_n.h | 29 +-------
libcxx/include/__vector/vector.h | 49 ++++++--------
4 files changed, 75 insertions(+), 72 deletions(-)
diff --git a/libcxx/include/__algorithm/copy_n.h b/libcxx/include/__algorithm/copy_n.h
index f93f39203a7e3..56fb44811fc4a 100644
--- a/libcxx/include/__algorithm/copy_n.h
+++ b/libcxx/include/__algorithm/copy_n.h
@@ -10,31 +10,63 @@
#define _LIBCPP___ALGORITHM_COPY_N_H
#include <__algorithm/copy.h>
+#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__type_traits/enable_if.h>
#include <__utility/convert_to_integral.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
_LIBCPP_BEGIN_NAMESPACE_STD
+template <class _AlgPolicy,
+ class _InIter,
+ class _OutIter,
+ __enable_if_t<__has_random_access_iterator_category<_InIter>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InIter, _OutIter>
+__copy_n(_InIter __first, typename _IterOps<_AlgPolicy>::template __difference_type<_InIter> __n, _OutIter __result) {
+ return std::__copy(__first, __first + __n, std::move(__result));
+}
+
+template <class _AlgPolicy,
+ class _InIter,
+ class _OutIter,
+ __enable_if_t<!__has_random_access_iterator_category<_InIter>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InIter, _OutIter>
+__copy_n(_InIter __first, typename _IterOps<_AlgPolicy>::template __difference_type<_InIter> __n, _OutIter __result) {
+ while (__n != 0) {
+ *__result = *__first;
+ ++__first;
+ ++__result;
+ --__n;
+ }
+ return std::make_pair(std::move(__first), std::move(__result));
+}
+
+// The InputIterator case is handled specially here because it's been written in a way to avoid incrementing __first
+// if not absolutely required. This was done to allow its use with istream_iterator and we want to avoid breaking
+// people, at least currently.
+// See https://github.com/llvm/llvm-project/commit/99847d2bf132854fffa019bab19818768102ccad
template <class _InputIterator,
class _Size,
class _OutputIterator,
- __enable_if_t<__has_input_iterator_category<_InputIterator>::value &&
- !__has_random_access_iterator_category<_InputIterator>::value,
- int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
-copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) {
- typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize;
- _IntegralSize __n = __orig_n;
- if (__n > 0) {
+ __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
+copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) {
+ using _IntegralSize = decltype(std::__convert_to_integral(__n));
+ _IntegralSize __converted = __n;
+ if (__converted > 0) {
*__result = *__first;
++__result;
- for (--__n; __n > 0; --__n) {
+ for (--__converted; __converted > 0; --__converted) {
++__first;
*__result = *__first;
++__result;
@@ -46,15 +78,17 @@ copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) {
template <class _InputIterator,
class _Size,
class _OutputIterator,
- __enable_if_t<__has_random_access_iterator_category<_InputIterator>::value, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
-copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) {
- typedef typename iterator_traits<_InputIterator>::difference_type difference_type;
- typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize;
- _IntegralSize __n = __orig_n;
- return std::copy(__first, __first + difference_type(__n), __result);
+ __enable_if_t<!__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
+copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) {
+ using _IntegralSize = decltype(std::__convert_to_integral(__n));
+ _IntegralSize __converted = __n;
+ return std::__copy_n<_ClassicAlgPolicy>(__first, __iterator_difference_type<_InputIterator>(__converted), __result)
+ .second;
}
_LIBCPP_END_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP___ALGORITHM_COPY_N_H
diff --git a/libcxx/include/__algorithm/iterator_operations.h b/libcxx/include/__algorithm/iterator_operations.h
index e5c89c1e67e3a..1aa2f8d1604f1 100644
--- a/libcxx/include/__algorithm/iterator_operations.h
+++ b/libcxx/include/__algorithm/iterator_operations.h
@@ -219,6 +219,9 @@ struct _IterOps<_ClassicAlgPolicy> {
template <class _AlgPolicy, class _Iter>
using __policy_iter_diff_t _LIBCPP_NODEBUG = typename _IterOps<_AlgPolicy>::template __difference_type<_Iter>;
+template <class _AlgPolicy, class _Iter>
+using __policy_value_type _LIBCPP_NODEBUG = typename _IterOps<_AlgPolicy>::template __value_type<_Iter>;
+
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
diff --git a/libcxx/include/__algorithm/ranges_copy_n.h b/libcxx/include/__algorithm/ranges_copy_n.h
index 1fbc61674e2dd..6bee4c3e7c9e5 100644
--- a/libcxx/include/__algorithm/ranges_copy_n.h
+++ b/libcxx/include/__algorithm/ranges_copy_n.h
@@ -9,16 +9,12 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_COPY_N_H
#define _LIBCPP___ALGORITHM_RANGES_COPY_N_H
-#include <__algorithm/copy.h>
+#include <__algorithm/copy_n.h>
#include <__algorithm/in_out_result.h>
#include <__algorithm/iterator_operations.h>
-#include <__algorithm/ranges_copy.h>
#include <__config>
-#include <__functional/identity.h>
#include <__iterator/concepts.h>
#include <__iterator/incrementable_traits.h>
-#include <__iterator/unreachable_sentinel.h>
-#include <__iterator/wrap_iter.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -37,32 +33,13 @@ namespace ranges {
template <class _Ip, class _Op>
using copy_n_result = in_out_result<_Ip, _Op>;
-// TODO: Merge this with copy_n
struct __copy_n {
- template <class _InIter, class _DiffType, class _OutIter>
- _LIBCPP_HIDE_FROM_ABI constexpr static copy_n_result<_InIter, _OutIter>
- __go(_InIter __first, _DiffType __n, _OutIter __result) {
- while (__n != 0) {
- *__result = *__first;
- ++__first;
- ++__result;
- --__n;
- }
- return {std::move(__first), std::move(__result)};
- }
-
- template <random_access_iterator _InIter, class _DiffType, random_access_iterator _OutIter>
- _LIBCPP_HIDE_FROM_ABI constexpr static copy_n_result<_InIter, _OutIter>
- __go(_InIter __first, _DiffType __n, _OutIter __result) {
- auto __ret = std::__copy(__first, __first + __n, __result);
- return {__ret.first, __ret.second};
- }
-
template <input_iterator _Ip, weakly_incrementable _Op>
requires indirectly_copyable<_Ip, _Op>
_LIBCPP_HIDE_FROM_ABI constexpr copy_n_result<_Ip, _Op>
operator()(_Ip __first, iter_difference_t<_Ip> __n, _Op __result) const {
- return __go(std::move(__first), __n, std::move(__result));
+ auto __res = std::__copy_n<_RangeAlgPolicy>(std::move(__first), __n, std::move(__result));
+ return {std::move(__res.first), std::move(__res.second)};
}
};
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 7051e044314ea..4961a5fcb2067 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -12,11 +12,11 @@
#include <__algorithm/copy.h>
#include <__algorithm/copy_n.h>
#include <__algorithm/fill_n.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/max.h>
#include <__algorithm/min.h>
#include <__algorithm/move.h>
#include <__algorithm/move_backward.h>
-#include <__algorithm/ranges_copy_n.h>
#include <__algorithm/rotate.h>
#include <__assert>
#include <__config>
@@ -314,7 +314,7 @@ class vector {
is_constructible<value_type, typename iterator_traits<_ForwardIterator>::reference>::value,
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(_ForwardIterator __first, _ForwardIterator __last) {
- __assign_with_size(__first, __last, std::distance(__first, __last));
+ __assign_with_size<_ClassicAlgPolicy>(__first, __last, std::distance(__first, __last));
}
#if _LIBCPP_STD_VER >= 23
@@ -322,7 +322,7 @@ class vector {
_LIBCPP_HIDE_FROM_ABI constexpr void assign_range(_Range&& __range) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
- __assign_with_size(ranges::begin(__range), ranges::end(__range), __n);
+ __assign_with_size<_RangeAlgPolicy>(ranges::begin(__range), ranges::end(__range), __n);
} else {
__assign_with_sentinel(ranges::begin(__range), ranges::end(__range));
@@ -518,7 +518,7 @@ class vector {
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator
insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last) {
- return __insert_with_size(__position, __first, __last, std::distance(__first, __last));
+ return __insert_with_size<_ClassicAlgPolicy>(__position, __first, __last, std::distance(__first, __last));
}
#if _LIBCPP_STD_VER >= 23
@@ -526,7 +526,7 @@ class vector {
_LIBCPP_HIDE_FROM_ABI constexpr iterator insert_range(const_iterator __position, _Range&& __range) {
if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
- return __insert_with_size(__position, ranges::begin(__range), ranges::end(__range), __n);
+ return __insert_with_size<_RangeAlgPolicy>(__position, ranges::begin(__range), ranges::end(__range), __n);
} else {
return __insert_with_sentinel(__position, ranges::begin(__range), ranges::end(__range));
@@ -619,12 +619,13 @@ class vector {
// The `_Iterator` in `*_with_size` functions can be input-only only if called from `*_range` (since C++23).
// Otherwise, `_Iterator` is a forward iterator.
- template <class _Iterator, class _Sentinel>
+ template <class _AlgPolicy, class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
__assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n);
- template <class _Iterator,
- __enable_if_t<!is_same<decltype(*std::declval<_Iterator&>())&&, value_type&&>::value, int> = 0>
+ template <class _AlgPolicy,
+ class _Iterator,
+ __enable_if_t<!is_same<__policy_value_type<_AlgPolicy, _Iterator>, value_type>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
__insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) {
for (pointer __end_position = __position + __n; __position != __end_position; ++__position, (void)++__first) {
@@ -633,25 +634,19 @@ class vector {
}
}
- template <class _Iterator,
- __enable_if_t<is_same<decltype(*std::declval<_Iterator&>())&&, value_type&&>::value, int> = 0>
+ template <class _AlgPolicy,
+ class _Iterator,
+ __enable_if_t<is_same<__policy_value_type<_AlgPolicy, _Iterator>, value_type>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
__insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) {
-#if _LIBCPP_STD_VER >= 23
- if constexpr (!forward_iterator<_Iterator>) { // Handles input-only sized ranges for insert_range
- ranges::copy_n(std::move(__first), __n, __position);
- } else
-#endif
- {
- std::copy_n(__first, __n, __position);
- }
+ std::__copy_n<_AlgPolicy>(std::move(__first), __n, __position);
}
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator
__insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last);
- template <class _Iterator, class _Sentinel>
+ template <class _AlgPolicy, class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator
__insert_with_size(const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n);
@@ -1039,20 +1034,14 @@ vector<_Tp, _Allocator>::__assign_with_sentinel(_Iterator __first, _Sentinel __l
}
template <class _Tp, class _Allocator>
-template <class _Iterator, class _Sentinel>
+template <class _AlgPolicy, class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n) {
size_type __new_size = static_cast<size_type>(__n);
if (__new_size <= capacity()) {
if (__new_size > size()) {
-#if _LIBCPP_STD_VER >= 23
- auto __mid = ranges::copy_n(std::move(__first), size(), this->__begin_).in;
+ auto __mid = std::__copy_n<_AlgPolicy>(std::move(__first), size(), this->__begin_).first;
__construct_at_end(std::move(__mid), std::move(__last), __new_size - size());
-#else
- _Iterator __mid = std::next(__first, size());
- std::copy(__first, __mid, this->__begin_);
- __construct_at_end(__mid, __last, __new_size - size());
-#endif
} else {
pointer __m = std::__copy(std::move(__first), __last, this->__begin_).second;
this->__destruct_at_end(__m);
@@ -1326,7 +1315,7 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
}
template <class _Tp, class _Allocator>
-template <class _Iterator, class _Sentinel>
+template <class _AlgPolicy, class _Iterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator
vector<_Tp, _Allocator>::__insert_with_size(
const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n) {
@@ -1347,12 +1336,12 @@ vector<_Tp, _Allocator>::__insert_with_size(
__construct_at_end(__m, __last, __n - __dx);
if (__dx > 0) {
__move_range(__p, __old_last, __p + __n);
- __insert_assign_n_unchecked(__first, __dx, __p);
+ __insert_assign_n_unchecked<_AlgPolicy>(__first, __dx, __p);
}
}
} else {
__move_range(__p, __old_last, __p + __n);
- __insert_assign_n_unchecked(std::move(__first), __n, __p);
+ __insert_assign_n_unchecked<_AlgPolicy>(std::move(__first), __n, __p);
}
} else {
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
More information about the libcxx-commits
mailing list