[libcxx-commits] [libcxx] [libc++] Optimize std::count and std::count_if for segmented iterators (PR #198375)

Aryan Naraghi via libcxx-commits libcxx-commits at lists.llvm.org
Sat May 23 10:21:45 PDT 2026


https://github.com/aryann updated https://github.com/llvm/llvm-project/pull/198375

>From bec55ed9b32b140a94e9763de3fab590dc3c830d Mon Sep 17 00:00:00 2001
From: Aryan Naraghi <aryan.naraghi at gmail.com>
Date: Mon, 18 May 2026 11:15:42 -0700
Subject: [PATCH 1/7] Implements segmented iterators for std::count and
 std::count_if

---
 libcxx/include/__algorithm/count.h    | 21 +++++++++++++++++++++
 libcxx/include/__algorithm/count_if.h | 20 ++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/libcxx/include/__algorithm/count.h b/libcxx/include/__algorithm/count.h
index 8529d110a30aa..f1b230691584e 100644
--- a/libcxx/include/__algorithm/count.h
+++ b/libcxx/include/__algorithm/count.h
@@ -10,6 +10,7 @@
 #ifndef _LIBCPP___ALGORITHM_COUNT_H
 #define _LIBCPP___ALGORITHM_COUNT_H
 
+#include <__algorithm/for_each_segment.h>
 #include <__algorithm/iterator_operations.h>
 #include <__algorithm/min.h>
 #include <__bit/invert_if.h>
@@ -18,6 +19,7 @@
 #include <__functional/identity.h>
 #include <__fwd/bit_reference.h>
 #include <__iterator/iterator_traits.h>
+#include <__iterator/segmented_iterator.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/invoke.h>
 
@@ -41,6 +43,25 @@ __count(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) {
   return __r;
 }
 
+// segmented iterator implementation
+#ifndef _LIBCPP_CXX03_LANG
+template <class _AlgPolicy,
+          class _SegmentedIterator,
+          class _Tp,
+          class _Proj,
+          __enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+typename _IterOps<_AlgPolicy>::template __difference_type<_SegmentedIterator>
+__count(_SegmentedIterator __first, _SegmentedIterator __last, const _Tp& __value, _Proj& __proj) {
+  typename _IterOps<_AlgPolicy>::template __difference_type<_SegmentedIterator> __r(0);
+  using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator;
+  std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
+    __r += std::__count<_AlgPolicy>(__lfirst, __llast, __value, __proj);
+  });
+  return __r;
+}
+#endif // _LIBCPP_CXX03_LANG
+
 // __bit_iterator implementation
 template <bool _ToCount, class _Cp, bool _IsConst>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bit_iterator<_Cp, _IsConst>::difference_type
diff --git a/libcxx/include/__algorithm/count_if.h b/libcxx/include/__algorithm/count_if.h
index 26f945e6bd98c..28329b948b687 100644
--- a/libcxx/include/__algorithm/count_if.h
+++ b/libcxx/include/__algorithm/count_if.h
@@ -10,10 +10,12 @@
 #ifndef _LIBCPP___ALGORITHM_COUNT_IF_H
 #define _LIBCPP___ALGORITHM_COUNT_IF_H
 
+#include <__algorithm/for_each_segment.h>
 #include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__functional/identity.h>
 #include <__iterator/iterator_traits.h>
+#include <__iterator/segmented_iterator.h>
 #include <__type_traits/invoke.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -33,6 +35,24 @@ __count_if(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) {
   return __counter;
 }
 
