[libcxx-commits] [libcxx] [libc++] Optimize ranges::copy for random_accsess_iterator and segmented_iterator (PR #120134)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jun 18 10:13:06 PDT 2025


================
@@ -221,12 +222,66 @@ struct __copy_impl {
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> >
   operator()(__bit_iterator<_Cp, _IsConst> __first,
              __bit_iterator<_Cp, _IsConst> __last,
-             __bit_iterator<_Cp, false> __result) const {
+             __bit_iterator<_Cp, /* IsConst = */ false> __result) const {
     if (__first.__ctz_ == __result.__ctz_)
       return std::make_pair(__last, std::__copy_aligned(__first, __last, __result));
     return std::make_pair(__last, std::__copy_unaligned(__first, __last, __result));
   }
 
+  template < class _InIter,
+             class _Cp,
+             __enable_if_t<!__is_segmented_iterator<_InIter>::value &&
+                               (__has_random_access_iterator_category<_InIter>::value ||
+                                __has_iterator_concept_convertible_to<_InIter, random_access_iterator_tag>::value) &&
+                               is_convertible<typename iterator_traits<_InIter>::value_type, bool>::value,
+                           int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, __bit_iterator<_Cp, false> >
+  operator()(_InIter __first, _InIter __last, __bit_iterator<_Cp, /* IsConst = */ false> __result) const {
+    using _It                      = __bit_iterator<_Cp, false>;
+    using __storage_type           = typename _It::__storage_type;
+    const unsigned __bits_per_word = _It::__bits_per_word;
+    __storage_type __n             = static_cast<__storage_type>(__last - __first);
+
+    if (__first != __last) {
+      // do first partial word, if present
+      if (__result.__ctz_ != 0) {
+        __storage_type __clz = static_cast<__storage_type>(__bits_per_word - __result.__ctz_);
+        __storage_type __dn  = std::min(__clz, __n);
+        __storage_type __w   = *__result.__seg_;
+        __storage_type __m   = std::__middle_mask<__storage_type>(__clz - __dn, __result.__ctz_);
+        __w &= ~__m;
+        for (__storage_type __i = 0; __i < __dn; ++__i, ++__first)
+          __w |= static_cast<__storage_type>(*__first) << __result.__ctz_++;
----------------
ldionne wrote:

Here you're static casting from e.g. `int*` to the storage type directly and you're shifting. When we copy from a sequence of `int`s to a `vector<bool>`, we should be performing a conversion of each integer to `bool`, and then setting the appropriate bit to either 0 or 1. I might be misunderstanding something here, but I don't see that that's what's happening.

I think what I am misunderstanding is how this happens:

> the optimization first assembles the input data into storage words

Could you please explain?

https://github.com/llvm/llvm-project/pull/120134


More information about the libcxx-commits mailing list