[libcxx-commits] [libcxx] [libc++] Refactor swap_ranges dispatching (PR #173384)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Tue Dec 23 06:39:39 PST 2025


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/173384

This patch does two things:
1) It moves ranges-only code into `ranges_swap_ranges.h` and refactors that dispatching
2) It refactors the `vector<bool>::iterator` specialization to use `__specialized_algorithm` dispatching


>From 91b0bc658bf11ae2fa0415f16b6268d953f744ad Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 23 Dec 2025 15:37:52 +0100
Subject: [PATCH] [libc++] Refactor swap_ranges dispatching

---
 .../include/__algorithm/ranges_swap_ranges.h  |  23 +-
 .../__algorithm/specialized_algorithms.h      |   1 +
 libcxx/include/__algorithm/swap_ranges.h      | 199 ++----------------
 libcxx/include/__bit_reference                | 149 +++++++++++++
 4 files changed, 193 insertions(+), 179 deletions(-)

diff --git a/libcxx/include/__algorithm/ranges_swap_ranges.h b/libcxx/include/__algorithm/ranges_swap_ranges.h
index ab6db50d8a13e..635c22f1373fc 100644
--- a/libcxx/include/__algorithm/ranges_swap_ranges.h
+++ b/libcxx/include/__algorithm/ranges_swap_ranges.h
@@ -41,9 +41,26 @@ struct __swap_ranges {
     requires indirectly_swappable<_I1, _I2>
   _LIBCPP_HIDE_FROM_ABI constexpr swap_ranges_result<_I1, _I2>
   operator()(_I1 __first1, _S1 __last1, _I2 __first2, _S2 __last2) const {
-    auto __ret = std::__swap_ranges<_RangeAlgPolicy>(
-        std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2));
-    return {std::move(__ret.first), std::move(__ret.second)};
+    if constexpr (sized_sentinel_for<_I1, _S1> && sized_sentinel_for<_I2, _S2> &&
+                  (random_access_iterator<_I1> || random_access_iterator<_I2>)) {
+      auto __offset = std::min(__last1 - __first1, __last2 - __first2);
+
+      if constexpr (random_access_iterator<_I1>) {
+        auto __ret = std::__swap_ranges<_RangeAlgPolicy>(__first1, __first1 + __offset, std::move(__first2));
+        return {std::move(__ret.first), std::move(__ret.second)};
+      } else {
+        auto __ret = std::__swap_ranges<_RangeAlgPolicy>(__first2, __first2 + __offset, std::move(__first1));
+        return {std::move(__ret.first), std::move(__ret.second)};
+      }
+    } else {
+      while (__first1 != __last1 && __first2 != __last2) {
+        ranges::iter_swap(__first1, __first2);
+        ++__first1;
+        ++__first2;
+      }
+
+      return {std::move(__first1), std::move(__first2)};
+    }
   }
 
   template <input_range _R1, input_range _R2>
diff --git a/libcxx/include/__algorithm/specialized_algorithms.h b/libcxx/include/__algorithm/specialized_algorithms.h
index 7cb94c015f767..58b4d93ee6894 100644
--- a/libcxx/include/__algorithm/specialized_algorithms.h
+++ b/libcxx/include/__algorithm/specialized_algorithms.h
@@ -21,6 +21,7 @@ namespace _Algorithm {
 struct __copy {};
 struct __fill_n {};
 struct __for_each {};
+struct __swap_ranges {};
 } // namespace _Algorithm
 
 template <class>
diff --git a/libcxx/include/__algorithm/swap_ranges.h b/libcxx/include/__algorithm/swap_ranges.h
index 2731d4feaa63d..f81d9da2c13be 100644
--- a/libcxx/include/__algorithm/swap_ranges.h
+++ b/libcxx/include/__algorithm/swap_ranges.h
@@ -10,12 +10,10 @@
 #define _LIBCPP___ALGORITHM_SWAP_RANGES_H
 
 #include <__algorithm/iterator_operations.h>
-#include <__algorithm/min.h>
+#include <__algorithm/specialized_algorithms.h>
 #include <__config>
-#include <__fwd/bit_reference.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
-#include <__utility/swap.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -26,189 +24,38 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Cl, class _Cr>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cr, false> __swap_ranges_aligned(
-    __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) {
-  using _I1             = __bit_iterator<_Cl, false>;
-  using difference_type = typename _I1::difference_type;
-  using __storage_type  = typename _I1::__storage_type;
-
-  const int __bits_per_word = _I1::__bits_per_word;
-  difference_type __n       = __last - __first;
-  if (__n > 0) {
-    // do first word
-    if (__first.__ctz_ != 0) {
-      unsigned __clz       = __bits_per_word - __first.__ctz_;
-      difference_type __dn = std::min(static_cast<difference_type>(__clz), __n);
-      __n -= __dn;
-      __storage_type __m  = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz - __dn));
-      __storage_type __b1 = *__first.__seg_ & __m;
-      *__first.__seg_ &= ~__m;
-      __storage_type __b2 = *__result.__seg_ & __m;
-      *__result.__seg_ &= ~__m;
-      *__result.__seg_ |= __b1;
-      *__first.__seg_ |= __b2;
-      __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word;
-      __result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word);
-      ++__first.__seg_;
-      // __first.__ctz_ = 0;
-    }
-    // __first.__ctz_ == 0;
-    // do middle words
-    for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_, ++__result.__seg_)
-      swap(*__first.__seg_, *__result.__seg_);
-    // do last word
-    if (__n > 0) {
-      __storage_type __m  = ~__storage_type(0) >> (__bits_per_word - __n);
-      __storage_type __b1 = *__first.__seg_ & __m;
-      *__first.__seg_ &= ~__m;
-      __storage_type __b2 = *__result.__seg_ & __m;
-      *__result.__seg_ &= ~__m;
-      *__result.__seg_ |= __b1;
-      *__first.__seg_ |= __b2;
-      __result.__ctz_ = static_cast<unsigned>(__n);
-    }
-  }
-  return __result;
-}
-
-template <class _Cl, class _Cr>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cr, false> __swap_ranges_unaligned(
-    __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) {
-  using _I1             = __bit_iterator<_Cl, false>;
-  using difference_type = typename _I1::difference_type;
-  using __storage_type  = typename _I1::__storage_type;
-
-  const int __bits_per_word = _I1::__bits_per_word;
-  difference_type __n       = __last - __first;
-  if (__n > 0) {
-    // do first word
-    if (__first.__ctz_ != 0) {
-      unsigned __clz_f     = __bits_per_word - __first.__ctz_;
-      difference_type __dn = std::min(static_cast<difference_type>(__clz_f), __n);
-      __n -= __dn;
-      __storage_type __m  = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
-      __storage_type __b1 = *__first.__seg_ & __m;
-      *__first.__seg_ &= ~__m;
-      unsigned __clz_r     = __bits_per_word - __result.__ctz_;
-      __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r);
-      __m                  = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn));
-      __storage_type __b2  = *__result.__seg_ & __m;
-      *__result.__seg_ &= ~__m;
-      if (__result.__ctz_ > __first.__ctz_) {
-        unsigned __s = __result.__ctz_ - __first.__ctz_;
-        *__result.__seg_ |= __b1 << __s;
-        *__first.__seg_ |= __b2 >> __s;
-      } else {
-        unsigned __s = __first.__ctz_ - __result.__ctz_;
-        *__result.__seg_ |= __b1 >> __s;
-        *__first.__seg_ |= __b2 << __s;
-      }
-      __result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word;
-      __result.__ctz_ = static_cast<unsigned>((__ddn + __result.__ctz_) % __bits_per_word);
-      __dn -= __ddn;
-      if (__dn > 0) {
-        __m  = ~__storage_type(0) >> (__bits_per_word - __dn);
-        __b2 = *__result.__seg_ & __m;
-        *__result.__seg_ &= ~__m;
-        unsigned __s = __first.__ctz_ + __ddn;
-        *__result.__seg_ |= __b1 >> __s;
-        *__first.__seg_ |= __b2 << __s;
-        __result.__ctz_ = static_cast<unsigned>(__dn);
-      }
-      ++__first.__seg_;
-      // __first.__ctz_ = 0;
-    }
-    // __first.__ctz_ == 0;
-    // do middle words
-    __storage_type __m = ~__storage_type(0) << __result.__ctz_;
-    unsigned __clz_r   = __bits_per_word - __result.__ctz_;
-    for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) {
-      __storage_type __b1 = *__first.__seg_;
-      __storage_type __b2 = *__result.__seg_ & __m;
-      *__result.__seg_ &= ~__m;
-      *__result.__seg_ |= __b1 << __result.__ctz_;
-      *__first.__seg_ = __b2 >> __result.__ctz_;
-      ++__result.__seg_;
-      __b2 = *__result.__seg_ & ~__m;
-      *__result.__seg_ &= __m;
-      *__result.__seg_ |= __b1 >> __clz_r;
-      *__first.__seg_ |= __b2 << __clz_r;
-    }
-    // do last word
-    if (__n > 0) {
-      __m                 = ~__storage_type(0) >> (__bits_per_word - __n);
-      __storage_type __b1 = *__first.__seg_ & __m;
-      *__first.__seg_ &= ~__m;
-      __storage_type __dn = std::min<__storage_type>(__n, __clz_r);
-      __m                 = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn));
-      __storage_type __b2 = *__result.__seg_ & __m;
-      *__result.__seg_ &= ~__m;
-      *__result.__seg_ |= __b1 << __result.__ctz_;
-      *__first.__seg_ |= __b2 >> __result.__ctz_;
-      __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word;
-      __result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word);
-      __n -= __dn;
-      if (__n > 0) {
-        __m  = ~__storage_type(0) >> (__bits_per_word - __n);
-        __b2 = *__result.__seg_ & __m;
-        *__result.__seg_ &= ~__m;
-        *__result.__seg_ |= __b1 >> __dn;
-        *__first.__seg_ |= __b2 << __dn;
-        __result.__ctz_ = static_cast<unsigned>(__n);
-      }
-    }
-  }
-  return __result;
-}
-
 // 2+1 iterators: size2 >= size1; used by std::swap_ranges.
-template <class, class _Cl, class _Cr>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cl, false>, __bit_iterator<_Cr, false> >
-__swap_ranges(__bit_iterator<_Cl, false> __first1,
-              __bit_iterator<_Cl, false> __last1,
-              __bit_iterator<_Cr, false> __first2) {
-  if (__first1.__ctz_ == __first2.__ctz_)
-    return std::make_pair(__last1, std::__swap_ranges_aligned(__first1, __last1, __first2));
-  return std::make_pair(__last1, std::__swap_ranges_unaligned(__first1, __last1, __first2));
-}
-
-// 2+2 iterators: used by std::ranges::swap_ranges.
-template <class _AlgPolicy, class _Cl, class _Cr>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cl, false>, __bit_iterator<_Cr, false> >
-__swap_ranges(__bit_iterator<_Cl, false> __first1,
-              __bit_iterator<_Cl, false> __last1,
-              __bit_iterator<_Cr, false> __first2,
-              __bit_iterator<_Cr, false> __last2) {
-  if (__last1 - __first1 < __last2 - __first2)
-    return std::make_pair(__last1, std::__swap_ranges<_AlgPolicy>(__first1, __last1, __first2).second);
-  return std::make_pair(std::__swap_ranges<_AlgPolicy>(__first2, __last2, __first1).second, __last2);
-}
-
-// 2+2 iterators: the shorter size will be used.
-template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _ForwardIterator2, class _Sentinel2>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator1, _ForwardIterator2>
-__swap_ranges(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2, _Sentinel2 __last2) {
-  while (__first1 != __last1 && __first2 != __last2) {
-    _IterOps<_AlgPolicy>::iter_swap(__first1, __first2);
-    ++__first1;
-    ++__first2;
-  }
-
-  return pair<_ForwardIterator1, _ForwardIterator2>(std::move(__first1), std::move(__first2));
+template <
+    class _AlgPolicy,
+    class _Iter1,
+    class _Sent1,
+    class _Iter2,
+    class _SpecialAlg =
+        __specialized_algorithm<_Algorithm::__swap_ranges, __iterator_pair<_Iter1, _Sent1>, __single_iterator<_Iter2> >,
+    __enable_if_t<_SpecialAlg::__has_algorithm, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter1, _Iter2>
+__swap_ranges(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2) {
+  return _SpecialAlg()(std::move(__first1), std::move(__last1), std::move(__first2));
 }
 
 // 2+1 iterators: size2 >= size1.
-template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _ForwardIterator2>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator1, _ForwardIterator2>
-__swap_ranges(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2) {
+template <
+    class _AlgPolicy,
+    class _Iter1,
+    class _Sent1,
+    class _Iter2,
+    class _SpecialAlg =
+        __specialized_algorithm<_Algorithm::__swap_ranges, __iterator_pair<_Iter1, _Sent1>, __single_iterator<_Iter2> >,
+    __enable_if_t<!_SpecialAlg::__has_algorithm, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter1, _Iter2>
+__swap_ranges(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2) {
   while (__first1 != __last1) {
     _IterOps<_AlgPolicy>::iter_swap(__first1, __first2);
     ++__first1;
     ++__first2;
   }
 
-  return pair<_ForwardIterator1, _ForwardIterator2>(std::move(__first1), std::move(__first2));
+  return pair<_Iter1, _Iter2>(std::move(__first1), std::move(__first2));
 }
 
 template <class _ForwardIterator1, class _ForwardIterator2>
diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference
index 8daf3a2baafcd..ed179d03618f5 100644
--- a/libcxx/include/__bit_reference
+++ b/libcxx/include/__bit_reference
@@ -728,6 +728,155 @@ struct __specialized_algorithm<_Algorithm::__copy,
   }
 };
 