+// segmented iterator implementation
+#ifndef _LIBCPP_CXX03_LANG
+template <class _AlgPolicy,
+          class _SegmentedIterator,
+          class _Proj,
+          class _Pred,
+          __enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __policy_iter_diff_t<_AlgPolicy, _SegmentedIterator>
+__count_if(_SegmentedIterator __first, _SegmentedIterator __last, _Pred& __pred, _Proj& __proj) {
+  __policy_iter_diff_t<_AlgPolicy, _SegmentedIterator> __counter(0);
+  using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator;
+  std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
+    __counter += std::__count_if<_AlgPolicy>(__lfirst, __llast, __pred, __proj);
+  });
+  return __counter;
+}
+#endif // _LIBCPP_CXX03_LANG
+
 template <class _InputIterator, class _Predicate>
 [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
 typename iterator_traits<_InputIterator>::difference_type

>From 70d9d6cdee59e15a5cdac4ba75d04a6ce0c7d882 Mon Sep 17 00:00:00 2001
From: Aryan Naraghi <aryan.naraghi at gmail.com>
Date: Mon, 18 May 2026 11:19:02 -0700
Subject: [PATCH 2/7] Add release notes

---
 libcxx/docs/ReleaseNotes/23.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index a55869a8bf783..d7b396c0f6e6c 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -57,6 +57,8 @@ Improvements and New Features
   for ``std::deque<int>`` iterators.
 - ``std::copy(CharT*, CharT*, ostreambuf_iterator<CharT>)`` has been optimized, resulting in performance improvements
   of up to 25x.
+- The ``std::count`` and ``std::count_if`` algorithms have been optimized for
+  segmented iterators.
 
 Deprecations and Removals
 -------------------------

>From a229fe5f0786ee514d056b050c7b08e77f357c5d Mon Sep 17 00:00:00 2001
From: Aryan Naraghi <aryan.naraghi at gmail.com>
Date: Mon, 18 May 2026 11:44:08 -0700
Subject: [PATCH 3/7] Adds unit tests for std::count

---
 .../alg.nonmodifying/alg.count/count.pass.cpp | 39 +++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp
index 1561dcf8a6352..c331dd8ef44b7 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp
@@ -20,12 +20,14 @@
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
+#include <deque>
 #include <vector>
 
 #include "sized_allocator.h"
 #include "test_macros.h"
 #include "test_iterators.h"
 #include "type_algorithms.h"
+#include <list>
 
 struct Test {
   template <class Iter>
@@ -87,11 +89,48 @@ TEST_CONSTEXPR_CXX20 bool test() {
   return true;
 }
 
+void test_deque_and_join_view_iterators() {
+  {
+    // Verify that segmented deque iterators work properly
+    const int sizes[] = {0, 1, 2, 1023, 1024, 1025, 2047, 2048, 2049};
+    for (const int size : sizes) {
+      std::deque<int> deque(size, 1);
+
+      std::ptrdiff_t twos = 0;
+      for (int i = 0; i < size; i += 3) {
+        deque[i] = 2;
+        ++twos;
+      }
+      std::ptrdiff_t ones = deque.size() - twos;
+
+      assert(std::count(deque.begin(), deque.end(), 1) == ones);
+      assert(std::count(deque.begin(), deque.end(), 2) == twos);
+      assert(std::count(deque.begin(), deque.end(), 99) == 0);
+    }
+  }
+
+#if TEST_STD_VER >= 20
+  {
+    // Verify that join_view of lists work properly
+    std::list<std::list<int>> list = {{}, {0}, {1, 2}, {}, {0, 1, 2}, {0, 1, 2, 0}, {1}, {2, 0, 1}};
+    auto joined                    = list | std::views::join;
+
+    assert(std::count(joined.begin(), joined.end(), 0) == 5);
+    assert(std::count(joined.begin(), joined.end(), 1) == 5);
+    assert(std::count(joined.begin(), joined.end(), 2) == 4);
+    assert(std::count(joined.begin(), joined.end(), 99) == 0);
+  }
+#endif // TEST_STD_VER >= 20
+}
+
 int main(int, char**) {
   test();
 #if TEST_STD_VER >= 20
   static_assert(test());
 #endif
+#if TEST_STD_VER >= 11
+  test_deque_and_join_view_iterators();
+#endif
 
   return 0;
 }

>From 3cce3998ce746c76d6745c2ab52d4243826157a1 Mon Sep 17 00:00:00 2001
From: Aryan Naraghi <aryan.naraghi at gmail.com>
Date: Mon, 18 May 2026 11:46:44 -0700
Subject: [PATCH 4/7] Adds more test cases to std::count

---
 .../alg.nonmodifying/alg.count/count.pass.cpp | 21 ++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp
index c331dd8ef44b7..ce88f14425ab5 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp
@@ -89,19 +89,19 @@ TEST_CONSTEXPR_CXX20 bool test() {
   return true;
 }
 
-void test_deque_and_join_view_iterators() {
+void test_segmented_iterators() {
   {
     // Verify that segmented deque iterators work properly
-    const int sizes[] = {0, 1, 2, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int sizes[] = {0, 1, 2, 1023, 1024, 1025, 2047, 2048, 2049, 4097};
     for (const int size : sizes) {
       std::deque<int> deque(size, 1);
 
-      std::ptrdiff_t twos = 0;
+      int twos = 0;
       for (int i = 0; i < size; i += 3) {
         deque[i] = 2;
         ++twos;
       }
-      std::ptrdiff_t ones = deque.size() - twos;
+      int ones = deque.size() - twos;
 
       assert(std::count(deque.begin(), deque.end(), 1) == ones);
       assert(std::count(deque.begin(), deque.end(), 2) == twos);
@@ -120,6 +120,17 @@ void test_deque_and_join_view_iterators() {
     assert(std::count(joined.begin(), joined.end(), 2) == 4);
     assert(std::count(joined.begin(), joined.end(), 99) == 0);
   }
+
+  {
+    // Verify that join_view of vectors work properly
+    std::vector<std::vector<int>> vector = {{}, {0}, {1, 2}, {}, {0, 1, 2}, {0, 1, 2, 0}, {1}, {2, 0, 1}};
+    auto joined                          = vector | std::views::join;
+
+    assert(std::count(joined.begin(), joined.end(), 0) == 5);
+    assert(std::count(joined.begin(), joined.end(), 1) == 5);
+    assert(std::count(joined.begin(), joined.end(), 2) == 4);
+    assert(std::count(joined.begin(), joined.end(), 99) == 0);
+  }
 #endif // TEST_STD_VER >= 20
 }
 
@@ -129,7 +140,7 @@ int main(int, char**) {
   static_assert(test());
 #endif
 #if TEST_STD_VER >= 11
-  test_deque_and_join_view_iterators();
+  test_segmented_iterators();
 #endif
 
   return 0;

>From f42262a74d7419c4916db15b4c37a99740ff7873 Mon Sep 17 00:00:00 2001
From: Aryan Naraghi <aryan.naraghi at gmail.com>
Date: Mon, 18 May 2026 11:52:56 -0700
Subject: [PATCH 5/7] Adds std::count_if tests for segmented iterators

---
 .../alg.nonmodifying/alg.count/count.pass.cpp |  2 +-
 .../alg.count/count_if.pass.cpp               | 92 ++++++++++++++-----
 2 files changed, 69 insertions(+), 25 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp
index ce88f14425ab5..88d912600de94 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp
@@ -21,13 +21,13 @@
 #include <cstddef>
 #include <cstdint>
 #include <deque>
+#include <list>
 #include <vector>
 
 #include "sized_allocator.h"
 #include "test_macros.h"
 #include "test_iterators.h"
 #include "type_algorithms.h"
-#include <list>
 
 struct Test {
   template <class Iter>
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count_if.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count_if.pass.cpp
index 64c3d7ce3ac86..9672129690481 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count_if.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count_if.pass.cpp
@@ -15,44 +15,88 @@
 
 #include <algorithm>
 #include <cassert>
+#include <cstddef>
+#include <deque>
 #include <functional>
 #include <iterator>
+#include <list>
+#include <vector>
 
 #include "test_macros.h"
 #include "test_iterators.h"
 
 struct eq {
-    TEST_CONSTEXPR eq (int val) : v(val) {}
-    TEST_CONSTEXPR bool operator () (int v2) const { return v == v2; }
-    int v;
-    };
+  TEST_CONSTEXPR eq(int val) : v(val) {}
+  TEST_CONSTEXPR bool operator()(int v2) const { return v == v2; }
+  int v;
+};
 
 #if TEST_STD_VER > 17
 TEST_CONSTEXPR bool test_constexpr() {
-    int ia[] = {0, 1, 2, 2, 0, 1, 2, 3};
-    int ib[] = {1, 2, 3, 4, 5, 6};
-    return    (std::count_if(std::begin(ia), std::end(ia), eq(2)) == 3)
-           && (std::count_if(std::begin(ib), std::end(ib), eq(9)) == 0)
-           ;
-    }
+  int ia[] = {0, 1, 2, 2, 0, 1, 2, 3};
+  int ib[] = {1, 2, 3, 4, 5, 6};
+  return (std::count_if(std::begin(ia), std::end(ia), eq(2)) == 3) &&
+         (std::count_if(std::begin(ib), std::end(ib), eq(9)) == 0);
+}
 #endif
 
-int main(int, char**)
-{
-    int ia[] = {0, 1, 2, 2, 0, 1, 2, 3};
-    const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-    assert(std::count_if(cpp17_input_iterator<const int*>(ia),
-                         cpp17_input_iterator<const int*>(ia + sa),
-                         eq(2)) == 3);
-    assert(std::count_if(cpp17_input_iterator<const int*>(ia),
-                         cpp17_input_iterator<const int*>(ia + sa),
-                         eq(7)) == 0);
-    assert(std::count_if(cpp17_input_iterator<const int*>(ia),
-                         cpp17_input_iterator<const int*>(ia),
-                         eq(2)) == 0);
+void test_segmented_iterators() {
+  {
+    // Verify that segmented deque iterators work properly
+    const int sizes[] = {0, 1, 2, 1023, 1024, 1025, 2047, 2048, 2049};
+    for (const int size : sizes) {
+      std::deque<int> deque(size, 1);
+
+      std::ptrdiff_t twos = 0;
+      for (int i = 0; i < size; i += 3) {
+        deque[i] = 2;
+        ++twos;
+      }
+      std::ptrdiff_t ones = deque.size() - twos;
+
+      assert(std::count_if(deque.begin(), deque.end(), eq(1)) == ones);
+      assert(std::count_if(deque.begin(), deque.end(), eq(2)) == twos);
+      assert(std::count_if(deque.begin(), deque.end(), eq(99)) == 0);
+    }
+  }
+
+#if TEST_STD_VER >= 20
+  {
+    // Verify that join_view of lists work properly
+    std::list<std::list<int>> list = {{}, {0}, {1, 2}, {}, {0, 1, 2}, {0, 1, 2, 0}, {1}, {2, 0, 1}};
+    auto joined                    = list | std::views::join;
+
+    assert(std::count_if(joined.begin(), joined.end(), eq(0)) == 5);
+    assert(std::count_if(joined.begin(), joined.end(), eq(1)) == 5);
+    assert(std::count_if(joined.begin(), joined.end(), eq(2)) == 4);
+    assert(std::count_if(joined.begin(), joined.end(), eq(99)) == 0);
+  }
+
+  {
+    // Verify that join_view of vectors work properly
+    std::vector<std::vector<int>> vector = {{}, {0}, {1, 2}, {}, {0, 1, 2}, {0, 1, 2, 0}, {1}, {2, 0, 1}};
+    auto joined                          = vector | std::views::join;
+
+    assert(std::count_if(joined.begin(), joined.end(), eq(0)) == 5);
+    assert(std::count_if(joined.begin(), joined.end(), eq(1)) == 5);
+    assert(std::count_if(joined.begin(), joined.end(), eq(2)) == 4);
+    assert(std::count_if(joined.begin(), joined.end(), eq(99)) == 0);
+  }
+#endif // TEST_STD_VER >= 20
+}
+
+int main(int, char**) {
+  int ia[]          = {0, 1, 2, 2, 0, 1, 2, 3};
+  const unsigned sa = sizeof(ia) / sizeof(ia[0]);
+  assert(std::count_if(cpp17_input_iterator<const int*>(ia), cpp17_input_iterator<const int*>(ia + sa), eq(2)) == 3);
+  assert(std::count_if(cpp17_input_iterator<const int*>(ia), cpp17_input_iterator<const int*>(ia + sa), eq(7)) == 0);
+  assert(std::count_if(cpp17_input_iterator<const int*>(ia), cpp17_input_iterator<const int*>(ia), eq(2)) == 0);
 
 #if TEST_STD_VER > 17
-    static_assert(test_constexpr());
+  static_assert(test_constexpr());
+#endif
+#if TEST_STD_VER >= 11
+  test_segmented_iterators();
 #endif
 
   return 0;

>From 1027b0b1cd5fe3d4e897e49568e1b786abdeb124 Mon Sep 17 00:00:00 2001
From: Aryan Naraghi <aryan.naraghi at gmail.com>
Date: Tue, 19 May 2026 17:12:05 -0700
Subject: [PATCH 6/7] Reimplements count and count_if in terms of for_each

---
 libcxx/include/__algorithm/count.h    | 47 ++++++++++-----------------
 libcxx/include/__algorithm/count_if.h | 33 ++++++-------------
 2 files changed, 27 insertions(+), 53 deletions(-)

diff --git a/libcxx/include/__algorithm/count.h b/libcxx/include/__algorithm/count.h
index f1b230691584e..7b2e16d265f88 100644
--- a/libcxx/include/__algorithm/count.h
+++ b/libcxx/include/__algorithm/count.h
@@ -10,7 +10,7 @@
 #ifndef _LIBCPP___ALGORITHM_COUNT_H
 #define _LIBCPP___ALGORITHM_COUNT_H
 
-#include <__algorithm/for_each_segment.h>
+#include <__algorithm/for_each.h>
 #include <__algorithm/iterator_operations.h>
 #include <__algorithm/min.h>
 #include <__bit/invert_if.h>
@@ -19,7 +19,6 @@
 #include <__functional/identity.h>
 #include <__fwd/bit_reference.h>
 #include <__iterator/iterator_traits.h>
-#include <__iterator/segmented_iterator.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/invoke.h>
 
@@ -36,31 +35,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 template <class _AlgPolicy, class _Iter, class _Sent, class _Tp, class _Proj>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename _IterOps<_AlgPolicy>::template __difference_type<_Iter>
 __count(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) {
-  typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __r(0);
-  for (; __first != __last; ++__first)
-    if (std::__invoke(__proj, *__first) == __value)
-      ++__r;
-  return __r;
-}
+  typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __counter(0);
+
+  auto __apply = [&__value, &__counter](auto&& __elem) {
+    if (__elem == __value) {
+      ++__counter;
+    }
+  };
 
-// segmented iterator implementation
-#ifndef _LIBCPP_CXX03_LANG
-template <class _AlgPolicy,
-          class _SegmentedIterator,
-          class _Tp,
-          class _Proj,
-          __enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
-typename _IterOps<_AlgPolicy>::template __difference_type<_SegmentedIterator>
-__count(_SegmentedIterator __first, _SegmentedIterator __last, const _Tp& __value, _Proj& __proj) {
-  typename _IterOps<_AlgPolicy>::template __difference_type<_SegmentedIterator> __r(0);
-  using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator;
-  std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
-    __r += std::__count<_AlgPolicy>(__lfirst, __llast, __value, __proj);
-  });
-  return __r;
+  // We implement __count using __for_each to inherit its optimizations for
+  // segmented iterators. This improves performance without adding complexity.
+  std::__for_each(__first, __last, __apply, __proj);
+  return __counter;
 }
-#endif // _LIBCPP_CXX03_LANG
 
 // __bit_iterator implementation
 template <bool _ToCount, class _Cp, bool _IsConst>
@@ -71,25 +58,25 @@ __count_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_t
   using difference_type = typename _It::difference_type;
 
   const int __bits_per_word = _It::__bits_per_word;
-  difference_type __r       = 0;
+  difference_type __counter = 0;
   // do first partial word
   if (__first.__ctz_ != 0) {
     __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
     __storage_type __dn    = std::min(__clz_f, __n);
     __storage_type __m     = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_);
-    __r                    = std::__popcount(__storage_type(std::__invert_if<!_ToCount>(*__first.__seg_) & __m));
+    __counter              = std::__popcount(__storage_type(std::__invert_if<!_ToCount>(*__first.__seg_) & __m));
     __n -= __dn;
     ++__first.__seg_;
   }
   // do middle whole words
   for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word)
-    __r += std::__popcount(std::__invert_if<!_ToCount>(*__first.__seg_));
+    __counter += std::__popcount(std::__invert_if<!_ToCount>(*__first.__seg_));
   // do last partial word
   if (__n > 0) {
     __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
-    __r += std::__popcount(__storage_type(std::__invert_if<!_ToCount>(*__first.__seg_) & __m));
+    __counter += std::__popcount(__storage_type(std::__invert_if<!_ToCount>(*__first.__seg_) & __m));
   }
-  return __r;
+  return __counter;
 }
 
 template <class, class _Cp, bool _IsConst, class _Tp, class _Proj, __enable_if_t<__is_identity<_Proj>::value, int> = 0>
diff --git a/libcxx/include/__algorithm/count_if.h b/libcxx/include/__algorithm/count_if.h
index 28329b948b687..26960259319b1 100644
--- a/libcxx/include/__algorithm/count_if.h
+++ b/libcxx/include/__algorithm/count_if.h
@@ -10,12 +10,11 @@
 #ifndef _LIBCPP___ALGORITHM_COUNT_IF_H
 #define _LIBCPP___ALGORITHM_COUNT_IF_H
 
-#include <__algorithm/for_each_segment.h>
+#include <__algorithm/for_each.h>
 #include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__functional/identity.h>
 #include <__iterator/iterator_traits.h>
-#include <__iterator/segmented_iterator.h>
 #include <__type_traits/invoke.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -25,33 +24,21 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _AlgPolicy, class _Iter, class _Sent, class _Proj, class _Pred>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __policy_iter_diff_t<_AlgPolicy, _Iter>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __policy_iter_diff_t<_AlgPolicy, _Iter>
 __count_if(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) {
   __policy_iter_diff_t<_AlgPolicy, _Iter> __counter(0);
-  for (; __first != __last; ++__first) {
-    if (std::__invoke(__pred, std::__invoke(__proj, *__first)))
+
+  auto __apply = [&__pred, &__counter](auto&& __elem) {
+    if (std::__invoke(__pred, __elem)) {
       ++__counter;
-  }
-  return __counter;
-}
+    }
+  };
 
-// segmented iterator implementation
-#ifndef _LIBCPP_CXX03_LANG
-template <class _AlgPolicy,
-          class _SegmentedIterator,
-          class _Proj,
-          class _Pred,
-          __enable_if_t<__is_segmented_iterator_v<_SegmentedIterator>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __policy_iter_diff_t<_AlgPolicy, _SegmentedIterator>
-__count_if(_SegmentedIterator __first, _SegmentedIterator __last, _Pred& __pred, _Proj& __proj) {
-  __policy_iter_diff_t<_AlgPolicy, _SegmentedIterator> __counter(0);
-  using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator;
-  std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) {
-    __counter += std::__count_if<_AlgPolicy>(__lfirst, __llast, __pred, __proj);
-  });
+  // We implement __count_if using __for_each to inherit its optimizations for
+  // segmented iterators. This improves performance without adding complexity.
+  std::__for_each(__first, __last, __apply, __proj);
   return __counter;
 }
-#endif // _LIBCPP_CXX03_LANG
 
 template <class _InputIterator, class _Predicate>
 [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20

>From d5975eaa4c5f33fea67bbd812b5de32cb65fcf78 Mon Sep 17 00:00:00 2001
From: Aryan Naraghi <aryan.naraghi at gmail.com>
Date: Tue, 19 May 2026 17:16:06 -0700
Subject: [PATCH 7/7] Passed the iterators by rvalue

---
 libcxx/include/__algorithm/count.h    | 4 ++--
 libcxx/include/__algorithm/count_if.h | 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__algorithm/count.h b/libcxx/include/__algorithm/count.h
index 7b2e16d265f88..64d48e4d6c7f0 100644
--- a/libcxx/include/__algorithm/count.h
+++ b/libcxx/include/__algorithm/count.h
@@ -20,7 +20,7 @@
 #include <__fwd/bit_reference.h>
 #include <__iterator/iterator_traits.h>
 #include <__type_traits/enable_if.h>
-#include <__type_traits/invoke.h>
+#include <__utility/move.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -45,7 +45,7 @@ __count(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) {
 
   // We implement __count using __for_each to inherit its optimizations for
   // segmented iterators. This improves performance without adding complexity.
-  std::__for_each(__first, __last, __apply, __proj);
+  std::__for_each(std::move(__first), std::move(__last), __apply, __proj);
   return __counter;
 }
 
diff --git a/libcxx/include/__algorithm/count_if.h b/libcxx/include/__algorithm/count_if.h
index 26960259319b1..986a9d37720c8 100644
--- a/libcxx/include/__algorithm/count_if.h
+++ b/libcxx/include/__algorithm/count_if.h
@@ -16,6 +16,7 @@
 #include <__functional/identity.h>
 #include <__iterator/iterator_traits.h>
 #include <__type_traits/invoke.h>
+#include <__utility/move.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -36,7 +37,7 @@ __count_if(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) {
 
   // We implement __count_if using __for_each to inherit its optimizations for
   // segmented iterators. This improves performance without adding complexity.
-  std::__for_each(__first, __last, __apply, __proj);
+  std::__for_each(std::move(__first), std::move(__last), __apply, __proj);
   return __counter;
 }
 



More information about the libcxx-commits mailing list