Skip to content

Conversation

philnik777
Copy link
Contributor

This reduces the amount of code we have to maintain a bit.

This also simplifies vector by using the internal API instead of #ifs to switch based on language dialect.

@ldionne ldionne marked this pull request as ready for review September 9, 2025 15:44
@ldionne ldionne requested a review from a team as a code owner September 9, 2025 15:44
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Sep 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 9, 2025

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

This reduces the amount of code we have to maintain a bit.

This also simplifies vector by using the internal API instead of #ifs to switch based on language dialect.


Full diff: https://github.com/llvm/llvm-project/pull/157444.diff

3 Files Affected:

  • (modified) libcxx/include/__algorithm/copy_n.h (+31-28)
  • (modified) libcxx/include/__algorithm/ranges_copy_n.h (+3-27)
  • (modified) libcxx/include/__vector/vector.h (+2-16)
diff --git a/libcxx/include/__algorithm/copy_n.h b/libcxx/include/__algorithm/copy_n.h
index f93f39203a7e3..c868852cf3afe 100644
--- a/libcxx/include/__algorithm/copy_n.h
+++ b/libcxx/include/__algorithm/copy_n.h
@@ -13,48 +13,51 @@
 #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 _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) {
+template <class _InIter,
+          class _DiffType,
+          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, _DiffType __n, _OutIter __result) {
+  return std::__copy(__first, __first + __n, std::move(__result));
+}
+
+template <class _InIter,
+          class _DiffType,
+          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, _DiffType __n, _OutIter __result) {
+  while (__n != 0) {
     *__result = *__first;
+    ++__first;
     ++__result;
-    for (--__n; __n > 0; --__n) {
-      ++__first;
-      *__result = *__first;
-      ++__result;
-    }
+    --__n;
   }
-  return __result;
+  return std::make_pair(std::move(__first), std::move(__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);
+template <class _InputIterator, class _Size, class _OutputIterator>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator
+copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) {
+  using __diff_t = __iter_diff_t<_InputIterator>;
+  return std::__copy_n(__first, __diff_t(__n), __result).second;
 }
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // _LIBCPP___ALGORITHM_COPY_N_H
diff --git a/libcxx/include/__algorithm/ranges_copy_n.h b/libcxx/include/__algorithm/ranges_copy_n.h
index 1fbc61674e2dd..3819779701076 100644
--- a/libcxx/include/__algorithm/ranges_copy_n.h
+++ b/libcxx/include/__algorithm/ranges_copy_n.h
@@ -9,16 +9,11 @@
 #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 +32,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(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 4307e78f6ddbc..b9b5beddd5a99 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -16,7 +16,6 @@
 #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>
@@ -640,14 +639,7 @@ class vector {
             __enable_if_t<is_same<decltype(*std::declval<_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(__first, __n, __position);
   }
 
   template <class _InputIterator, class _Sentinel>
@@ -1066,14 +1058,8 @@ vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last,
   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(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);

@philnik777 philnik777 changed the title [libc++] Merge the implementations of ranges::copy_n and std::copy_n [libc++] Merge the implementations of ranges::copy_n and std::copy_n and fix vector::insert to assign Sep 20, 2025
@philnik777 philnik777 force-pushed the merge_copy_n_impls branch 2 times, most recently from e6e6f2f to df67f59 Compare September 24, 2025 13:40
#else

template <class _Iter>
using __iter_value_t _LIBCPP_NODEBUG = __iter_value_type<_Iter>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming in this file is starting to be pretty confusing. I'd like us to rename __iter_reference, __iter_diff_t and friends to something else. Maybe __classic_iter_diff_t or __iterator_traits_diff_t?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants