[libcxx-commits] [libcxx] [libc++] Refactor swap_ranges to use __specialized_algorithm for the vector<bool>::iterator specialization (PR #173384)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jan 28 01:08:51 PST 2026


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

>From cc702c885c108928649318dd74507a861b544d7c 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

---
 .../__algorithm/specialized_algorithms.h      |   1 +
 libcxx/include/__algorithm/swap_ranges.h      | 175 +++---------------
 libcxx/include/__bit_reference                | 161 +++++++++++++++-
 .../specialized_algorithms.compile.pass.cpp   |  73 ++++++++
 4 files changed, 249 insertions(+), 161 deletions(-)
 create mode 100644 libcxx/test/libcxx/algorithms/specialized_algorithms.compile.pass.cpp

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 fb8c3b55beec1..3a9e841f471ba 100644
--- a/libcxx/include/__algorithm/swap_ranges.h
+++ b/libcxx/include/__algorithm/swap_ranges.h
@@ -10,12 +10,11 @@
 #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 <__type_traits/enable_if.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,162 +25,36 @@ _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;
-}
-
-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));
+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));
 }
 
-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..5155f18754b58 100644
--- a/libcxx/include/__bit_reference
+++ b/libcxx/include/__bit_reference
@@ -19,7 +19,6 @@
 #include <__algorithm/min.h>
 #include <__algorithm/rotate.h>
 #include <__algorithm/specialized_algorithms.h>
-#include <__algorithm/swap_ranges.h>
 #include <__assert>
 #include <__bit/countr.h>
 #include <__compare/ordering.h>
@@ -487,15 +486,6 @@ private:
       __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result);
   template <class _AlgPolicy>
   friend struct __copy_backward_impl;
-  template <class _Cl, class _Cr>
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Cr, false>
-      __swap_ranges_aligned(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>);
-  template <class _Cl, class _Cr>
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Cr, false>
-      __swap_ranges_unaligned(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>);
-  template <class, class _Cl, class _Cr>
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 friend pair<__bit_iterator<_Cl, false>, __bit_iterator<_Cr, false> >
-      __swap_ranges(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>);
   template <class, class _Dp>
   _LIBCPP_CONSTEXPR_SINCE_CXX20 friend pair<__bit_iterator<_Dp, false>, __bit_iterator<_Dp, false> >
       __rotate(__bit_iterator<_Dp, false>, __bit_iterator<_Dp, false>, __bit_iterator<_Dp, false>);
@@ -728,6 +718,157 @@ 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> > > {
+  static const bool __has_algorithm = true;
+
+  _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
diff --git a/libcxx/test/libcxx/algorithms/specialized_algorithms.compile.pass.cpp b/libcxx/test/libcxx/algorithms/specialized_algorithms.compile.pass.cpp
new file mode 100644
index 0000000000000..e765b92ed68a2
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/specialized_algorithms.compile.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make use that `__specialized_algorithm::__has_algorithm` is true when we expect it to be
+
+// UNSUPPORTED: c++03
+
+// ADDITIONAL_COMPILE_FLAGS: -Wno-c++14-extensions -Wno-c++17-extensions
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <vector>
+
+template <class... Args>
+inline constexpr bool has_alg = std::__specialized_algorithm<Args...>::__has_algorithm;
+
+template <class T>
+using single_iter = std::__single_iterator<T>;
+
+template <class T, class U>
+using iter_pair = std::__iterator_pair<T, U>;
+
+template <class T>
+using single_range = std::__single_range<T>;
+
+namespace Alg = std::_Algorithm;
+
+namespace vector_bool {
+using iter       = typename std::vector<bool>::iterator;
+using const_iter = typename std::vector<bool>::const_iterator;
+static_assert(has_alg<Alg::__fill_n, single_iter<iter>>);
+static_assert(has_alg<Alg::__copy, iter_pair<iter, iter>, single_iter<iter>>);
+static_assert(has_alg<Alg::__copy, iter_pair<const_iter, const_iter>, single_iter<iter>>);
+static_assert(has_alg<Alg::__swap_ranges, iter_pair<iter, iter>, single_iter<iter>>);
+} // namespace vector_bool
+
+namespace set {
+using iter       = typename std::set<int>::iterator;
+using const_iter = typename std::set<int>::const_iterator;
+static_assert(has_alg<Alg::__for_each, iter_pair<iter, iter>>);
+static_assert(has_alg<Alg::__for_each, iter_pair<const_iter, const_iter>>);
+static_assert(has_alg<Alg::__for_each, single_range<std::set<int>>>);
+} // namespace set
+
+namespace multiset {
+using iter       = typename std::multiset<int>::iterator;
+using const_iter = typename std::multiset<int>::const_iterator;
+static_assert(has_alg<Alg::__for_each, iter_pair<iter, iter>>);
+static_assert(has_alg<Alg::__for_each, iter_pair<const_iter, const_iter>>);
+static_assert(has_alg<Alg::__for_each, single_range<std::multiset<int>>>);
+} // namespace multiset
+
+namespace map {
+using iter       = typename std::map<int, int>::iterator;
+using const_iter = typename std::map<int, int>::const_iterator;
+static_assert(has_alg<Alg::__for_each, iter_pair<iter, iter>>);
+static_assert(has_alg<Alg::__for_each, iter_pair<const_iter, const_iter>>);
+static_assert(has_alg<Alg::__for_each, single_range<std::map<int, int>>>);
+} // namespace map
+
+namespace multimap {
+using iter       = typename std::multimap<int, int>::iterator;
+using const_iter = typename std::multimap<int, int>::const_iterator;
+static_assert(has_alg<Alg::__for_each, iter_pair<iter, iter>>);
+static_assert(has_alg<Alg::__for_each, iter_pair<const_iter, const_iter>>);
+static_assert(has_alg<Alg::__for_each, single_range<std::multimap<int, int>>>);
+} // namespace multimap



More information about the libcxx-commits mailing list