+template <class _Cl, class _Cr>
+struct __specialized_algorithm<_Algorithm::__swap_ranges,
+                               __iterator_pair<__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false> >,
+                               __single_iterator<__bit_iterator<_Cr, false> > > {
+  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cr, false> __aligned_impl(
+      __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) {
+    using _I1             = __bit_iterator<_Cl, false>;
+    using difference_type = typename _I1::difference_type;
+    using __storage_type  = typename _I1::__storage_type;
+
+    const int __bits_per_word = _I1::__bits_per_word;
+    difference_type __n       = __last - __first;
+    if (__n > 0) {
+      // do first word
+      if (__first.__ctz_ != 0) {
+        unsigned __clz       = __bits_per_word - __first.__ctz_;
+        difference_type __dn = std::min(static_cast<difference_type>(__clz), __n);
+        __n -= __dn;
+        __storage_type __m  = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz - __dn));
+        __storage_type __b1 = *__first.__seg_ & __m;
+        *__first.__seg_ &= ~__m;
+        __storage_type __b2 = *__result.__seg_ & __m;
+        *__result.__seg_ &= ~__m;
+        *__result.__seg_ |= __b1;
+        *__first.__seg_ |= __b2;
+        __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word;
+        __result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word);
+        ++__first.__seg_;
+        // __first.__ctz_ = 0;
+      }
+      // __first.__ctz_ == 0;
+      // do middle words
+      for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_, ++__result.__seg_)
+        swap(*__first.__seg_, *__result.__seg_);
+      // do last word
+      if (__n > 0) {
+        __storage_type __m  = ~__storage_type(0) >> (__bits_per_word - __n);
+        __storage_type __b1 = *__first.__seg_ & __m;
+        *__first.__seg_ &= ~__m;
+        __storage_type __b2 = *__result.__seg_ & __m;
+        *__result.__seg_ &= ~__m;
+        *__result.__seg_ |= __b1;
+        *__first.__seg_ |= __b2;
+        __result.__ctz_ = static_cast<unsigned>(__n);
+      }
+    }
+    return __result;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cr, false> __unaligned_impl(
+      __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) {
+    using _I1             = __bit_iterator<_Cl, false>;
+    using difference_type = typename _I1::difference_type;
+    using __storage_type  = typename _I1::__storage_type;
+
+    const int __bits_per_word = _I1::__bits_per_word;
+    difference_type __n       = __last - __first;
+    if (__n > 0) {
+      // do first word
+      if (__first.__ctz_ != 0) {
+        unsigned __clz_f     = __bits_per_word - __first.__ctz_;
+        difference_type __dn = std::min(static_cast<difference_type>(__clz_f), __n);
+        __n -= __dn;
+        __storage_type __m  = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
+        __storage_type __b1 = *__first.__seg_ & __m;
+        *__first.__seg_ &= ~__m;
+        unsigned __clz_r     = __bits_per_word - __result.__ctz_;
+        __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r);
+        __m                  = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn));
+        __storage_type __b2  = *__result.__seg_ & __m;
+        *__result.__seg_ &= ~__m;
+        if (__result.__ctz_ > __first.__ctz_) {
+          unsigned __s = __result.__ctz_ - __first.__ctz_;
+          *__result.__seg_ |= __b1 << __s;
+          *__first.__seg_ |= __b2 >> __s;
+        } else {
+          unsigned __s = __first.__ctz_ - __result.__ctz_;
+          *__result.__seg_ |= __b1 >> __s;
+          *__first.__seg_ |= __b2 << __s;
+        }
+        __result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word;
+        __result.__ctz_ = static_cast<unsigned>((__ddn + __result.__ctz_) % __bits_per_word);
+        __dn -= __ddn;
+        if (__dn > 0) {
+          __m  = ~__storage_type(0) >> (__bits_per_word - __dn);
+          __b2 = *__result.__seg_ & __m;
+          *__result.__seg_ &= ~__m;
+          unsigned __s = __first.__ctz_ + __ddn;
+          *__result.__seg_ |= __b1 >> __s;
+          *__first.__seg_ |= __b2 << __s;
+          __result.__ctz_ = static_cast<unsigned>(__dn);
+        }
+        ++__first.__seg_;
+        // __first.__ctz_ = 0;
+      }
+      // __first.__ctz_ == 0;
+      // do middle words
+      __storage_type __m = ~__storage_type(0) << __result.__ctz_;
+      unsigned __clz_r   = __bits_per_word - __result.__ctz_;
+      for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) {
+        __storage_type __b1 = *__first.__seg_;
+        __storage_type __b2 = *__result.__seg_ & __m;
+        *__result.__seg_ &= ~__m;
+        *__result.__seg_ |= __b1 << __result.__ctz_;
+        *__first.__seg_ = __b2 >> __result.__ctz_;
+        ++__result.__seg_;
+        __b2 = *__result.__seg_ & ~__m;
+        *__result.__seg_ &= __m;
+        *__result.__seg_ |= __b1 >> __clz_r;
+        *__first.__seg_ |= __b2 << __clz_r;
+      }
+      // do last word
+      if (__n > 0) {
+        __m                 = ~__storage_type(0) >> (__bits_per_word - __n);
+        __storage_type __b1 = *__first.__seg_ & __m;
+        *__first.__seg_ &= ~__m;
+        __storage_type __dn = std::min<__storage_type>(__n, __clz_r);
+        __m                 = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn));
+        __storage_type __b2 = *__result.__seg_ & __m;
+        *__result.__seg_ &= ~__m;
+        *__result.__seg_ |= __b1 << __result.__ctz_;
+        *__first.__seg_ |= __b2 >> __result.__ctz_;
+        __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word;
+        __result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word);
+        __n -= __dn;
+        if (__n > 0) {
+          __m  = ~__storage_type(0) >> (__bits_per_word - __n);
+          __b2 = *__result.__seg_ & __m;
+          *__result.__seg_ &= ~__m;
+          *__result.__seg_ |= __b1 >> __dn;
+          *__first.__seg_ |= __b2 << __dn;
+          __result.__ctz_ = static_cast<unsigned>(__n);
+        }
+      }
+    }
+    return __result;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI static
+      _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cl, false>, __bit_iterator<_Cr, false> >
+      operator()(__bit_iterator<_Cl, false> __first1,
+                 __bit_iterator<_Cl, false> __last1,
+                 __bit_iterator<_Cr, false> __first2) {
+    if (__first1.__ctz_ == __first2.__ctz_)
+      return std::make_pair(__last1, __aligned_impl(__first1, __last1, __first2));
+    return std::make_pair(__last1, __unaligned_impl(__first1, __last1, __first2));
+  }
+};
+
 _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS



More information about the libcxx-commits mailing list