[libcxx-commits] [libcxx] [libc++][pstl] Introduce a "statpart" backend (PR #230540)

Michael G. Kazakov via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 16 05:15:08 PDT 2026


https://github.com/mikekazakov updated https://github.com/llvm/llvm-project/pull/230540

>From 4f222cde8246d1c139493786b3421921b33fd645 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 9 Oct 2026 15:53:38 +0100
Subject: [PATCH 01/24] Introduce a "statpart" backend

---
 libcxx/CMakeLists.txt                         |    2 +
 libcxx/include/CMakeLists.txt                 |    1 +
 libcxx/include/__config_site.in               |    1 +
 libcxx/include/__pstl/backend.h               |    6 +
 libcxx/include/__pstl/backend_fwd.h           |    3 +
 libcxx/include/__pstl/backends/statpart.h     | 1207 +++++++++++++++++
 libcxx/include/module.modulemap.in            |    3 +
 libcxx/src/CMakeLists.txt                     |    6 +
 libcxx/src/pstl/statpart.cpp                  |   26 +
 .../test/libcxx/transitive_includes/cxx17.csv |    4 +
 .../test/libcxx/transitive_includes/cxx20.csv |    4 +
 .../test/libcxx/transitive_includes/cxx23.csv |    4 +
 .../test/libcxx/transitive_includes/cxx26.csv |    4 +
 13 files changed, 1271 insertions(+)
 create mode 100644 libcxx/include/__pstl/backends/statpart.h
 create mode 100644 libcxx/src/pstl/statpart.cpp

diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index d163f0f579c395..5478c38afa781d 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -803,6 +803,8 @@ elseif(LIBCXX_PSTL_BACKEND STREQUAL "std_thread")
   config_define(1 _LIBCPP_PSTL_BACKEND_STD_THREAD)
 elseif(LIBCXX_PSTL_BACKEND STREQUAL "libdispatch")
   config_define(1 _LIBCPP_PSTL_BACKEND_LIBDISPATCH)
+elseif(LIBCXX_PSTL_BACKEND STREQUAL "statpart")
+  config_define(1 _LIBCPP_PSTL_BACKEND_STATPART)
 else()
   message(FATAL_ERROR "LIBCXX_PSTL_BACKEND is set to ${LIBCXX_PSTL_BACKEND}, which is not a valid backend.
                        Valid backends are: serial, std_thread and libdispatch")
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 1ee2081561fd97..da2546a54bc04d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -695,6 +695,7 @@ set(files
   __pstl/backends/default.h
   __pstl/backends/libdispatch.h
   __pstl/backends/serial.h
+  __pstl/backends/statpart.h
   __pstl/backends/std_thread.h
   __pstl/cpu_algos/any_of.h
   __pstl/cpu_algos/cpu_traits.h
diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in
index e6e33a2eeb2a9e..b0a2230c42c21d 100644
--- a/libcxx/include/__config_site.in
+++ b/libcxx/include/__config_site.in
@@ -36,6 +36,7 @@
 #cmakedefine _LIBCPP_PSTL_BACKEND_SERIAL
 #cmakedefine _LIBCPP_PSTL_BACKEND_STD_THREAD
 #cmakedefine _LIBCPP_PSTL_BACKEND_LIBDISPATCH
+#cmakedefine _LIBCPP_PSTL_BACKEND_STATPART
 
 // Hardening.
 #cmakedefine _LIBCPP_HARDENING_MODE_DEFAULT @_LIBCPP_HARDENING_MODE_DEFAULT@
diff --git a/libcxx/include/__pstl/backend.h b/libcxx/include/__pstl/backend.h
index 5980b0708cd340..75ccb5063c2919 100644
--- a/libcxx/include/__pstl/backend.h
+++ b/libcxx/include/__pstl/backend.h
@@ -30,8 +30,14 @@ _LIBCPP_PUSH_MACROS
 #  elif defined(_LIBCPP_PSTL_BACKEND_LIBDISPATCH)
 #    include <__pstl/backends/default.h>
 #    include <__pstl/backends/libdispatch.h>
+#  elif defined(_LIBCPP_PSTL_BACKEND_STATPART)
+#    include <__pstl/backends/default.h>
+#    include <__pstl/backends/statpart.h>
 #  endif
 
+// statpart pulls <cerrno> in transitively via __thread/thread.h, make sure this include is not is conditional/flaky
+#  include <cerrno>
+
 #endif // _LIBCPP_STD_VER >= 17
 
 _LIBCPP_POP_MACROS
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index 2665209887944f..31ae6581e1a52d 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -51,6 +51,7 @@ struct __default_backend_tag;
 struct __libdispatch_backend_tag;
 struct __serial_backend_tag;
 struct __std_thread_backend_tag;
+struct __statpart_backend_tag;
 
 #  if defined(_LIBCPP_PSTL_BACKEND_SERIAL)
 using __current_configuration _LIBCPP_NODEBUG = __backend_configuration<__serial_backend_tag, __default_backend_tag>;
@@ -60,6 +61,8 @@ using __current_configuration _LIBCPP_NODEBUG =
 #  elif defined(_LIBCPP_PSTL_BACKEND_LIBDISPATCH)
 using __current_configuration _LIBCPP_NODEBUG =
     __backend_configuration<__libdispatch_backend_tag, __default_backend_tag>;
+#  elif defined(_LIBCPP_PSTL_BACKEND_STATPART)
+using __current_configuration _LIBCPP_NODEBUG = __backend_configuration<__statpart_backend_tag, __default_backend_tag>;
 #  else
 
 // ...New vendors can add parallel backends here...
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
new file mode 100644
index 00000000000000..41e473d663f3ed
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -0,0 +1,1207 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_H
+#define _LIBCPP___PSTL_STATPART_H
+
+#include <__algorithm/find_end.h>
+#include <__algorithm/find_if.h>
+#include <__algorithm/for_each.h>
+#include <__algorithm/is_heap_until.h>
+#include <__algorithm/lower_bound.h>
+#include <__algorithm/merge.h>
+#include <__algorithm/min.h>
+#include <__algorithm/min_element.h>
+#include <__algorithm/minmax_element.h>
+#include <__algorithm/mismatch.h>
+#include <__algorithm/move.h>
+#include <__algorithm/reverse.h>
+#include <__algorithm/search.h>
+#include <__algorithm/search_n.h>
+#include <__algorithm/stable_sort.h>
+#include <__algorithm/swap_ranges.h>
+#include <__algorithm/transform.h>
+#include <__algorithm/upper_bound.h>
+#include <__atomic/atomic.h>
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/move_iterator.h>
+#include <__iterator/next.h>
+#include <__iterator/reverse_iterator.h>
+#include <__memory/allocator.h>
+#include <__memory/construct_at.h>
+#include <__memory/destroy.h>
+#include <__memory/uninitialized_algorithms.h>
+#include <__memory/unique_ptr.h>
+#include <__numeric/reduce.h>
+#include <__numeric/transform_reduce.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/cpu_algos/cpu_traits.h>
+#include <__pstl/cpu_algos/find_if.h>
+#include <__thread/thread.h>
+#include <__type_traits/is_assignable.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__type_traits/is_trivially_copyable.h>
+#include <__utility/convert_to_integral.h>
+#include <__utility/empty.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>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+namespace __statpart {
+
+// The backbone for the backend: applies the function to each of the indices [0, __chunk_count] in parallel.
+// The actual number of parallel workers and the order of application is unspecified.
+_LIBCPP_EXPORTED_FROM_ABI void
+__apply(size_t __chunk_count, void* __context, void (*__func)(void* __context, size_t __chunk)) noexcept;
+
+// The maximum number of partitions to be processed per each CPU
+constexpr inline size_t __max_partitions_per_cpu = 8;
+
+// The minimum number of elements to sort serially in a single partition
+constexpr inline size_t __min_sort_partition_size = 256;
+
+enum class __partitioning_result {
+  // returned when the partitioning result is not nullopt
+  __ok,
+  // returned when there is not enough element to produce a single partition or the final number of partitions is less
+  // than 2, i.e. there's no reason to process in parallel
+  __not_enough_elements,
+  // later: returned memory couldn't be allocated for the stashed forward iterators
+  __bad_alloc
+};
+
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __iterator_range {
+  _Iterator __first;
+  _Iterator __last;
+};
+
+// Later to support forward iterators via a second implicit template argument.
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
+  _LIBCPP_HIDE_FROM_ABI size_t __partitions_count() const { return __partitions_count_; }
+
+  _LIBCPP_HIDE_FROM_ABI __iterator_range<_Iterator> __partition(size_t __n) const {
+    _Iterator __first = __base_ + __n * __partition_size_ + (__n < __remainder_ ? __n : __remainder_);
+    _Iterator __last  = __first + __partition_size_ + (__n < __remainder_ ? 1 : 0);
+    return __iterator_range<_Iterator>{__first, __last};
+  }
+
+  _LIBCPP_HIDE_FROM_ABI _Iterator __end() const { return __base_ + __count_; }
+
+private:
+  _Iterator __base_;
+  size_t __count_;
+  size_t __partition_size_;
+  size_t __remainder_;
+  size_t __partitions_count_;
+
+  template <class _Iter>
+  friend optional<__iterator_partitions<_Iter>>
+  __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t) noexcept;
+};
+
+template <class _ForwardIterator>
+_LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>>
+__partition(_ForwardIterator __first,
+            _ForwardIterator __last,
+            __partitioning_result& __result,
+            size_t __min_partition_size = 1,
+            size_t __prefix_to_skip     = 0,
+            size_t __suffix_to_skip     = 0) noexcept {
+  // forward iteratos to be supported later
+  static_assert(__has_random_access_iterator_category_or_concept<_ForwardIterator>::value);
+  // TODO: assert( __min_partition_size > 0 )?
+
+  size_t __count = static_cast<size_t>(std::distance(__first, __last));
+  if (__count < __prefix_to_skip + __suffix_to_skip) {
+    __result = __partitioning_result::__not_enough_elements;
+    return {};
+  }
+
+  size_t __effective_count = __count - __prefix_to_skip - __suffix_to_skip;
+  size_t __workers_count   = thread::hardware_concurrency();
+  size_t __max_partitions  = __workers_count * __max_partitions_per_cpu;
+  size_t __partition_count = std::min(__max_partitions, __effective_count / __min_partition_size);
+
+  if (__partition_count < 2) {
+    // TODO: verify that's what we want
+    __result = __partitioning_result::__not_enough_elements;
+    return {}; // not enough input data to process in parallel => no reason to build partitions
+  }
+
+  __iterator_partitions<_ForwardIterator> __p;
+  __p.__base_             = __first + __prefix_to_skip;
+  __p.__count_            = __count;
+  __p.__partition_size_   = __count / __partition_count;
+  __p.__remainder_        = __count % __partition_count;
+  __p.__partitions_count_ = __partition_count;
+  return __p;
+}
+
+// for_each with explicit partitioning
+template <class _Iterator, class _Functor>
+_LIBCPP_HIDE_FROM_ABI void __for_each_partition(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
+  struct __ctx_t {
+    const __iterator_partitions<_Iterator>& __partitions_;
+    _Functor& __func_;
+  } __ctx{__partitions, __func};
+  __statpart::__apply(__partitions.__partitions_count(), &__ctx, [](void* __context, size_t __partition) {
+    __ctx_t& __ctx = *static_cast<__ctx_t*>(__context);
+    auto __range   = __ctx.__partitions_.__partition(__partition);
+    __ctx.__func_(__range.__first, __range.__last);
+  });
+}
+
+// Calls __func(index) for every index in [0, __count) in parallel
+template <class _Functor>
+_LIBCPP_HIDE_FROM_ABI void __for_each_index(size_t __count, _Functor __func) {
+  __statpart::__apply(__count, &__func, [](void* __context, size_t __index) {
+    (*static_cast<_Functor*>(__context))(__index);
+  });
+}
+
+// TODO: ...
+template <class _Iterator, class _Functor>
+_LIBCPP_HIDE_FROM_ABI void
+__for_each_partition_index(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
+  __statpart::__for_each_index(__partitions.__partitions_count(), std::move(__func));
+}
+
+// for_each with default implicit partitioning
+template <class _Iterator, class _Functor>
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each(_Iterator __first, _Iterator __last, _Functor __func) {
+  if (__first == __last)
+    return __empty{};
+  __partitioning_result __partition_result;
+  auto __partitions = __statpart::__partition(__first, __last, __partition_result);
+  if (__partitions) {
+    __statpart::__for_each_partition(*__partitions, std::move(__func));
+    return __empty{};
+  } else if (__partition_result == __partitioning_result::__bad_alloc) {
+    return nullopt;
+  } else {
+    __func(__first, __last);
+    return __empty{};
+  }
+}
+
+// Applies the 3-legged function to sub-ranges of the input ranges in parallel:
+//   f(sub_range1_first, sub_range1_last, sub_range2_first)
+template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BrickFunction>
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each_iter_pair(
+    _RandomAccessIterator1 __first1,
+    _RandomAccessIterator1 __last1,
+    _RandomAccessIterator2 __first2,
+    _BrickFunction __f) {
+  return __for_each(
+      __first1,
+      __last1,
+      [__first1, __first2, __f = std::move(__f)](
+          _RandomAccessIterator1 __brick_first1, _RandomAccessIterator1 __brick_last1) {
+        _RandomAccessIterator2 __brick_first2 = __first2 + (__brick_first1 - __first1);
+        __f(__brick_first1, __brick_last1, __brick_first2);
+      });
+}
+
+template <class _Index, class _Brick, class _Compare>
+_LIBCPP_HIDE_FROM_ABI optional<_Index>
+__find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) {
+  typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType;
+  const _DifferenceType __n      = __last - __first;
+  _DifferenceType __initial_dist = __b_first ? __n : -1;
+  std::atomic<_DifferenceType> __extremum(__initial_dist);
+  // TODO: find out what is better here: parallel_for or parallel_reduce
+  auto __res = __statpart::__for_each(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
+    // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of
+    // why using a shared variable scales fairly well in this situation.
+    if (__comp(__i - __first, __extremum)) {
+      _Index __result = __f(__i, __j);
+      // If not '__last' returned then we found what we want so put this to extremum
+      if (__result != __j) {
+        const _DifferenceType __k = __result - __first;
+        for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) {
+          __extremum.compare_exchange_weak(__old, __k);
+        }
+      }
+    }
+  });
+  if (!__res)
+    return nullopt;
+  return __extremum.load() != __initial_dist ? __first + __extremum.load() : __last;
+}
+
+template <class _RandomAccessIterator, class _Transform, class _Value, class _Combiner, class _Reduction>
+_LIBCPP_HIDE_FROM_ABI optional<_Value> __transform_reduce(
+    _RandomAccessIterator __first,
+    _RandomAccessIterator __last,
+    _Transform __transform,
+    _Value __init,
+    _Combiner __combiner,
+    _Reduction __reduction) {
+  if (__first == __last)
+    return __init;
+
+  // Split into partitions with at least 3 elements in each
+  __partitioning_result __partitioning_result;
+  auto __partitions = __statpart::__partition(__first, __last, __partitioning_result, 3);
+  if (!__partitions) {
+    if (__partitioning_result == __partitioning_result::__bad_alloc) {
+      // Failed to allocate memory for the partitions, propagate the error up.
+      return nullopt;
+    } else {
+      // Not enough elements to run in parallel, switch to serial implementation.
+      return __reduction(std::move(__first), std::move(__last), std::move(__init));
+    }
+  }
+
+  auto __destroy = [__count = __partitions->__partitions_count()](_Value* __ptr) {
+    std::destroy_n(__ptr, __count);
+    std::allocator<_Value>().deallocate(__ptr, __count);
+  };
+
+  // TODO: use __uninitialized_buffer
+  // TODO: allocate one element per worker instead of one element per chunk
+  unique_ptr<_Value[], decltype(__destroy)> __values(
+      std::allocator<_Value>().allocate(__partitions->__partitions_count()), __destroy);
+
+  // __dispatch_apply is noexcept
+  __statpart::__for_each_partition_index(*__partitions, [&](size_t __index) {
+    auto __range = __partitions->__partition(__index);
+    std::__construct_at(
+        __values.get() + __index,
+        __reduction(__range.__first + 2,
+                    __range.__last,
+                    __combiner(__transform(__range.__first), __transform(__range.__first + 1))));
+  });
+
+  return std::reduce(
+      std::make_move_iterator(__values.get()),
+      std::make_move_iterator(__values.get() + __partitions->__partitions_count()),
+      std::move(__init),
+      __combiner);
+}
+
+template <class _RandomAccessIterator1,
+          class _RandomAccessIterator2,
+          class _RandomAccessIterator3,
+          class _Compare,
+          class _LeafMerge>
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
+__merge(_RandomAccessIterator1 __first1,
+        _RandomAccessIterator1 __last1,
+        _RandomAccessIterator2 __first2,
+        _RandomAccessIterator2 __last2,
+        _RandomAccessIterator3 __result,
+        _Compare __comp,
+        _LeafMerge __leaf_merge) noexcept {
+  // Run the merge such that the longest range is partitioned.
+  // __merge_sub_ranges swaps the ranges implicitly in case the second range was the longest one.
+  auto __run =
+      [__result](auto __long_first,
+                 auto __long_last,
+                 auto __short_first,
+                 auto __short_last,
+                 auto __find_cutpoint,
+                 auto __merge_sub_ranges) -> optional<__empty> {
+    // Partition the longest input range evenly.
+    __partitioning_result __partitioning_result;
+    auto __partitions = __statpart::__partition(__long_first, __long_last, __partitioning_result);
+    if (!__partitions) {
+      if (__partitioning_result == __partitioning_result::__bad_alloc)
+        return nullopt;
+      // Not enough elements to run in parallel, merge everything serially.
+      __merge_sub_ranges(__long_first, __long_last, __short_first, __short_last, __result);
+      return __empty{};
+    }
+
+    // Process the partitions of the longest range in parallel.
+    __statpart::__for_each_partition_index(*__partitions, [&](size_t __index) {
+      // Get the sub-range inside the longer input range.
+      auto __range = __partitions->__partition(__index);
+
+      // Find the matching sub-range of the shorter input range: it will hold the elements that come after the last
+      // element of the previous long partition and up to the last element of this partition.
+      // This generally runs two binary searches in the smaller input range, edge partitions use existing bounds.
+      auto __short_begin =
+          __index == 0 ? __short_first : __find_cutpoint(__short_first, __short_last, __range.__first[-1]);
+      auto __short_end =
+          __index == __partitions->__partitions_count() - 1
+              ? __short_last
+              : __find_cutpoint(__short_first, __short_last, __range.__last[-1]);
+
+      // Derive the position in the output range and merge the sub-ranges.
+      auto __result_first = __result + (__range.__first - __long_first) + (__short_begin - __short_first);
+      __merge_sub_ranges(__range.__first, __range.__last, __short_begin, __short_end, __result_first);
+    });
+    return __empty{};
+  };
+
+  if (__last1 - __first1 > __last2 - __first2) {
+    // Preserve the order of the input ranges, partition the first range.
+    // Equal elements of the second range go after the cut => use lower_bound when cutting.
+    return __run(
+        __first1,
+        __last1,
+        __first2,
+        __last2,
+        [&](auto __first, auto __last, const auto& __value) {
+          return std::lower_bound(__first, __last, __value, __comp);
+        },
+        [&](auto __long_first, auto __long_last, auto __short_first, auto __short_last, auto __result_first) {
+          __leaf_merge(__long_first, __long_last, __short_first, __short_last, __result_first, __comp);
+        });
+  } else {
+    // Swap the order of the input ranges, partition the second range.
+    // Equal elements of the first range go before the cut => use upper_bound when cutting.
+    return __run(
+        __first2,
+        __last2,
+        __first1,
+        __last1,
+        [&](auto __first, auto __last, const auto& __value) {
+          return std::upper_bound(__first, __last, __value, __comp);
+        },
+        [&](auto __long_first, auto __long_last, auto __short_first, auto __short_last, auto __result_first) {
+          __leaf_merge(__short_first, __short_last, __long_first, __long_last, __result_first, __comp);
+        });
+  }
+}
+
+template <class _RandomAccessIterator, class _Comp, class _LeafSort>
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
+__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
+  const auto __size = __last - __first;
+
+  __partitioning_result __partitioning_result;
+  auto __partitions = __statpart::__partition(__first, __last, __partitioning_result, __min_sort_partition_size);
+  if (!__partitions) {
+    if (__partitioning_result == __partitioning_result::__bad_alloc)
+      return nullopt;
+    // Not enough elements to run in parallel, sort everything serially.
+    __leaf_sort(__first, __last, __comp);
+    return __empty{};
+  }
+
+  using _Value = __iterator_value_type<_RandomAccessIterator>;
+
+  auto __destroy = [__size](_Value* __ptr) {
+    std::destroy_n(__ptr, __size);
+    std::allocator<_Value>().deallocate(__ptr, __size);
+  };
+
+  // TODO: use __uninitialized_buffer
+  unique_ptr<_Value[], decltype(__destroy)> __values(std::allocator<_Value>().allocate(__size), __destroy);
+
+  // Initialize all elements to a moved-from state
+  // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928
+  std::__construct_at(__values.get(), std::move(*__first));
+  for (__iterator_difference_type<_RandomAccessIterator> __i = 1; __i != __size; ++__i) {
+    std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1]));
+  }
+  *__first = std::move(__values.get()[__size - 1]);
+
+  __statpart::__for_each_partition(
+      *__partitions, [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) {
+        __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp);
+      });
+
+  // A chunk span is a run of __chunk_span_size consecutive partitions, the last chunk can be shorter in case of odd
+  // number of chunk spans. Each pass merges the chunk spans pairwise, so the chunk span size doubles and the chunk
+  // count is halved (rounded up).
+  const size_t __partition_count = __partitions->__partitions_count();
+  size_t __chunk_span_size       = 1;
+  size_t __chunk_spans           = __partition_count;
+
+  // Offsets of the beginning and the end of the chunk from __first
+  auto __chunk_begin = [&](size_t __chunk) {
+    return __partitions->__partition(__chunk * __chunk_span_size).__first - __first;
+  };
+  auto __chunk_end = [&](size_t __chunk) {
+    return __partitions->__partition(std::min((__chunk + 1) * __chunk_span_size, __partition_count) - 1).__last -
+           __first;
+  };
+
+  bool __objects_are_in_buffer = false;
+  do {
+    size_t __chunk_spans_pairs = (__chunk_spans + 1) / 2;
+    auto __merge_chunks        = [&](auto __from_first, auto __to_first) {
+      __statpart::__for_each_index(__chunk_spans_pairs, [&](size_t __span_pair_index) {
+        size_t __left_chunk  = 2 * __span_pair_index;
+        size_t __right_chunk = __left_chunk + 1;
+        auto __pair_first    = __chunk_begin(__left_chunk);
+        if (__right_chunk == __chunk_spans) {
+          // The odd chunk has no counterpart to merge with => carry it over to the other buffer as-is.
+          std::move(__from_first + __pair_first, __from_first + __chunk_end(__left_chunk), __to_first + __pair_first);
+        } else {
+          // Merge the two chunk spans into the other buffer
+          auto __pair_mid  = __chunk_begin(__right_chunk);
+          auto __pair_last = __chunk_end(__right_chunk);
+          std::merge(std::make_move_iterator(__from_first + __pair_first),
+                     std::make_move_iterator(__from_first + __pair_mid),
+                     std::make_move_iterator(__from_first + __pair_mid),
+                     std::make_move_iterator(__from_first + __pair_last),
+                     __to_first + __pair_first,
+                     __comp);
+        }
+      });
+    };
+
+    if (__objects_are_in_buffer)
+      __merge_chunks(__values.get(), __first);
+    else
+      __merge_chunks(__first, __values.get());
+    __objects_are_in_buffer = !__objects_are_in_buffer;
+
+    __chunk_span_size *= 2;
+    __chunk_spans = __chunk_spans_pairs;
+  } while (__chunk_spans > 1);
+
+  if (__objects_are_in_buffer) {
+    std::move(__values.get(), __values.get() + __size, __first);
+  }
+
+  return __empty{};
+}
+
+} // namespace __statpart
+
+template <class _ExecutionPolicy>
+struct __find_end<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _BinaryPredicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
+      _DifferenceType __size2 = __last2 - __first2; // The length of the needle to search for.
+      if (__size2 == 0) {
+        return __last1; // If the needle length is zero, the last iterator is returned.
+      }
+      _DifferenceType __size1 = __last1 - __first1;
+      if (__size1 < __size2) {
+        return __last1; // The range is too small to contain the requested number of consecutive elements.
+      }
+      // Calculate the length of the tail where a potential match cannot start by definition.
+      _DifferenceType __crop = __size2 - 1;
+      // We're only interested in the range where a potential match can start: [first, last - crop)
+      _ForwardIterator1 __last1_cropped = __last1 - __crop;
+      // Run a parallel chunked find_if, covering the range where a potential match can start.
+      auto __res = __statpart::__find(
+          __first1,
+          __last1_cropped,
+          [__first2, __last2, __crop, &__pred](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+            // Uncrop the range to allow std::find_end to find a full match, which can go beyond __brick_last.
+            _ForwardIterator1 __brick_last_uncropped = __brick_last + __crop;
+            // Run a serial std::find_end inside each of the chunks in parallel.
+            _ForwardIterator1 __ret = std::find_end(__brick_first, __brick_last_uncropped, __first2, __last2, __pred);
+            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
+            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __parallel_find().
+            return __ret == __brick_last_uncropped ? __brick_last : __ret;
+          },
+          greater<>{}, // `greater` here means the highest index among the matches
+          false        // `false` here means we want the last match, not the first
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (*__res == __last1_cropped) {
+        return __last1; // No match was found in the range.
+      }
+      return *__res; // Return the successful match.
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::find_end(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __for_each<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Function>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __func) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__for_each(
+          std::move(__first), std::move(__last), [&](auto __partition_first, auto __partition_last) {
+            std::for_each(__partition_first, __partition_last, __func);
+          });
+    } else {
+      std::for_each(std::move(__first), std::move(__last), std::move(__func));
+      return __empty{};
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __find_if<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__find(
+          std::move(__first),
+          std::move(__last),
+          [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            return std::find_if(__brick_first, __brick_last, __pred);
+          },
+          less<>{},
+          true);
+    } else {
+      return std::find_if(std::move(__first), std::move(__last), std::move(__pred));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __is_heap_until<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _RandomAccessIterator, class _Comp>
+  _LIBCPP_HIDE_FROM_ABI optional<_RandomAccessIterator>
+  operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
+      if (__last - __first < 2)
+        return __last; // Any sequence with less than 2 elements is a heap
+      // Run a parallel find in chunks over [first+1, last) to validate every element except the root.
+      return __statpart::__find(
+          __first + 1,
+          __last,
+          [__first, &__comp](_RandomAccessIterator __child_first, _RandomAccessIterator __child_last) {
+            // This algorithm assumes that __find() will never pass an empty brick,
+            // i.e. that __child_first != __child_last.
+            using _DifferenceType = typename std::iterator_traits<_RandomAccessIterator>::difference_type;
+
+            // Derive the indices of the children and the iterators of their parents
+            _DifferenceType __child_first_idx   = __child_first - __first;
+            _DifferenceType __child_last_idx    = __child_last - __first;
+            _RandomAccessIterator __parent      = __first + (__child_first_idx - 1) / 2;
+            _RandomAccessIterator __parent_last = __first + (__child_last_idx - 1) / 2;
+
+            // If we're starting from a right child => process this element separately in a prologue
+            if (__child_first_idx % 2 == 0) {
+              if (__comp(*__parent, *__child_first)) // Check the right child
+                return __child_first;
+              ++__parent;
+              ++__child_first;
+            }
+
+            // Iterate over the parents and check their left and right children
+            for (; __parent != __parent_last; ++__parent) {
+              if (__comp(*__parent, *__child_first)) // Check the left child
+                return __child_first;
+              ++__child_first;
+
+              if (__comp(*__parent, *__child_first)) // Check the right child
+                return __child_first;
+              ++__child_first;
+            }
+
+            // If we're ending with a right child => __parent_last also includes the left child.
+            // Process this accessible element separately in an epilogue.
+            if (__child_last_idx % 2 == 0) {
+              if (__comp(*__parent, *__child_first)) // Check the left child
+                return __child_first;
+            }
+
+            return __child_last; // No violations found in this brick
+          },
+          less<>{}, // `less` here means the lowest index among the matches
+          true      // `true` here means we want the first match, not the last
+      );
+    } else {
+      return std::is_heap_until(std::move(__first), std::move(__last), std::move(__comp));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __merge<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardOutIterator, class _Comp>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> operator()(
+      _Policy&&,
+      _ForwardIterator1 __first1,
+      _ForwardIterator1 __last1,
+      _ForwardIterator2 __first2,
+      _ForwardIterator2 __last2,
+      _ForwardOutIterator __result,
+      _Comp __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      auto __res = __statpart::__merge(
+          __first1,
+          __last1,
+          __first2,
+          __last2,
+          __result,
+          __comp,
+          [](_ForwardIterator1 __brick_first1,
+             _ForwardIterator1 __brick_last1,
+             _ForwardIterator2 __brick_first2,
+             _ForwardIterator2 __brick_last2,
+             _ForwardOutIterator __brick_result,
+             _Comp __g_comp) {
+            std::merge(std::move(__brick_first1),
+                       std::move(__brick_last1),
+                       std::move(__brick_first2),
+                       std::move(__brick_last2),
+                       std::move(__brick_result),
+                       std::move(__g_comp));
+          });
+      if (!__res)
+        return nullopt;
+      return __result + (__last1 - __first1) + (__last2 - __first2);
+    } else {
+      return std::merge(__first1, __last1, __first2, __last2, __result, __comp);
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __min_element<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Compare>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      if (__first == __last) {
+        return __last; // nothing to do
+      }
+
+      _ForwardIterator __init = __first;
+      ++__first;
+      if (__first == __last) {
+        return __init; // the only element is the minimum
+      }
+
+      // A reduction that returns an iterator pointing to the lowest element, left bias in case of a tie
+      auto __iter_reduce = [&__comp](_ForwardIterator __lhs, _ForwardIterator __rhs) {
+        return __comp(*__rhs, *__lhs) ? __rhs : __lhs;
+      };
+
+      // Perform a parallel reduction of iterators [first+1, last) with 'first' as init.
+      return __statpart::__transform_reduce(
+          std::move(__first),
+          std::move(__last),
+          __identity{},      // No transformations
+          std::move(__init), // Use the first iterator as the init element
+          __iter_reduce,     // Reduction of 2 elements
+          [&__iter_reduce, &__comp](auto __brick_first, auto __brick_last, auto __brick_init) {
+            // Reduction of an iterator range + init element: use the serial version to find the minimum among
+            // the iterators and then reduce with the init element.
+            return __iter_reduce(__brick_init, std::min_element(__brick_first, __brick_last, __comp));
+          });
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::min_element(std::move(__first), std::move(__last), std::move(__comp));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __minmax_element<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Compare>
+  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator, _ForwardIterator>>
+  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      using _IterPair = pair<_ForwardIterator, _ForwardIterator>;
+
+      if (__first == __last) {
+        return _IterPair{__last, __last}; // Nothing to do
+      }
+
+      _IterPair __init = {__first, __first};
+      ++__first;
+      if (__first == __last) {
+        return __init; // The only element is both the minimum and the maximum
+      }
+
+      // A reduction that returns a pair of iterators pointing to the minimum and maximum elements.
+      // In a case of a tie the minimum iterators are biased left and the maximum iterators are biased right.
+      auto __iter_reduce = [&__comp](_IterPair __lhs, _IterPair __rhs) {
+        return _IterPair{__comp(*__rhs.first, *__lhs.first) ? __rhs.first : __lhs.first,
+                         __comp(*__rhs.second, *__lhs.second) ? __lhs.second : __rhs.second};
+      };
+
+      // Perform a parallel reduction of iterators [first+1, last) with {first, first} as init.
+      return __statpart::__transform_reduce(
+          std::move(__first),
+          std::move(__last),
+          [](auto __it) { return _IterPair{__it, __it}; }, // Transform an iterator into an iterator pair
+          std::move(__init),                               // Use the pair of first iterators as the init element
+          __iter_reduce,                                   // Reduction of 2 minmax pairs
+          [&__iter_reduce, &__comp](auto __brick_first, auto __brick_last, auto __brick_init) {
+            // Reduction of an iterator range + init element: use the serial version to find the minmax among
+            // the iterators and then reduce it with the init element.
+            return __iter_reduce(__brick_init, std::minmax_element(__brick_first, __brick_last, __comp));
+          });
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::minmax_element(std::move(__first), std::move(__last), std::move(__comp));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __mismatch<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator1, _ForwardIterator2>>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      // Look for a mismatch only in the prefix of the two ranges.
+      auto __n = std::min(__last1 - __first1, __last2 - __first2);
+      // Find a position in the first range where the predicate is false against the corresponding position in the
+      // second range.
+      auto __res = __statpart::__find(
+          __first1,
+          __first1 + __n,
+          [&__pred, __first1, __first2](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1) {
+            // Run the sequential mismatch algorithm on these ranges:
+            //   [__brick_first1, __brick_last1) and
+            //   [__first2 + (__brick_first1 - __first1), __first2 + (__brick_last1 - __first1))
+            auto __brick_first2 = __first2 + (__brick_first1 - __first1);
+            return std::mismatch(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2), __pred)
+                .first;
+          },
+          less<>{}, // `less` here means the lowest index among the mismatches
+          true      // `true` here means we want the first mismatch, not the last
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      auto __idx = *__res - __first1;
+      return pair<_ForwardIterator1, _ForwardIterator2>{std::move(*__res), __first2 + __idx};
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      // Unsequenced execution is also implicitly covered by the sequential implementation.
+      return std::mismatch(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __reverse<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _BidirectionalIterator>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&&, _BidirectionalIterator __first, _BidirectionalIterator __last) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_BidirectionalIterator>::value) {
+      // Perform a chunked for_each on the first half of the range.
+      // Odd-sized ranges will leave the middle element untouched, which is correct for this algorithm:
+      // its reversed position is the same.
+      auto __n = (__last - __first) / 2;
+      return __statpart::__for_each(
+          __first, __first + __n, [__first, __last](_BidirectionalIterator __i, _BidirectionalIterator __j) {
+            // Derive the last position of the mirrored range by counting from the end.
+            _BidirectionalIterator __mirror_last = __last - (__i - __first);
+            // Swap the elements in the range of the first half with their mirrored counterparts in the second half.
+            std::swap_ranges(std::move(__i),
+                             std::move(__j),
+                             std::reverse_iterator<_BidirectionalIterator>(std::move(__mirror_last)));
+          });
+    } else {
+      // Non-random access iterators currently cannot be processed in parallel, use the sequential implementation.
+      std::reverse(std::move(__first), std::move(__last));
+      return __empty{};
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __search<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _BinaryPredicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
+      _DifferenceType __size2 = __last2 - __first2; // The length of the needle to search for.
+      if (__size2 == 0) {
+        return __first1; // If the needle length is zero, the first iterator is returned.
+      }
+      _DifferenceType __size1 = __last1 - __first1;
+      if (__size1 < __size2) {
+        return __last1; // The range is too small to contain the requested number of consecutive elements.
+      }
+      // Calculate the length of the tail where a potential match cannot start by definition.
+      _DifferenceType __crop = __size2 - 1;
+      // We're only interested in the range where a potential match can start: [first, last - crop)
+      _ForwardIterator1 __last1_cropped = __last1 - __crop;
+      // Run a parallel chunked find_if, covering the range where a potential match can start.
+      auto __res = __statpart::__find(
+          __first1,
+          __last1_cropped,
+          [__first2, __last2, __crop, &__pred](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+            // Uncrop the range to allow std::search to find a full match, which can go beyond __brick_last.
+            _ForwardIterator1 __brick_last_uncropped = __brick_last + __crop;
+            // Run a serial std::search inside each of the chunks in parallel.
+            _ForwardIterator1 __ret = std::search(__brick_first, __brick_last_uncropped, __first2, __last2, __pred);
+            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
+            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __find().
+            return __ret == __brick_last_uncropped ? __brick_last : __ret;
+          },
+          less<>{}, // `less` here means the lowest index among the matches
+          true      // `true` here means we want the first match, not the last
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (*__res == __last1_cropped) {
+        return __last1; // No match was found in the range.
+      }
+      return *__res; // Return the successful match.
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::search(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __search_n<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Size, class _Tp, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+  operator()(_Policy&&,
+             _ForwardIterator __first,
+             _ForwardIterator __last,
+             _Size __count,
+             const _Tp& __value,
+             _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      typedef typename std::iterator_traits<_ForwardIterator>::difference_type _DifferenceType;
+      _DifferenceType __integral_count = std::__convert_to_integral(__count);
+      if (__integral_count <= 0) {
+        return __first; // If the count is non-positive, the first iterator is returned.
+      }
+      _DifferenceType __size = __last - __first;
+      if (__size < __integral_count) {
+        return __last; // The range is too small to contain the requested number of consecutive elements.
+      }
+      // Calculate the length of the tail where a potential match cannot start by definition.
+      _DifferenceType __crop = __integral_count - 1;
+      // We're only interested in the range where a potential match can start: [first, last - crop)
+      _ForwardIterator __last2 = __last - __crop;
+      // Run a parallel chunked find_if, covering the range where a potential match can start.
+      auto __res = __statpart::__find(
+          __first,
+          __last2,
+          [__integral_count, __crop, &__value, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            // Uncrop the range to allow std::search_n to find a full match, which can go beyond __brick_last.
+            _ForwardIterator __brick_last_uncropped = __brick_last + __crop;
+            // Run a serial std::search_n inside each of the chunks in parallel.
+            _ForwardIterator __ret =
+                std::search_n(__brick_first, __brick_last_uncropped, __integral_count, __value, __pred);
+            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
+            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __find().
+            return __ret == __brick_last_uncropped ? __brick_last : __ret;
+          },
+          less<>{}, // `less` here means the lowest index among the matches
+          true      // `true` here means we want the first match, not the last
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (*__res == __last2) {
+        return __last; // No match was found in the range.
+      }
+      return *__res; // Return the successful match.
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::search_n(std::move(__first), std::move(__last), __count, __value, std::move(__pred));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __stable_sort<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _RandomAccessIterator, class _Comp>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
+      return __statpart::__stable_sort(
+          __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) {
+            std::stable_sort(__g_first, __g_last, __g_comp);
+          });
+    } else {
+      std::stable_sort(__first, __last, __comp);
+      return __empty{};
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __swap_ranges<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+      _Policy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      auto __res = __statpart::__for_each_iter_pair(
+          __first1,
+          __last1,
+          __first2,
+          [](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1, _ForwardIterator2 __brick_first2) {
+            std::swap_ranges(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2));
+          });
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      return __first2 + (__last1 - __first1);
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::swap_ranges(std::move(__first1), std::move(__last1), std::move(__first2));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __transform<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _UnaryOperation>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> operator()(
+      _Policy&&, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result, _UnaryOperation __op)
+      const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      __statpart::__for_each(
+          __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            return std::transform(__brick_first, __brick_last, __result + (__brick_first - __first), __op);
+          });
+      return __result + (__last - __first);
+    } else {
+      return std::transform(__first, __last, __result, __op);
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __transform_binary<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy,
+            class _ForwardIterator1,
+            class _ForwardIterator2,
+            class _ForwardOutIterator,
+            class _BinaryOperation>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardOutIterator __result,
+             _BinaryOperation __op) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      auto __res = __statpart::__for_each(
+          __first1,
+          __last1,
+          [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+            return std::transform(
+                __brick_first,
+                __brick_last,
+                __first2 + (__brick_first - __first1),
+                __result + (__brick_first - __first1),
+                __op);
+          });
+      if (!__res)
+        return nullopt;
+      return __result + (__last1 - __first1);
+    } else {
+      return std::transform(__first1, __last1, __first2, __result, __op);
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __transform_reduce<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
+  _LIBCPP_HIDE_FROM_ABI optional<_Tp>
+  operator()(_Policy&&,
+             _ForwardIterator __first,
+             _ForwardIterator __last,
+             _Tp __init,
+             _BinaryOperation __reduce,
+             _UnaryOperation __transform) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__transform_reduce(
+          std::move(__first),
+          std::move(__last),
+          [__transform](_ForwardIterator __iter) { return __transform(*__iter); },
+          std::move(__init),
+          __reduce,
+          [__transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) {
+            return std::transform_reduce(
+                std::move(__brick_first),
+                std::move(__brick_last),
+                std::move(__brick_init),
+                std::move(__reduce),
+                std::move(__transform));
+          });
+    } else {
+      return std::transform_reduce(
+          std::move(__first), std::move(__last), std::move(__init), std::move(__reduce), std::move(__transform));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __transform_reduce_binary<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy,
+            class _ForwardIterator1,
+            class _ForwardIterator2,
+            class _Tp,
+            class _BinaryOperation1,
+            class _BinaryOperation2>
+  _LIBCPP_HIDE_FROM_ABI optional<_Tp> operator()(
+      _Policy&&,
+      _ForwardIterator1 __first1,
+      _ForwardIterator1 __last1,
+      _ForwardIterator2 __first2,
+      _Tp __init,
+      _BinaryOperation1 __reduce,
+      _BinaryOperation2 __transform) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      return __statpart::__transform_reduce(
+          __first1,
+          std::move(__last1),
+          [__first1, __first2, __transform](_ForwardIterator1 __iter) {
+            return __transform(*__iter, *(__first2 + (__iter - __first1)));
+          },
+          std::move(__init),
+          std::move(__reduce),
+          [__first1, __first2, __reduce, __transform](
+              _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) {
+            return std::transform_reduce(
+                __brick_first,
+                std::move(__brick_last),
+                __first2 + (__brick_first - __first1),
+                std::move(__brick_init),
+                std::move(__reduce),
+                std::move(__transform));
+          });
+    } else {
+      return std::transform_reduce(
+          std::move(__first1),
+          std::move(__last1),
+          std::move(__first2),
+          std::move(__init),
+          std::move(__reduce),
+          std::move(__transform));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __uninitialized_copy<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+      _Policy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      auto __res = __statpart::__for_each_iter_pair(
+          __first,
+          __last,
+          __result,
+          [](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _ForwardIterator2 __brick_result) {
+            std::uninitialized_copy(std::move(__brick_first), std::move(__brick_last), std::move(__brick_result));
+          });
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      return __result + (__last - __first);
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::uninitialized_copy(std::move(__first), std::move(__last), std::move(__result));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __uninitialized_move<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+      _Policy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      auto __res = __statpart::__for_each_iter_pair(
+          __first,
+          __last,
+          __result,
+          [](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _ForwardIterator2 __brick_result) {
+            std::uninitialized_move(std::move(__brick_first), std::move(__brick_last), std::move(__brick_result));
+          });
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      return __result + (__last - __first);
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::uninitialized_move(std::move(__first), std::move(__last), std::move(__result));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 28ae9ee8de46a3..87a1ef5ed8292f 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2416,6 +2416,9 @@ module std {
         header "__pstl/backends/serial.h"
         export std_core.utility_core.empty
       }
+      module statpart {
+        header "__pstl/backends/statpart.h"
+      }
       module std_thread {
         header "__pstl/backends/std_thread.h"
         export std.pstl.cpu_algos
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index e029f9f29d5ea2..d49dd69e66f95b 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -310,6 +310,12 @@ if (LIBCXX_PSTL_BACKEND STREQUAL "libdispatch")
     )
 endif()
 
+if (LIBCXX_PSTL_BACKEND STREQUAL "statpart")
+  list(APPEND LIBCXX_EXPERIMENTAL_SOURCES
+    pstl/statpart.cpp
+    )
+endif()
+
 if (LIBCXX_ENABLE_LOCALIZATION AND LIBCXX_ENABLE_FILESYSTEM AND LIBCXX_ENABLE_TIME_ZONE_DATABASE)
   list(APPEND LIBCXX_EXPERIMENTAL_SOURCES
     experimental/include/tzdb/time_zone_private.h
diff --git a/libcxx/src/pstl/statpart.cpp b/libcxx/src/pstl/statpart.cpp
new file mode 100644
index 00000000000000..903ebbf000128e
--- /dev/null
+++ b/libcxx/src/pstl/statpart.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <__config>
+#include <__pstl/backends/statpart.h>
+#include <dispatch/dispatch.h>
+
+// Hardcoded to use libdispatch for now.
+// CMake switches to be introduced later.
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl::__statpart {
+
+void __apply(size_t chunk_count, void* context, void (*func)(void* context, size_t chunk)) noexcept {
+  ::dispatch_apply_f(chunk_count, DISPATCH_APPLY_AUTO, context, func);
+}
+
+} // namespace __pstl::__statpart
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index e0a92259202c48..5db6a12c1dd278 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -1,4 +1,5 @@
 algorithm cctype
+algorithm cerrno
 algorithm climits
 algorithm compare
 algorithm cstdint
@@ -528,6 +529,7 @@ map tuple
 map version
 mdspan version
 memory cctype
+memory cerrno
 memory climits
 memory compare
 memory cstdint
@@ -564,6 +566,7 @@ mutex version
 new version
 numbers version
 numeric cctype
+numeric cerrno
 numeric climits
 numeric compare
 numeric cstdint
@@ -640,6 +643,7 @@ queue tuple
 queue vector
 queue version
 random cctype
+random cerrno
 random climits
 random cmath
 random compare
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 3c5e9439f100cc..1e40f6abcadd6a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -1,4 +1,5 @@
 algorithm cctype
+algorithm cerrno
 algorithm climits
 algorithm compare
 algorithm cstdint
@@ -594,6 +595,7 @@ map tuple
 map version
 mdspan version
 memory cctype
+memory cerrno
 memory climits
 memory compare
 memory cstdint
@@ -630,6 +632,7 @@ mutex version
 new version
 numbers version
 numeric cctype
+numeric cerrno
 numeric climits
 numeric compare
 numeric cstdint
@@ -716,6 +719,7 @@ queue tuple
 queue vector
 queue version
 random cctype
+random cerrno
 random climits
 random cmath
 random compare
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 8c03f1c3c2251e..f3c6c4c9796553 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -1,4 +1,5 @@
 algorithm cctype
+algorithm cerrno
 algorithm climits
 algorithm compare
 algorithm cstdint
@@ -628,6 +629,7 @@ mdspan span
 mdspan stdexcept
 mdspan version
 memory cctype
+memory cerrno
 memory climits
 memory compare
 memory cstdint
@@ -664,6 +666,7 @@ mutex version
 new version
 numbers version
 numeric cctype
+numeric cerrno
 numeric climits
 numeric compare
 numeric cstdint
@@ -758,6 +761,7 @@ queue tuple
 queue vector
 queue version
 random cctype
+random cerrno
 random climits
 random cmath
 random compare
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 800d65aed4704c..269a32ca1befe0 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -1,4 +1,5 @@
 algorithm cctype
+algorithm cerrno
 algorithm climits
 algorithm compare
 algorithm cstdint
@@ -620,6 +621,7 @@ mdspan span
 mdspan stdexcept
 mdspan version
 memory cctype
+memory cerrno
 memory climits
 memory compare
 memory cstdint
@@ -656,6 +658,7 @@ mutex version
 new version
 numbers version
 numeric cctype
+numeric cerrno
 numeric climits
 numeric compare
 numeric cstdint
@@ -743,6 +746,7 @@ queue tuple
 queue vector
 queue version
 random cctype
+random cerrno
 random climits
 random compare
 random cstdint

>From eb04b45b236442822aae0a80373023ea13274fd5 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 9 Oct 2026 16:32:03 +0100
Subject: [PATCH 02/24] Update includes for C++29 as well

---
 libcxx/test/libcxx/transitive_includes/cxx29.csv | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libcxx/test/libcxx/transitive_includes/cxx29.csv b/libcxx/test/libcxx/transitive_includes/cxx29.csv
index 800d65aed4704c..269a32ca1befe0 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx29.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx29.csv
@@ -1,4 +1,5 @@
 algorithm cctype
+algorithm cerrno
 algorithm climits
 algorithm compare
 algorithm cstdint
@@ -620,6 +621,7 @@ mdspan span
 mdspan stdexcept
 mdspan version
 memory cctype
+memory cerrno
 memory climits
 memory compare
 memory cstdint
@@ -656,6 +658,7 @@ mutex version
 new version
 numbers version
 numeric cctype
+numeric cerrno
 numeric climits
 numeric compare
 numeric cstdint
@@ -743,6 +746,7 @@ queue tuple
 queue vector
 queue version
 random cctype
+random cerrno
 random climits
 random compare
 random cstdint

>From 738efff6945043e3b64ecef455f549887cbe8d64 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 9 Oct 2026 17:47:27 +0100
Subject: [PATCH 03/24] Use the statpart backend on Apple platforms to run it
 against CI

---
 libcxx/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 5478c38afa781d..55b7a5fc709b37 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -321,7 +321,7 @@ option(LIBCXX_HAS_EXTERNAL_THREAD_API
 option(LIBCXX_HAS_C11_THREAD_API "Ignore auto-detection and force use of C11 thread API" OFF)
 
 if (APPLE)
-  set(LIBCXX_PSTL_BACKEND_DEFAULT_VALUE "libdispatch")
+  set(LIBCXX_PSTL_BACKEND_DEFAULT_VALUE "statpart")
 elseif(LIBCXX_ENABLE_THREADS)
   set(LIBCXX_PSTL_BACKEND_DEFAULT_VALUE "std_thread")
 else()

>From 3a57228a1c21d6c2985fc5a25103a9b09a80ee09 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 12 Oct 2026 13:27:31 +0100
Subject: [PATCH 04/24] Polished __partition() a bit, added some basic unit
 tests

---
 libcxx/include/__pstl/backends/statpart.h     |  25 +--
 .../pstl.statpart.partition.pass.cpp          | 181 ++++++++++++++++++
 .../libcxx/test/features/libcxx_macros.py     |   1 +
 3 files changed, 195 insertions(+), 12 deletions(-)
 create mode 100644 libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp

diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index 41e473d663f3ed..715027c6bd706a 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -121,17 +121,18 @@ struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
 
   template <class _Iter>
   friend optional<__iterator_partitions<_Iter>>
-  __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t) noexcept;
+  __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t, size_t) noexcept;
 };
 
 template <class _ForwardIterator>
-_LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>>
-__partition(_ForwardIterator __first,
-            _ForwardIterator __last,
-            __partitioning_result& __result,
-            size_t __min_partition_size = 1,
-            size_t __prefix_to_skip     = 0,
-            size_t __suffix_to_skip     = 0) noexcept {
+_LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partition(
+    _ForwardIterator __first,
+    _ForwardIterator __last,
+    __partitioning_result& __result,
+    size_t __min_partition_size = 1,
+    size_t __prefix_to_skip     = 0,
+    size_t __suffix_to_skip     = 0,
+    size_t __workers_count      = thread::hardware_concurrency()) noexcept {
   // forward iteratos to be supported later
   static_assert(__has_random_access_iterator_category_or_concept<_ForwardIterator>::value);
   // TODO: assert( __min_partition_size > 0 )?
@@ -143,7 +144,6 @@ __partition(_ForwardIterator __first,
   }
 
   size_t __effective_count = __count - __prefix_to_skip - __suffix_to_skip;
-  size_t __workers_count   = thread::hardware_concurrency();
   size_t __max_partitions  = __workers_count * __max_partitions_per_cpu;
   size_t __partition_count = std::min(__max_partitions, __effective_count / __min_partition_size);
 
@@ -155,10 +155,11 @@ __partition(_ForwardIterator __first,
 
   __iterator_partitions<_ForwardIterator> __p;
   __p.__base_             = __first + __prefix_to_skip;
-  __p.__count_            = __count;
-  __p.__partition_size_   = __count / __partition_count;
-  __p.__remainder_        = __count % __partition_count;
+  __p.__count_            = __effective_count;
+  __p.__partition_size_   = __effective_count / __partition_count;
+  __p.__remainder_        = __effective_count % __partition_count;
   __p.__partitions_count_ = __partition_count;
+  __result                = __partitioning_result::__ok;
   return __p;
 }
 
diff --git a/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp b/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp
new file mode 100644
index 00000000000000..e9c973b94e7a23
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp
@@ -0,0 +1,181 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// REQUIRES: std-at-least-c++17
+// REQUIRES: libcpp-pstl-backend-statpart
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class Iterator>
+// optional<__iterator_partitions<Iterator>>
+// __partition(Iterator __first,
+//             Iterator __last,
+//             __partitioning_result& __result,
+//             size_t __min_partition_size,
+//             size_t __prefix_to_skip,
+//             size_t __suffix_to_skip,
+//             size_t __workers_count)
+
+#include <__pstl/backends/statpart.h>
+#include <algorithm>
+#include <iterator>
+#include <cassert>
+#include <cstddef>
+#include <vector>
+
+template <class Container>
+void test_partition() {
+  auto part_eq = [](const auto& partition, const auto& container, size_t first_pos, size_t last_pos) {
+    return partition.__first == std::next(container.begin(), first_pos) &&
+           partition.__last == std::next(container.begin(), last_pos);
+  };
+
+  { // 1 element, 8 workers: no partitions
+    Container v(1);
+    std::__pstl::__statpart::__partitioning_result result;
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 1, 0, 0, 8);
+    assert(partitions == std::nullopt);
+    assert(result == std::__pstl::__statpart::__partitioning_result::__not_enough_elements);
+  }
+  { // 2 elements, 8 workers: 2 partitions
+    // [0..1), [1..2)
+    Container v(2);
+    std::__pstl::__statpart::__partitioning_result result;
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 1, 0, 0, 8);
+    assert(partitions != std::nullopt);
+    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
+    assert(partitions->__partitions_count() == 2);
+    assert(partitions->__end() == v.end());
+    assert(part_eq(partitions->__partition(0), v, 0, 1));
+    assert(part_eq(partitions->__partition(1), v, 1, 2));
+  }
+  { // 2 elements, min_size=2, 8 workers: no partitions
+    // [0..1), [1..2)
+    Container v(2);
+    std::__pstl::__statpart::__partitioning_result result;
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 1, 2, 0, 8);
+    assert(partitions == std::nullopt);
+    assert(result == std::__pstl::__statpart::__partitioning_result::__not_enough_elements);
+  }
+  { // 20 elements, 2 workers: 16 partitions
+    // [0..2), [2..4), [4..6), [6..8), [8..9), [9..10), ..., [19, 20)
+    Container v(20);
+    std::__pstl::__statpart::__partitioning_result result;
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 1, 0, 0, 2);
+    assert(partitions != std::nullopt);
+    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
+    assert(partitions->__partitions_count() == 16);
+    assert(partitions->__end() == v.end());
+    assert(part_eq(partitions->__partition(0), v, 0, 2));
+    assert(part_eq(partitions->__partition(1), v, 2, 4));
+    assert(part_eq(partitions->__partition(2), v, 4, 6));
+    assert(part_eq(partitions->__partition(3), v, 6, 8));
+    assert(part_eq(partitions->__partition(4), v, 8, 9));
+    assert(part_eq(partitions->__partition(5), v, 9, 10));
+    assert(part_eq(partitions->__partition(6), v, 10, 11));
+    assert(part_eq(partitions->__partition(7), v, 11, 12));
+    assert(part_eq(partitions->__partition(8), v, 12, 13));
+    assert(part_eq(partitions->__partition(9), v, 13, 14));
+    assert(part_eq(partitions->__partition(10), v, 14, 15));
+    assert(part_eq(partitions->__partition(11), v, 15, 16));
+    assert(part_eq(partitions->__partition(12), v, 16, 17));
+    assert(part_eq(partitions->__partition(13), v, 17, 18));
+    assert(part_eq(partitions->__partition(14), v, 18, 19));
+    assert(part_eq(partitions->__partition(15), v, 19, 20));
+  }
+  { // 20 elements, min_size=2, 2 workers: 10 partitions
+    // [0..2), [2..4), [4..6), ..., [18, 20)
+    Container v(20);
+    std::__pstl::__statpart::__partitioning_result result;
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 2, 0, 0, 2);
+    assert(partitions != std::nullopt);
+    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
+    assert(partitions->__partitions_count() == 10);
+    assert(partitions->__end() == v.end());
+    assert(part_eq(partitions->__partition(0), v, 0, 2));
+    assert(part_eq(partitions->__partition(1), v, 2, 4));
+    assert(part_eq(partitions->__partition(2), v, 4, 6));
+    assert(part_eq(partitions->__partition(3), v, 6, 8));
+    assert(part_eq(partitions->__partition(4), v, 8, 10));
+    assert(part_eq(partitions->__partition(5), v, 10, 12));
+    assert(part_eq(partitions->__partition(6), v, 12, 14));
+    assert(part_eq(partitions->__partition(7), v, 14, 16));
+    assert(part_eq(partitions->__partition(8), v, 16, 18));
+    assert(part_eq(partitions->__partition(9), v, 18, 20));
+  }
+  { // 20 elements, min_size=3, 2 workers: 6 partitions
+    // [0..4), [4..8), [8..11), [11..14), [14..17), [17..20)
+    Container v(20);
+    std::__pstl::__statpart::__partitioning_result result;
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 3, 0, 0, 2);
+    assert(partitions != std::nullopt);
+    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
+    assert(partitions->__partitions_count() == 6);
+    assert(partitions->__end() == v.end());
+    assert(part_eq(partitions->__partition(0), v, 0, 4));
+    assert(part_eq(partitions->__partition(1), v, 4, 8));
+    assert(part_eq(partitions->__partition(2), v, 8, 11));
+    assert(part_eq(partitions->__partition(3), v, 11, 14));
+    assert(part_eq(partitions->__partition(4), v, 14, 17));
+    assert(part_eq(partitions->__partition(5), v, 17, 20));
+  }
+  { // 20 elements, min_size=3, prefix_skip=1, 2 workers: 6 partitions
+    // [1..5), [5..8), [8..11), [11..14), [14..17), [17..20)
+    Container v(20);
+    std::__pstl::__statpart::__partitioning_result result;
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 3, 1, 0, 2);
+    assert(partitions != std::nullopt);
+    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
+    assert(partitions->__partitions_count() == 6);
+    assert(partitions->__end() == v.end());
+    assert(part_eq(partitions->__partition(0), v, 1, 5));
+    assert(part_eq(partitions->__partition(1), v, 5, 8));
+    assert(part_eq(partitions->__partition(2), v, 8, 11));
+    assert(part_eq(partitions->__partition(3), v, 11, 14));
+    assert(part_eq(partitions->__partition(4), v, 14, 17));
+    assert(part_eq(partitions->__partition(5), v, 17, 20));
+  }
+  { // 20 elements, min_size=3, suffix_skip=1, 2 workers: 6 partitions
+    // [0..4), [4..8), [8..11), [11..14), [14..17), [17..20)
+    Container v(20);
+    std::__pstl::__statpart::__partitioning_result result;
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 3, 0, 1, 2);
+    assert(partitions != std::nullopt);
+    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
+    assert(partitions->__partitions_count() == 6);
+    assert(partitions->__end() == std::prev(v.end(), 1));
+    assert(part_eq(partitions->__partition(0), v, 0, 4));
+    assert(part_eq(partitions->__partition(1), v, 4, 7));
+    assert(part_eq(partitions->__partition(2), v, 7, 10));
+    assert(part_eq(partitions->__partition(3), v, 10, 13));
+    assert(part_eq(partitions->__partition(4), v, 13, 16));
+    assert(part_eq(partitions->__partition(5), v, 16, 19));
+  }
+  { // 20 elements, min_size=3, prefix_skip=1, suffix_skip=1, 2 workers: 6 partitions
+    // [0..4), [4..8), [8..11), [11..14), [14..17), [17..20)
+    Container v(20);
+    std::__pstl::__statpart::__partitioning_result result;
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 3, 1, 1, 2);
+    assert(partitions != std::nullopt);
+    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
+    assert(partitions->__partitions_count() == 6);
+    assert(partitions->__end() == std::prev(v.end(), 1));
+    assert(part_eq(partitions->__partition(0), v, 1, 4));
+    assert(part_eq(partitions->__partition(1), v, 4, 7));
+    assert(part_eq(partitions->__partition(2), v, 7, 10));
+    assert(part_eq(partitions->__partition(3), v, 10, 13));
+    assert(part_eq(partitions->__partition(4), v, 13, 16));
+    assert(part_eq(partitions->__partition(5), v, 16, 19));
+  }
+}
+
+int main(int, char**) {
+  test_partition<std::vector<int>>();
+  // later: test_partition<std::list<int>>();
+}
diff --git a/libcxx/utils/libcxx/test/features/libcxx_macros.py b/libcxx/utils/libcxx/test/features/libcxx_macros.py
index 33d569e75e6bcb..2feeeb3eb6a879 100644
--- a/libcxx/utils/libcxx/test/features/libcxx_macros.py
+++ b/libcxx/utils/libcxx/test/features/libcxx_macros.py
@@ -34,6 +34,7 @@
     "_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR": "libcpp-deprecated-abi-disable-pair-trivial-copy-ctor",
     "_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING": "libcpp-abi-no-compressed-pair-padding",
     "_LIBCPP_PSTL_BACKEND_LIBDISPATCH": "libcpp-pstl-backend-libdispatch",
+    "_LIBCPP_PSTL_BACKEND_STATPART": "libcpp-pstl-backend-statpart",
     "_LIBCPP_ABI_USE_SMALL_DEQUE_BLOCK_SIZE": "libcpp-abi-use-small-deque-block-size",
 }
 for macro, feature in macros.items():

>From f3e9747fe8327102293afb45c07625f563bd9de8 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 12 Oct 2026 13:43:07 +0100
Subject: [PATCH 05/24] More comments

---
 libcxx/include/__pstl/backends/statpart.h | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index 715027c6bd706a..11a1264fe6b117 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -72,7 +72,7 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl {
 namespace __statpart {
 
-// The backbone for the backend: applies the function to each of the indices [0, __chunk_count] in parallel.
+// The backbone of the backend: applies the function to each of the indices [0, __chunk_count] in parallel.
 // The actual number of parallel workers and the order of application is unspecified.
 _LIBCPP_EXPORTED_FROM_ABI void
 __apply(size_t __chunk_count, void* __context, void (*__func)(void* __context, size_t __chunk)) noexcept;
@@ -99,7 +99,9 @@ struct _LIBCPP_HIDE_FROM_ABI __iterator_range {
   _Iterator __last;
 };
 
-// Later to support forward iterators via a second implicit template argument.
+// __iterator_partitions<Iter> holds a finite per-determined set of partitions and allows to query each iterator range
+// in O(1) time.
+// TODO: Later to support forward iterators via a second implicit template argument.
 template <class _Iterator>
 struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
   _LIBCPP_HIDE_FROM_ABI size_t __partitions_count() const { return __partitions_count_; }
@@ -124,6 +126,14 @@ struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
   __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t, size_t) noexcept;
 };
 
+// Splits the input iterator range into a finite set of partitions, such as that every iterator sub-range can queried in
+// a O(1) time later.
+// In case partitioning failed returns nullopt and reports the reason in __result.
+// __min_partition_size specifies the minimal number of elements in every partition.
+// __prefix_to_skip and __suffix_to_skip allow to optionally trim the input range by specified numbers of elements
+// before partitioning.
+// __workers_count is normally implicitly queried from hardware_concurrency() and should be explicitly specified only in
+// unit tests.
 template <class _ForwardIterator>
 _LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partition(
     _ForwardIterator __first,
@@ -136,6 +146,7 @@ _LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partit
   // forward iteratos to be supported later
   static_assert(__has_random_access_iterator_category_or_concept<_ForwardIterator>::value);
   // TODO: assert( __min_partition_size > 0 )?
+  // TODO: assert( __workers_count > 0 )?
 
   size_t __count = static_cast<size_t>(std::distance(__first, __last));
   if (__count < __prefix_to_skip + __suffix_to_skip) {
@@ -163,7 +174,8 @@ _LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partit
   return __p;
 }
 
-// for_each with explicit partitioning
+// for_each with explicit partitioning:
+// calls __func in parallel with every iterator ranges provided in __partitions
 template <class _Iterator, class _Functor>
 _LIBCPP_HIDE_FROM_ABI void __for_each_partition(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
   struct __ctx_t {
@@ -185,14 +197,15 @@ _LIBCPP_HIDE_FROM_ABI void __for_each_index(size_t __count, _Functor __func) {
   });
 }
 
-// TODO: ...
+// for_each that calls __func in parallel against every partition index available in __partitions
 template <class _Iterator, class _Functor>
 _LIBCPP_HIDE_FROM_ABI void
 __for_each_partition_index(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
   __statpart::__for_each_index(__partitions.__partitions_count(), std::move(__func));
 }
 
-// for_each with default implicit partitioning
+// for_each with default implicit partitioning:
+// calls __func in parallel with every element in [__first, __last), provided as iterator ranges.
 template <class _Iterator, class _Functor>
 _LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each(_Iterator __first, _Iterator __last, _Functor __func) {
   if (__first == __last)

>From ed528d4c619311a46d19cefd4cff063a4d9eee27 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 12 Oct 2026 18:13:20 +0100
Subject: [PATCH 06/24] Restructuring the statpart backend for easier
 maintenance

---
 libcxx/include/CMakeLists.txt                 |   3 +-
 libcxx/include/__pstl/backends/statpart.h     | 434 +--------------
 .../include/__pstl/backends/statpart/basis.h  | 494 ++++++++++++++++++
 libcxx/include/module.modulemap.in            |   5 +
 4 files changed, 503 insertions(+), 433 deletions(-)
 create mode 100644 libcxx/include/__pstl/backends/statpart/basis.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index da2546a54bc04d..5b99cc3ba58565 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -695,7 +695,8 @@ set(files
   __pstl/backends/default.h
   __pstl/backends/libdispatch.h
   __pstl/backends/serial.h
-  __pstl/backends/statpart.h
+  __pstl/backends/statpart.h  
+  __pstl/backends/statpart/basis.h
   __pstl/backends/std_thread.h
   __pstl/cpu_algos/any_of.h
   __pstl/cpu_algos/cpu_traits.h
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index 11a1264fe6b117..788bb713c4fae6 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -9,6 +9,8 @@
 #ifndef _LIBCPP___PSTL_STATPART_H
 #define _LIBCPP___PSTL_STATPART_H
 
+#include <__pstl/backends/statpart/basis.h>
+
 #include <__algorithm/find_end.h>
 #include <__algorithm/find_if.h>
 #include <__algorithm/for_each.h>
@@ -70,438 +72,6 @@ _LIBCPP_PUSH_MACROS
 _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl {
-namespace __statpart {
-
-// The backbone of the backend: applies the function to each of the indices [0, __chunk_count] in parallel.
-// The actual number of parallel workers and the order of application is unspecified.
-_LIBCPP_EXPORTED_FROM_ABI void
-__apply(size_t __chunk_count, void* __context, void (*__func)(void* __context, size_t __chunk)) noexcept;
-
-// The maximum number of partitions to be processed per each CPU
-constexpr inline size_t __max_partitions_per_cpu = 8;
-
-// The minimum number of elements to sort serially in a single partition
-constexpr inline size_t __min_sort_partition_size = 256;
-
-enum class __partitioning_result {
-  // returned when the partitioning result is not nullopt
-  __ok,
-  // returned when there is not enough element to produce a single partition or the final number of partitions is less
-  // than 2, i.e. there's no reason to process in parallel
-  __not_enough_elements,
-  // later: returned memory couldn't be allocated for the stashed forward iterators
-  __bad_alloc
-};
-
-template <class _Iterator>
-struct _LIBCPP_HIDE_FROM_ABI __iterator_range {
-  _Iterator __first;
-  _Iterator __last;
-};
-
-// __iterator_partitions<Iter> holds a finite per-determined set of partitions and allows to query each iterator range
-// in O(1) time.
-// TODO: Later to support forward iterators via a second implicit template argument.
-template <class _Iterator>
-struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
-  _LIBCPP_HIDE_FROM_ABI size_t __partitions_count() const { return __partitions_count_; }
-
-  _LIBCPP_HIDE_FROM_ABI __iterator_range<_Iterator> __partition(size_t __n) const {
-    _Iterator __first = __base_ + __n * __partition_size_ + (__n < __remainder_ ? __n : __remainder_);
-    _Iterator __last  = __first + __partition_size_ + (__n < __remainder_ ? 1 : 0);
-    return __iterator_range<_Iterator>{__first, __last};
-  }
-
-  _LIBCPP_HIDE_FROM_ABI _Iterator __end() const { return __base_ + __count_; }
-
-private:
-  _Iterator __base_;
-  size_t __count_;
-  size_t __partition_size_;
-  size_t __remainder_;
-  size_t __partitions_count_;
-
-  template <class _Iter>
-  friend optional<__iterator_partitions<_Iter>>
-  __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t, size_t) noexcept;
-};
-
-// Splits the input iterator range into a finite set of partitions, such as that every iterator sub-range can queried in
-// a O(1) time later.
-// In case partitioning failed returns nullopt and reports the reason in __result.
-// __min_partition_size specifies the minimal number of elements in every partition.
-// __prefix_to_skip and __suffix_to_skip allow to optionally trim the input range by specified numbers of elements
-// before partitioning.
-// __workers_count is normally implicitly queried from hardware_concurrency() and should be explicitly specified only in
-// unit tests.
-template <class _ForwardIterator>
-_LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partition(
-    _ForwardIterator __first,
-    _ForwardIterator __last,
-    __partitioning_result& __result,
-    size_t __min_partition_size = 1,
-    size_t __prefix_to_skip     = 0,
-    size_t __suffix_to_skip     = 0,
-    size_t __workers_count      = thread::hardware_concurrency()) noexcept {
-  // forward iteratos to be supported later
-  static_assert(__has_random_access_iterator_category_or_concept<_ForwardIterator>::value);
-  // TODO: assert( __min_partition_size > 0 )?
-  // TODO: assert( __workers_count > 0 )?
-
-  size_t __count = static_cast<size_t>(std::distance(__first, __last));
-  if (__count < __prefix_to_skip + __suffix_to_skip) {
-    __result = __partitioning_result::__not_enough_elements;
-    return {};
-  }
-
-  size_t __effective_count = __count - __prefix_to_skip - __suffix_to_skip;
-  size_t __max_partitions  = __workers_count * __max_partitions_per_cpu;
-  size_t __partition_count = std::min(__max_partitions, __effective_count / __min_partition_size);
-
-  if (__partition_count < 2) {
-    // TODO: verify that's what we want
-    __result = __partitioning_result::__not_enough_elements;
-    return {}; // not enough input data to process in parallel => no reason to build partitions
-  }
-
-  __iterator_partitions<_ForwardIterator> __p;
-  __p.__base_             = __first + __prefix_to_skip;
-  __p.__count_            = __effective_count;
-  __p.__partition_size_   = __effective_count / __partition_count;
-  __p.__remainder_        = __effective_count % __partition_count;
-  __p.__partitions_count_ = __partition_count;
-  __result                = __partitioning_result::__ok;
-  return __p;
-}
-
-// for_each with explicit partitioning:
-// calls __func in parallel with every iterator ranges provided in __partitions
-template <class _Iterator, class _Functor>
-_LIBCPP_HIDE_FROM_ABI void __for_each_partition(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
-  struct __ctx_t {
-    const __iterator_partitions<_Iterator>& __partitions_;
-    _Functor& __func_;
-  } __ctx{__partitions, __func};
-  __statpart::__apply(__partitions.__partitions_count(), &__ctx, [](void* __context, size_t __partition) {
-    __ctx_t& __ctx = *static_cast<__ctx_t*>(__context);
-    auto __range   = __ctx.__partitions_.__partition(__partition);
-    __ctx.__func_(__range.__first, __range.__last);
-  });
-}
-
-// Calls __func(index) for every index in [0, __count) in parallel
-template <class _Functor>
-_LIBCPP_HIDE_FROM_ABI void __for_each_index(size_t __count, _Functor __func) {
-  __statpart::__apply(__count, &__func, [](void* __context, size_t __index) {
-    (*static_cast<_Functor*>(__context))(__index);
-  });
-}
-
-// for_each that calls __func in parallel against every partition index available in __partitions
-template <class _Iterator, class _Functor>
-_LIBCPP_HIDE_FROM_ABI void
-__for_each_partition_index(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
-  __statpart::__for_each_index(__partitions.__partitions_count(), std::move(__func));
-}
-
-// for_each with default implicit partitioning:
-// calls __func in parallel with every element in [__first, __last), provided as iterator ranges.
-template <class _Iterator, class _Functor>
-_LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each(_Iterator __first, _Iterator __last, _Functor __func) {
-  if (__first == __last)
-    return __empty{};
-  __partitioning_result __partition_result;
-  auto __partitions = __statpart::__partition(__first, __last, __partition_result);
-  if (__partitions) {
-    __statpart::__for_each_partition(*__partitions, std::move(__func));
-    return __empty{};
-  } else if (__partition_result == __partitioning_result::__bad_alloc) {
-    return nullopt;
-  } else {
-    __func(__first, __last);
-    return __empty{};
-  }
-}
-
-// Applies the 3-legged function to sub-ranges of the input ranges in parallel:
-//   f(sub_range1_first, sub_range1_last, sub_range2_first)
-template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BrickFunction>
-_LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each_iter_pair(
-    _RandomAccessIterator1 __first1,
-    _RandomAccessIterator1 __last1,
-    _RandomAccessIterator2 __first2,
-    _BrickFunction __f) {
-  return __for_each(
-      __first1,
-      __last1,
-      [__first1, __first2, __f = std::move(__f)](
-          _RandomAccessIterator1 __brick_first1, _RandomAccessIterator1 __brick_last1) {
-        _RandomAccessIterator2 __brick_first2 = __first2 + (__brick_first1 - __first1);
-        __f(__brick_first1, __brick_last1, __brick_first2);
-      });
-}
-
-template <class _Index, class _Brick, class _Compare>
-_LIBCPP_HIDE_FROM_ABI optional<_Index>
-__find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) {
-  typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType;
-  const _DifferenceType __n      = __last - __first;
-  _DifferenceType __initial_dist = __b_first ? __n : -1;
-  std::atomic<_DifferenceType> __extremum(__initial_dist);
-  // TODO: find out what is better here: parallel_for or parallel_reduce
-  auto __res = __statpart::__for_each(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
-    // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of
-    // why using a shared variable scales fairly well in this situation.
-    if (__comp(__i - __first, __extremum)) {
-      _Index __result = __f(__i, __j);
-      // If not '__last' returned then we found what we want so put this to extremum
-      if (__result != __j) {
-        const _DifferenceType __k = __result - __first;
-        for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) {
-          __extremum.compare_exchange_weak(__old, __k);
-        }
-      }
-    }
-  });
-  if (!__res)
-    return nullopt;
-  return __extremum.load() != __initial_dist ? __first + __extremum.load() : __last;
-}
-
-template <class _RandomAccessIterator, class _Transform, class _Value, class _Combiner, class _Reduction>
-_LIBCPP_HIDE_FROM_ABI optional<_Value> __transform_reduce(
-    _RandomAccessIterator __first,
-    _RandomAccessIterator __last,
-    _Transform __transform,
-    _Value __init,
-    _Combiner __combiner,
-    _Reduction __reduction) {
-  if (__first == __last)
-    return __init;
-
-  // Split into partitions with at least 3 elements in each
-  __partitioning_result __partitioning_result;
-  auto __partitions = __statpart::__partition(__first, __last, __partitioning_result, 3);
-  if (!__partitions) {
-    if (__partitioning_result == __partitioning_result::__bad_alloc) {
-      // Failed to allocate memory for the partitions, propagate the error up.
-      return nullopt;
-    } else {
-      // Not enough elements to run in parallel, switch to serial implementation.
-      return __reduction(std::move(__first), std::move(__last), std::move(__init));
-    }
-  }
-
-  auto __destroy = [__count = __partitions->__partitions_count()](_Value* __ptr) {
-    std::destroy_n(__ptr, __count);
-    std::allocator<_Value>().deallocate(__ptr, __count);
-  };
-
-  // TODO: use __uninitialized_buffer
-  // TODO: allocate one element per worker instead of one element per chunk
-  unique_ptr<_Value[], decltype(__destroy)> __values(
-      std::allocator<_Value>().allocate(__partitions->__partitions_count()), __destroy);
-
-  // __dispatch_apply is noexcept
-  __statpart::__for_each_partition_index(*__partitions, [&](size_t __index) {
-    auto __range = __partitions->__partition(__index);
-    std::__construct_at(
-        __values.get() + __index,
-        __reduction(__range.__first + 2,
-                    __range.__last,
-                    __combiner(__transform(__range.__first), __transform(__range.__first + 1))));
-  });
-
-  return std::reduce(
-      std::make_move_iterator(__values.get()),
-      std::make_move_iterator(__values.get() + __partitions->__partitions_count()),
-      std::move(__init),
-      __combiner);
-}
-
-template <class _RandomAccessIterator1,
-          class _RandomAccessIterator2,
-          class _RandomAccessIterator3,
-          class _Compare,
-          class _LeafMerge>
-_LIBCPP_HIDE_FROM_ABI optional<__empty>
-__merge(_RandomAccessIterator1 __first1,
-        _RandomAccessIterator1 __last1,
-        _RandomAccessIterator2 __first2,
-        _RandomAccessIterator2 __last2,
-        _RandomAccessIterator3 __result,
-        _Compare __comp,
-        _LeafMerge __leaf_merge) noexcept {
-  // Run the merge such that the longest range is partitioned.
-  // __merge_sub_ranges swaps the ranges implicitly in case the second range was the longest one.
-  auto __run =
-      [__result](auto __long_first,
-                 auto __long_last,
-                 auto __short_first,
-                 auto __short_last,
-                 auto __find_cutpoint,
-                 auto __merge_sub_ranges) -> optional<__empty> {
-    // Partition the longest input range evenly.
-    __partitioning_result __partitioning_result;
-    auto __partitions = __statpart::__partition(__long_first, __long_last, __partitioning_result);
-    if (!__partitions) {
-      if (__partitioning_result == __partitioning_result::__bad_alloc)
-        return nullopt;
-      // Not enough elements to run in parallel, merge everything serially.
-      __merge_sub_ranges(__long_first, __long_last, __short_first, __short_last, __result);
-      return __empty{};
-    }
-
-    // Process the partitions of the longest range in parallel.
-    __statpart::__for_each_partition_index(*__partitions, [&](size_t __index) {
-      // Get the sub-range inside the longer input range.
-      auto __range = __partitions->__partition(__index);
-
-      // Find the matching sub-range of the shorter input range: it will hold the elements that come after the last
-      // element of the previous long partition and up to the last element of this partition.
-      // This generally runs two binary searches in the smaller input range, edge partitions use existing bounds.
-      auto __short_begin =
-          __index == 0 ? __short_first : __find_cutpoint(__short_first, __short_last, __range.__first[-1]);
-      auto __short_end =
-          __index == __partitions->__partitions_count() - 1
-              ? __short_last
-              : __find_cutpoint(__short_first, __short_last, __range.__last[-1]);
-
-      // Derive the position in the output range and merge the sub-ranges.
-      auto __result_first = __result + (__range.__first - __long_first) + (__short_begin - __short_first);
-      __merge_sub_ranges(__range.__first, __range.__last, __short_begin, __short_end, __result_first);
-    });
-    return __empty{};
-  };
-
-  if (__last1 - __first1 > __last2 - __first2) {
-    // Preserve the order of the input ranges, partition the first range.
-    // Equal elements of the second range go after the cut => use lower_bound when cutting.
-    return __run(
-        __first1,
-        __last1,
-        __first2,
-        __last2,
-        [&](auto __first, auto __last, const auto& __value) {
-          return std::lower_bound(__first, __last, __value, __comp);
-        },
-        [&](auto __long_first, auto __long_last, auto __short_first, auto __short_last, auto __result_first) {
-          __leaf_merge(__long_first, __long_last, __short_first, __short_last, __result_first, __comp);
-        });
-  } else {
-    // Swap the order of the input ranges, partition the second range.
-    // Equal elements of the first range go before the cut => use upper_bound when cutting.
-    return __run(
-        __first2,
-        __last2,
-        __first1,
-        __last1,
-        [&](auto __first, auto __last, const auto& __value) {
-          return std::upper_bound(__first, __last, __value, __comp);
-        },
-        [&](auto __long_first, auto __long_last, auto __short_first, auto __short_last, auto __result_first) {
-          __leaf_merge(__short_first, __short_last, __long_first, __long_last, __result_first, __comp);
-        });
-  }
-}
-
-template <class _RandomAccessIterator, class _Comp, class _LeafSort>
-_LIBCPP_HIDE_FROM_ABI optional<__empty>
-__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
-  const auto __size = __last - __first;
-
-  __partitioning_result __partitioning_result;
-  auto __partitions = __statpart::__partition(__first, __last, __partitioning_result, __min_sort_partition_size);
-  if (!__partitions) {
-    if (__partitioning_result == __partitioning_result::__bad_alloc)
-      return nullopt;
-    // Not enough elements to run in parallel, sort everything serially.
-    __leaf_sort(__first, __last, __comp);
-    return __empty{};
-  }
-
-  using _Value = __iterator_value_type<_RandomAccessIterator>;
-
-  auto __destroy = [__size](_Value* __ptr) {
-    std::destroy_n(__ptr, __size);
-    std::allocator<_Value>().deallocate(__ptr, __size);
-  };
-
-  // TODO: use __uninitialized_buffer
-  unique_ptr<_Value[], decltype(__destroy)> __values(std::allocator<_Value>().allocate(__size), __destroy);
-
-  // Initialize all elements to a moved-from state
-  // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928
-  std::__construct_at(__values.get(), std::move(*__first));
-  for (__iterator_difference_type<_RandomAccessIterator> __i = 1; __i != __size; ++__i) {
-    std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1]));
-  }
-  *__first = std::move(__values.get()[__size - 1]);
-
-  __statpart::__for_each_partition(
-      *__partitions, [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) {
-        __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp);
-      });
-
-  // A chunk span is a run of __chunk_span_size consecutive partitions, the last chunk can be shorter in case of odd
-  // number of chunk spans. Each pass merges the chunk spans pairwise, so the chunk span size doubles and the chunk
-  // count is halved (rounded up).
-  const size_t __partition_count = __partitions->__partitions_count();
-  size_t __chunk_span_size       = 1;
-  size_t __chunk_spans           = __partition_count;
-
-  // Offsets of the beginning and the end of the chunk from __first
-  auto __chunk_begin = [&](size_t __chunk) {
-    return __partitions->__partition(__chunk * __chunk_span_size).__first - __first;
-  };
-  auto __chunk_end = [&](size_t __chunk) {
-    return __partitions->__partition(std::min((__chunk + 1) * __chunk_span_size, __partition_count) - 1).__last -
-           __first;
-  };
-
-  bool __objects_are_in_buffer = false;
-  do {
-    size_t __chunk_spans_pairs = (__chunk_spans + 1) / 2;
-    auto __merge_chunks        = [&](auto __from_first, auto __to_first) {
-      __statpart::__for_each_index(__chunk_spans_pairs, [&](size_t __span_pair_index) {
-        size_t __left_chunk  = 2 * __span_pair_index;
-        size_t __right_chunk = __left_chunk + 1;
-        auto __pair_first    = __chunk_begin(__left_chunk);
-        if (__right_chunk == __chunk_spans) {
-          // The odd chunk has no counterpart to merge with => carry it over to the other buffer as-is.
-          std::move(__from_first + __pair_first, __from_first + __chunk_end(__left_chunk), __to_first + __pair_first);
-        } else {
-          // Merge the two chunk spans into the other buffer
-          auto __pair_mid  = __chunk_begin(__right_chunk);
-          auto __pair_last = __chunk_end(__right_chunk);
-          std::merge(std::make_move_iterator(__from_first + __pair_first),
-                     std::make_move_iterator(__from_first + __pair_mid),
-                     std::make_move_iterator(__from_first + __pair_mid),
-                     std::make_move_iterator(__from_first + __pair_last),
-                     __to_first + __pair_first,
-                     __comp);
-        }
-      });
-    };
-
-    if (__objects_are_in_buffer)
-      __merge_chunks(__values.get(), __first);
-    else
-      __merge_chunks(__first, __values.get());
-    __objects_are_in_buffer = !__objects_are_in_buffer;
-
-    __chunk_span_size *= 2;
-    __chunk_spans = __chunk_spans_pairs;
-  } while (__chunk_spans > 1);
-
-  if (__objects_are_in_buffer) {
-    std::move(__values.get(), __values.get() + __size, __first);
-  }
-
-  return __empty{};
-}
-
-} // namespace __statpart
 
 template <class _ExecutionPolicy>
 struct __find_end<__statpart_backend_tag, _ExecutionPolicy> {
diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
new file mode 100644
index 00000000000000..709eee0504bc4e
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -0,0 +1,494 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART__BASIS_H
+#define _LIBCPP___PSTL_STATPART__BASIS_H
+
+#include <__algorithm/lower_bound.h>
+#include <__algorithm/merge.h>
+#include <__algorithm/min.h>
+#include <__algorithm/move.h>
+#include <__algorithm/upper_bound.h>
+#include <__atomic/atomic.h>
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/distance.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/move_iterator.h>
+#include <__memory/allocator.h>
+#include <__memory/construct_at.h>
+#include <__memory/destroy.h>
+#include <__memory/unique_ptr.h>
+#include <__numeric/reduce.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__thread/thread.h>
+#include <__type_traits/is_assignable.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__type_traits/is_trivially_copyable.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+namespace __statpart {
+
+// The backbone of the backend: applies the function to each of the indices [0, __chunk_count] in parallel.
+// The actual number of parallel workers and the order of application is unspecified.
+_LIBCPP_EXPORTED_FROM_ABI void
+__apply(size_t __chunk_count, void* __context, void (*__func)(void* __context, size_t __chunk)) noexcept;
+
+// The maximum number of partitions to be processed per each CPU
+constexpr inline size_t __max_partitions_per_cpu = 8;
+
+// The minimum number of elements to sort serially in a single partition
+constexpr inline size_t __min_sort_partition_size = 256;
+
+enum class __partitioning_result {
+  // returned when the partitioning result is not nullopt
+  __ok,
+  // returned when there is not enough element to produce a single partition or the final number of partitions is less
+  // than 2, i.e. there's no reason to process in parallel
+  __not_enough_elements,
+  // later: returned memory couldn't be allocated for the stashed forward iterators
+  __bad_alloc
+};
+
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __iterator_range {
+  _Iterator __first;
+  _Iterator __last;
+};
+
+// __iterator_partitions<Iter> holds a finite per-determined set of partitions and allows to query each iterator range
+// in O(1) time.
+// TODO: Later to support forward iterators via a second implicit template argument.
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
+  _LIBCPP_HIDE_FROM_ABI size_t __partitions_count() const { return __partitions_count_; }
+
+  _LIBCPP_HIDE_FROM_ABI __iterator_range<_Iterator> __partition(size_t __n) const {
+    _Iterator __first = __base_ + __n * __partition_size_ + (__n < __remainder_ ? __n : __remainder_);
+    _Iterator __last  = __first + __partition_size_ + (__n < __remainder_ ? 1 : 0);
+    return __iterator_range<_Iterator>{__first, __last};
+  }
+
+  _LIBCPP_HIDE_FROM_ABI _Iterator __end() const { return __base_ + __count_; }
+
+private:
+  _Iterator __base_;
+  size_t __count_;
+  size_t __partition_size_;
+  size_t __remainder_;
+  size_t __partitions_count_;
+
+  template <class _Iter>
+  friend optional<__iterator_partitions<_Iter>>
+  __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t, size_t) noexcept;
+};
+
+// Splits the input iterator range into a finite set of partitions, such as that every iterator sub-range can queried in
+// a O(1) time later.
+// In case partitioning failed returns nullopt and reports the reason in __result.
+// __min_partition_size specifies the minimal number of elements in every partition.
+// __prefix_to_skip and __suffix_to_skip allow to optionally trim the input range by specified numbers of elements
+// before partitioning.
+// __workers_count is normally implicitly queried from hardware_concurrency() and should be explicitly specified only in
+// unit tests.
+template <class _ForwardIterator>
+_LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partition(
+    _ForwardIterator __first,
+    _ForwardIterator __last,
+    __partitioning_result& __result,
+    size_t __min_partition_size = 1,
+    size_t __prefix_to_skip     = 0,
+    size_t __suffix_to_skip     = 0,
+    size_t __workers_count      = thread::hardware_concurrency()) noexcept {
+  // forward iteratos to be supported later
+  static_assert(__has_random_access_iterator_category_or_concept<_ForwardIterator>::value);
+  // TODO: assert( __min_partition_size > 0 )?
+  // TODO: assert( __workers_count > 0 )?
+
+  size_t __count = static_cast<size_t>(std::distance(__first, __last));
+  if (__count < __prefix_to_skip + __suffix_to_skip) {
+    __result = __partitioning_result::__not_enough_elements;
+    return {};
+  }
+
+  size_t __effective_count = __count - __prefix_to_skip - __suffix_to_skip;
+  size_t __max_partitions  = __workers_count * __max_partitions_per_cpu;
+  size_t __partition_count = std::min(__max_partitions, __effective_count / __min_partition_size);
+
+  if (__partition_count < 2) {
+    // TODO: verify that's what we want
+    __result = __partitioning_result::__not_enough_elements;
+    return {}; // not enough input data to process in parallel => no reason to build partitions
+  }
+
+  __iterator_partitions<_ForwardIterator> __p;
+  __p.__base_             = __first + __prefix_to_skip;
+  __p.__count_            = __effective_count;
+  __p.__partition_size_   = __effective_count / __partition_count;
+  __p.__remainder_        = __effective_count % __partition_count;
+  __p.__partitions_count_ = __partition_count;
+  __result                = __partitioning_result::__ok;
+  return __p;
+}
+
+// for_each with explicit partitioning:
+// calls __func in parallel with every iterator ranges provided in __partitions
+template <class _Iterator, class _Functor>
+_LIBCPP_HIDE_FROM_ABI void __for_each_partition(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
+  struct __ctx_t {
+    const __iterator_partitions<_Iterator>& __partitions_;
+    _Functor& __func_;
+  } __ctx{__partitions, __func};
+  __statpart::__apply(__partitions.__partitions_count(), &__ctx, [](void* __context, size_t __partition) {
+    __ctx_t& __ctx = *static_cast<__ctx_t*>(__context);
+    auto __range   = __ctx.__partitions_.__partition(__partition);
+    __ctx.__func_(__range.__first, __range.__last);
+  });
+}
+
+// Calls __func(index) for every index in [0, __count) in parallel
+template <class _Functor>
+_LIBCPP_HIDE_FROM_ABI void __for_each_index(size_t __count, _Functor __func) {
+  __statpart::__apply(__count, &__func, [](void* __context, size_t __index) {
+    (*static_cast<_Functor*>(__context))(__index);
+  });
+}
+
+// for_each that calls __func in parallel against every partition index available in __partitions
+template <class _Iterator, class _Functor>
+_LIBCPP_HIDE_FROM_ABI void
+__for_each_partition_index(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
+  __statpart::__for_each_index(__partitions.__partitions_count(), std::move(__func));
+}
+
+// for_each with default implicit partitioning:
+// calls __func in parallel with every element in [__first, __last), provided as iterator ranges.
+template <class _Iterator, class _Functor>
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each(_Iterator __first, _Iterator __last, _Functor __func) {
+  if (__first == __last)
+    return __empty{};
+  __partitioning_result __partition_result;
+  auto __partitions = __statpart::__partition(__first, __last, __partition_result);
+  if (__partitions) {
+    __statpart::__for_each_partition(*__partitions, std::move(__func));
+    return __empty{};
+  } else if (__partition_result == __partitioning_result::__bad_alloc) {
+    return nullopt;
+  } else {
+    __func(__first, __last);
+    return __empty{};
+  }
+}
+
+// Applies the 3-legged function to sub-ranges of the input ranges in parallel:
+//   f(sub_range1_first, sub_range1_last, sub_range2_first)
+template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _BrickFunction>
+_LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each_iter_pair(
+    _RandomAccessIterator1 __first1,
+    _RandomAccessIterator1 __last1,
+    _RandomAccessIterator2 __first2,
+    _BrickFunction __f) {
+  return __for_each(
+      __first1,
+      __last1,
+      [__first1, __first2, __f = std::move(__f)](
+          _RandomAccessIterator1 __brick_first1, _RandomAccessIterator1 __brick_last1) {
+        _RandomAccessIterator2 __brick_first2 = __first2 + (__brick_first1 - __first1);
+        __f(__brick_first1, __brick_last1, __brick_first2);
+      });
+}
+
+template <class _Index, class _Brick, class _Compare>
+_LIBCPP_HIDE_FROM_ABI optional<_Index>
+__find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) {
+  typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType;
+  const _DifferenceType __n      = __last - __first;
+  _DifferenceType __initial_dist = __b_first ? __n : -1;
+  std::atomic<_DifferenceType> __extremum(__initial_dist);
+  // TODO: find out what is better here: parallel_for or parallel_reduce
+  auto __res = __statpart::__for_each(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
+    // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of
+    // why using a shared variable scales fairly well in this situation.
+    if (__comp(__i - __first, __extremum)) {
+      _Index __result = __f(__i, __j);
+      // If not '__last' returned then we found what we want so put this to extremum
+      if (__result != __j) {
+        const _DifferenceType __k = __result - __first;
+        for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) {
+          __extremum.compare_exchange_weak(__old, __k);
+        }
+      }
+    }
+  });
+  if (!__res)
+    return nullopt;
+  return __extremum.load() != __initial_dist ? __first + __extremum.load() : __last;
+}
+
+template <class _RandomAccessIterator, class _Transform, class _Value, class _Combiner, class _Reduction>
+_LIBCPP_HIDE_FROM_ABI optional<_Value> __transform_reduce(
+    _RandomAccessIterator __first,
+    _RandomAccessIterator __last,
+    _Transform __transform,
+    _Value __init,
+    _Combiner __combiner,
+    _Reduction __reduction) {
+  if (__first == __last)
+    return __init;
+
+  // Split into partitions with at least 3 elements in each
+  __partitioning_result __partitioning_result;
+  auto __partitions = __statpart::__partition(__first, __last, __partitioning_result, 3);
+  if (!__partitions) {
+    if (__partitioning_result == __partitioning_result::__bad_alloc) {
+      // Failed to allocate memory for the partitions, propagate the error up.
+      return nullopt;
+    } else {
+      // Not enough elements to run in parallel, switch to serial implementation.
+      return __reduction(std::move(__first), std::move(__last), std::move(__init));
+    }
+  }
+
+  auto __destroy = [__count = __partitions->__partitions_count()](_Value* __ptr) {
+    std::destroy_n(__ptr, __count);
+    std::allocator<_Value>().deallocate(__ptr, __count);
+  };
+
+  // TODO: use __uninitialized_buffer
+  // TODO: allocate one element per worker instead of one element per chunk
+  unique_ptr<_Value[], decltype(__destroy)> __values(
+      std::allocator<_Value>().allocate(__partitions->__partitions_count()), __destroy);
+
+  // __dispatch_apply is noexcept
+  __statpart::__for_each_partition_index(*__partitions, [&](size_t __index) {
+    auto __range = __partitions->__partition(__index);
+    std::__construct_at(
+        __values.get() + __index,
+        __reduction(__range.__first + 2,
+                    __range.__last,
+                    __combiner(__transform(__range.__first), __transform(__range.__first + 1))));
+  });
+
+  return std::reduce(
+      std::make_move_iterator(__values.get()),
+      std::make_move_iterator(__values.get() + __partitions->__partitions_count()),
+      std::move(__init),
+      __combiner);
+}
+
+template <class _RandomAccessIterator1,
+          class _RandomAccessIterator2,
+          class _RandomAccessIterator3,
+          class _Compare,
+          class _LeafMerge>
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
+__merge(_RandomAccessIterator1 __first1,
+        _RandomAccessIterator1 __last1,
+        _RandomAccessIterator2 __first2,
+        _RandomAccessIterator2 __last2,
+        _RandomAccessIterator3 __result,
+        _Compare __comp,
+        _LeafMerge __leaf_merge) noexcept {
+  // Run the merge such that the longest range is partitioned.
+  // __merge_sub_ranges swaps the ranges implicitly in case the second range was the longest one.
+  auto __run =
+      [__result](auto __long_first,
+                 auto __long_last,
+                 auto __short_first,
+                 auto __short_last,
+                 auto __find_cutpoint,
+                 auto __merge_sub_ranges) -> optional<__empty> {
+    // Partition the longest input range evenly.
+    __partitioning_result __partitioning_result;
+    auto __partitions = __statpart::__partition(__long_first, __long_last, __partitioning_result);
+    if (!__partitions) {
+      if (__partitioning_result == __partitioning_result::__bad_alloc)
+        return nullopt;
+      // Not enough elements to run in parallel, merge everything serially.
+      __merge_sub_ranges(__long_first, __long_last, __short_first, __short_last, __result);
+      return __empty{};
+    }
+
+    // Process the partitions of the longest range in parallel.
+    __statpart::__for_each_partition_index(*__partitions, [&](size_t __index) {
+      // Get the sub-range inside the longer input range.
+      auto __range = __partitions->__partition(__index);
+
+      // Find the matching sub-range of the shorter input range: it will hold the elements that come after the last
+      // element of the previous long partition and up to the last element of this partition.
+      // This generally runs two binary searches in the smaller input range, edge partitions use existing bounds.
+      auto __short_begin =
+          __index == 0 ? __short_first : __find_cutpoint(__short_first, __short_last, __range.__first[-1]);
+      auto __short_end =
+          __index == __partitions->__partitions_count() - 1
+              ? __short_last
+              : __find_cutpoint(__short_first, __short_last, __range.__last[-1]);
+
+      // Derive the position in the output range and merge the sub-ranges.
+      auto __result_first = __result + (__range.__first - __long_first) + (__short_begin - __short_first);
+      __merge_sub_ranges(__range.__first, __range.__last, __short_begin, __short_end, __result_first);
+    });
+    return __empty{};
+  };
+
+  if (__last1 - __first1 > __last2 - __first2) {
+    // Preserve the order of the input ranges, partition the first range.
+    // Equal elements of the second range go after the cut => use lower_bound when cutting.
+    return __run(
+        __first1,
+        __last1,
+        __first2,
+        __last2,
+        [&](auto __first, auto __last, const auto& __value) {
+          return std::lower_bound(__first, __last, __value, __comp);
+        },
+        [&](auto __long_first, auto __long_last, auto __short_first, auto __short_last, auto __result_first) {
+          __leaf_merge(__long_first, __long_last, __short_first, __short_last, __result_first, __comp);
+        });
+  } else {
+    // Swap the order of the input ranges, partition the second range.
+    // Equal elements of the first range go before the cut => use upper_bound when cutting.
+    return __run(
+        __first2,
+        __last2,
+        __first1,
+        __last1,
+        [&](auto __first, auto __last, const auto& __value) {
+          return std::upper_bound(__first, __last, __value, __comp);
+        },
+        [&](auto __long_first, auto __long_last, auto __short_first, auto __short_last, auto __result_first) {
+          __leaf_merge(__short_first, __short_last, __long_first, __long_last, __result_first, __comp);
+        });
+  }
+}
+
+template <class _RandomAccessIterator, class _Comp, class _LeafSort>
+_LIBCPP_HIDE_FROM_ABI optional<__empty>
+__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
+  const auto __size = __last - __first;
+
+  __partitioning_result __partitioning_result;
+  auto __partitions = __statpart::__partition(__first, __last, __partitioning_result, __min_sort_partition_size);
+  if (!__partitions) {
+    if (__partitioning_result == __partitioning_result::__bad_alloc)
+      return nullopt;
+    // Not enough elements to run in parallel, sort everything serially.
+    __leaf_sort(__first, __last, __comp);
+    return __empty{};
+  }
+
+  using _Value = __iterator_value_type<_RandomAccessIterator>;
+
+  auto __destroy = [__size](_Value* __ptr) {
+    std::destroy_n(__ptr, __size);
+    std::allocator<_Value>().deallocate(__ptr, __size);
+  };
+
+  // TODO: use __uninitialized_buffer
+  unique_ptr<_Value[], decltype(__destroy)> __values(std::allocator<_Value>().allocate(__size), __destroy);
+
+  // Initialize all elements to a moved-from state
+  // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928
+  std::__construct_at(__values.get(), std::move(*__first));
+  for (__iterator_difference_type<_RandomAccessIterator> __i = 1; __i != __size; ++__i) {
+    std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1]));
+  }
+  *__first = std::move(__values.get()[__size - 1]);
+
+  __statpart::__for_each_partition(
+      *__partitions, [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) {
+        __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp);
+      });
+
+  // A chunk span is a run of __chunk_span_size consecutive partitions, the last chunk can be shorter in case of odd
+  // number of chunk spans. Each pass merges the chunk spans pairwise, so the chunk span size doubles and the chunk
+  // count is halved (rounded up).
+  const size_t __partition_count = __partitions->__partitions_count();
+  size_t __chunk_span_size       = 1;
+  size_t __chunk_spans           = __partition_count;
+
+  // Offsets of the beginning and the end of the chunk from __first
+  auto __chunk_begin = [&](size_t __chunk) {
+    return __partitions->__partition(__chunk * __chunk_span_size).__first - __first;
+  };
+  auto __chunk_end = [&](size_t __chunk) {
+    return __partitions->__partition(std::min((__chunk + 1) * __chunk_span_size, __partition_count) - 1).__last -
+           __first;
+  };
+
+  bool __objects_are_in_buffer = false;
+  do {
+    size_t __chunk_spans_pairs = (__chunk_spans + 1) / 2;
+    auto __merge_chunks        = [&](auto __from_first, auto __to_first) {
+      __statpart::__for_each_index(__chunk_spans_pairs, [&](size_t __span_pair_index) {
+        size_t __left_chunk  = 2 * __span_pair_index;
+        size_t __right_chunk = __left_chunk + 1;
+        auto __pair_first    = __chunk_begin(__left_chunk);
+        if (__right_chunk == __chunk_spans) {
+          // The odd chunk has no counterpart to merge with => carry it over to the other buffer as-is.
+          std::move(__from_first + __pair_first, __from_first + __chunk_end(__left_chunk), __to_first + __pair_first);
+        } else {
+          // Merge the two chunk spans into the other buffer
+          auto __pair_mid  = __chunk_begin(__right_chunk);
+          auto __pair_last = __chunk_end(__right_chunk);
+          std::merge(std::make_move_iterator(__from_first + __pair_first),
+                     std::make_move_iterator(__from_first + __pair_mid),
+                     std::make_move_iterator(__from_first + __pair_mid),
+                     std::make_move_iterator(__from_first + __pair_last),
+                     __to_first + __pair_first,
+                     __comp);
+        }
+      });
+    };
+
+    if (__objects_are_in_buffer)
+      __merge_chunks(__values.get(), __first);
+    else
+      __merge_chunks(__first, __values.get());
+    __objects_are_in_buffer = !__objects_are_in_buffer;
+
+    __chunk_span_size *= 2;
+    __chunk_spans = __chunk_spans_pairs;
+  } while (__chunk_spans > 1);
+
+  if (__objects_are_in_buffer) {
+    std::move(__values.get(), __values.get() + __size, __first);
+  }
+
+  return __empty{};
+}
+
+} // namespace __statpart
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART__BASIS_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 87a1ef5ed8292f..153d67fc05d54d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2417,6 +2417,11 @@ module std {
         export std_core.utility_core.empty
       }
       module statpart {
+        module basis {
+          header "__pstl/backends/statpart/basis.h"
+        }
+      }
+      module statpart_old {
         header "__pstl/backends/statpart.h"
       }
       module std_thread {

>From 1b3a65f26b0161a438e52ba90a4e005ee457e953 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 13 Oct 2026 10:10:18 +0100
Subject: [PATCH 07/24] Moved find_end to a separate file

---
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__pstl/backends/statpart.h     |  58 +---------
 .../include/__pstl/backends/statpart/basis.h  |   6 +-
 .../__pstl/backends/statpart/find_end.h       | 102 ++++++++++++++++++
 libcxx/include/module.modulemap.in            |   3 +
 5 files changed, 110 insertions(+), 60 deletions(-)
 create mode 100644 libcxx/include/__pstl/backends/statpart/find_end.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 5b99cc3ba58565..c7830a12eaf009 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -697,6 +697,7 @@ set(files
   __pstl/backends/serial.h
   __pstl/backends/statpart.h  
   __pstl/backends/statpart/basis.h
+  __pstl/backends/statpart/find_end.h
   __pstl/backends/std_thread.h
   __pstl/cpu_algos/any_of.h
   __pstl/cpu_algos/cpu_traits.h
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index 788bb713c4fae6..1ac299caeae200 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___PSTL_STATPART_H
 
 #include <__pstl/backends/statpart/basis.h>
+#include <__pstl/backends/statpart/find_end.h>
 
 #include <__algorithm/find_end.h>
 #include <__algorithm/find_if.h>
@@ -73,63 +74,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl {
 
-template <class _ExecutionPolicy>
-struct __find_end<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
-  operator()(_Policy&&,
-             _ForwardIterator1 __first1,
-             _ForwardIterator1 __last1,
-             _ForwardIterator2 __first2,
-             _ForwardIterator2 __last2,
-             _BinaryPredicate __pred) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
-      typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
-      _DifferenceType __size2 = __last2 - __first2; // The length of the needle to search for.
-      if (__size2 == 0) {
-        return __last1; // If the needle length is zero, the last iterator is returned.
-      }
-      _DifferenceType __size1 = __last1 - __first1;
-      if (__size1 < __size2) {
-        return __last1; // The range is too small to contain the requested number of consecutive elements.
-      }
-      // Calculate the length of the tail where a potential match cannot start by definition.
-      _DifferenceType __crop = __size2 - 1;
-      // We're only interested in the range where a potential match can start: [first, last - crop)
-      _ForwardIterator1 __last1_cropped = __last1 - __crop;
-      // Run a parallel chunked find_if, covering the range where a potential match can start.
-      auto __res = __statpart::__find(
-          __first1,
-          __last1_cropped,
-          [__first2, __last2, __crop, &__pred](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
-            // Uncrop the range to allow std::find_end to find a full match, which can go beyond __brick_last.
-            _ForwardIterator1 __brick_last_uncropped = __brick_last + __crop;
-            // Run a serial std::find_end inside each of the chunks in parallel.
-            _ForwardIterator1 __ret = std::find_end(__brick_first, __brick_last_uncropped, __first2, __last2, __pred);
-            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
-            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __parallel_find().
-            return __ret == __brick_last_uncropped ? __brick_last : __ret;
-          },
-          greater<>{}, // `greater` here means the highest index among the matches
-          false        // `false` here means we want the last match, not the first
-      );
-      if (!__res) {
-        return std::nullopt; // Failed to run the algorithm, propagate the error.
-      }
-      if (*__res == __last1_cropped) {
-        return __last1; // No match was found in the range.
-      }
-      return *__res; // Return the successful match.
-    } else {
-      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
-      return std::find_end(
-          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
-    }
-  }
-};
-
 template <class _ExecutionPolicy>
 struct __for_each<__statpart_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Function>
diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
index 709eee0504bc4e..75dc2a5e159dcf 100644
--- a/libcxx/include/__pstl/backends/statpart/basis.h
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART__BASIS_H
-#define _LIBCPP___PSTL_STATPART__BASIS_H
+#ifndef _LIBCPP___PSTL_STATPART_BASIS_H
+#define _LIBCPP___PSTL_STATPART_BASIS_H
 
 #include <__algorithm/lower_bound.h>
 #include <__algorithm/merge.h>
@@ -491,4 +491,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART__BASIS_H
+#endif // _LIBCPP___PSTL_STATPART_BASIS_H
diff --git a/libcxx/include/__pstl/backends/statpart/find_end.h b/libcxx/include/__pstl/backends/statpart/find_end.h
new file mode 100644
index 00000000000000..2f022024077258
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/find_end.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_FIND_END_H
+#define _LIBCPP___PSTL_STATPART_FIND_END_H
+
+#include <__algorithm/find_end.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __find_end<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _BinaryPredicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
+      _DifferenceType __size2 = __last2 - __first2; // The length of the needle to search for.
+      if (__size2 == 0) {
+        return __last1; // If the needle length is zero, the last iterator is returned.
+      }
+      _DifferenceType __size1 = __last1 - __first1;
+      if (__size1 < __size2) {
+        return __last1; // The range is too small to contain the requested number of consecutive elements.
+      }
+      // Calculate the length of the tail where a potential match cannot start by definition.
+      _DifferenceType __crop = __size2 - 1;
+      // We're only interested in the range where a potential match can start: [first, last - crop)
+      _ForwardIterator1 __last1_cropped = __last1 - __crop;
+      // Run a parallel chunked find_if, covering the range where a potential match can start.
+      auto __res = __statpart::__find(
+          __first1,
+          __last1_cropped,
+          [__first2, __last2, __crop, &__pred](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+            // Uncrop the range to allow std::find_end to find a full match, which can go beyond __brick_last.
+            _ForwardIterator1 __brick_last_uncropped = __brick_last + __crop;
+            // Run a serial std::find_end inside each of the chunks in parallel.
+            _ForwardIterator1 __ret = std::find_end(__brick_first, __brick_last_uncropped, __first2, __last2, __pred);
+            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
+            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __parallel_find().
+            return __ret == __brick_last_uncropped ? __brick_last : __ret;
+          },
+          greater<>{}, // `greater` here means the highest index among the matches
+          false        // `false` here means we want the last match, not the first
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (*__res == __last1_cropped) {
+        return __last1; // No match was found in the range.
+      }
+      return *__res; // Return the successful match.
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::find_end(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_FIND_END_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 153d67fc05d54d..dfe7eea64cb542 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2420,6 +2420,9 @@ module std {
         module basis {
           header "__pstl/backends/statpart/basis.h"
         }
+        module find_end {
+          header "__pstl/backends/statpart/find_end.h"
+        }
       }
       module statpart_old {
         header "__pstl/backends/statpart.h"

>From f7d7832ca578ff66e1bbb2edaa638813b2db878e Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 13 Oct 2026 11:09:16 +0100
Subject: [PATCH 08/24] Reorg

---
 libcxx/include/CMakeLists.txt                 |   4 +
 libcxx/include/__pstl/backends/statpart.h     | 147 +-----------------
 .../__pstl/backends/statpart/find_if.h        |  67 ++++++++
 .../__pstl/backends/statpart/for_each.h       |  63 ++++++++
 .../__pstl/backends/statpart/is_heap_until.h  | 105 +++++++++++++
 .../include/__pstl/backends/statpart/merge.h  |  88 +++++++++++
 libcxx/include/module.modulemap.in            |  14 +-
 7 files changed, 343 insertions(+), 145 deletions(-)
 create mode 100644 libcxx/include/__pstl/backends/statpart/find_if.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/for_each.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/is_heap_until.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/merge.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index c7830a12eaf009..2edea9fad38c61 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -698,6 +698,10 @@ set(files
   __pstl/backends/statpart.h  
   __pstl/backends/statpart/basis.h
   __pstl/backends/statpart/find_end.h
+  __pstl/backends/statpart/find_if.h
+  __pstl/backends/statpart/for_each.h
+  __pstl/backends/statpart/is_heap_until.h
+  __pstl/backends/statpart/merge.h
   __pstl/backends/std_thread.h
   __pstl/cpu_algos/any_of.h
   __pstl/cpu_algos/cpu_traits.h
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index 1ac299caeae200..5396380a9c51da 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -11,6 +11,10 @@
 
 #include <__pstl/backends/statpart/basis.h>
 #include <__pstl/backends/statpart/find_end.h>
+#include <__pstl/backends/statpart/find_if.h>
+#include <__pstl/backends/statpart/for_each.h>
+#include <__pstl/backends/statpart/is_heap_until.h>
+#include <__pstl/backends/statpart/merge.h>
 
 #include <__algorithm/find_end.h>
 #include <__algorithm/find_if.h>
@@ -74,149 +78,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl {
 
-template <class _ExecutionPolicy>
-struct __for_each<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator, class _Function>
-  _LIBCPP_HIDE_FROM_ABI optional<__empty>
-  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __func) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-      return __statpart::__for_each(
-          std::move(__first), std::move(__last), [&](auto __partition_first, auto __partition_last) {
-            std::for_each(__partition_first, __partition_last, __func);
-          });
-    } else {
-      std::for_each(std::move(__first), std::move(__last), std::move(__func));
-      return __empty{};
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __find_if<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator, class _Predicate>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
-  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-      return __statpart::__find(
-          std::move(__first),
-          std::move(__last),
-          [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
-            return std::find_if(__brick_first, __brick_last, __pred);
-          },
-          less<>{},
-          true);
-    } else {
-      return std::find_if(std::move(__first), std::move(__last), std::move(__pred));
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __is_heap_until<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _RandomAccessIterator, class _Comp>
-  _LIBCPP_HIDE_FROM_ABI optional<_RandomAccessIterator>
-  operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
-      if (__last - __first < 2)
-        return __last; // Any sequence with less than 2 elements is a heap
-      // Run a parallel find in chunks over [first+1, last) to validate every element except the root.
-      return __statpart::__find(
-          __first + 1,
-          __last,
-          [__first, &__comp](_RandomAccessIterator __child_first, _RandomAccessIterator __child_last) {
-            // This algorithm assumes that __find() will never pass an empty brick,
-            // i.e. that __child_first != __child_last.
-            using _DifferenceType = typename std::iterator_traits<_RandomAccessIterator>::difference_type;
-
-            // Derive the indices of the children and the iterators of their parents
-            _DifferenceType __child_first_idx   = __child_first - __first;
-            _DifferenceType __child_last_idx    = __child_last - __first;
-            _RandomAccessIterator __parent      = __first + (__child_first_idx - 1) / 2;
-            _RandomAccessIterator __parent_last = __first + (__child_last_idx - 1) / 2;
-
-            // If we're starting from a right child => process this element separately in a prologue
-            if (__child_first_idx % 2 == 0) {
-              if (__comp(*__parent, *__child_first)) // Check the right child
-                return __child_first;
-              ++__parent;
-              ++__child_first;
-            }
-
-            // Iterate over the parents and check their left and right children
-            for (; __parent != __parent_last; ++__parent) {
-              if (__comp(*__parent, *__child_first)) // Check the left child
-                return __child_first;
-              ++__child_first;
-
-              if (__comp(*__parent, *__child_first)) // Check the right child
-                return __child_first;
-              ++__child_first;
-            }
-
-            // If we're ending with a right child => __parent_last also includes the left child.
-            // Process this accessible element separately in an epilogue.
-            if (__child_last_idx % 2 == 0) {
-              if (__comp(*__parent, *__child_first)) // Check the left child
-                return __child_first;
-            }
-
-            return __child_last; // No violations found in this brick
-          },
-          less<>{}, // `less` here means the lowest index among the matches
-          true      // `true` here means we want the first match, not the last
-      );
-    } else {
-      return std::is_heap_until(std::move(__first), std::move(__last), std::move(__comp));
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __merge<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardOutIterator, class _Comp>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> operator()(
-      _Policy&&,
-      _ForwardIterator1 __first1,
-      _ForwardIterator1 __last1,
-      _ForwardIterator2 __first2,
-      _ForwardIterator2 __last2,
-      _ForwardOutIterator __result,
-      _Comp __comp) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
-      auto __res = __statpart::__merge(
-          __first1,
-          __last1,
-          __first2,
-          __last2,
-          __result,
-          __comp,
-          [](_ForwardIterator1 __brick_first1,
-             _ForwardIterator1 __brick_last1,
-             _ForwardIterator2 __brick_first2,
-             _ForwardIterator2 __brick_last2,
-             _ForwardOutIterator __brick_result,
-             _Comp __g_comp) {
-            std::merge(std::move(__brick_first1),
-                       std::move(__brick_last1),
-                       std::move(__brick_first2),
-                       std::move(__brick_last2),
-                       std::move(__brick_result),
-                       std::move(__g_comp));
-          });
-      if (!__res)
-        return nullopt;
-      return __result + (__last1 - __first1) + (__last2 - __first2);
-    } else {
-      return std::merge(__first1, __last1, __first2, __last2, __result, __comp);
-    }
-  }
-};
-
 template <class _ExecutionPolicy>
 struct __min_element<__statpart_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Compare>
diff --git a/libcxx/include/__pstl/backends/statpart/find_if.h b/libcxx/include/__pstl/backends/statpart/find_if.h
new file mode 100644
index 00000000000000..c7273a75e54bba
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/find_if.h
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_FIND_IF_H
+#define _LIBCPP___PSTL_STATPART_FIND_IF_H
+
+#include <__algorithm/find_if.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __find_if<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__find(
+          std::move(__first),
+          std::move(__last),
+          [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            return std::find_if(__brick_first, __brick_last, __pred);
+          },
+          less<>{},
+          true);
+    } else {
+      return std::find_if(std::move(__first), std::move(__last), std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_FIND_IF_H
diff --git a/libcxx/include/__pstl/backends/statpart/for_each.h b/libcxx/include/__pstl/backends/statpart/for_each.h
new file mode 100644
index 00000000000000..b2199a828cb185
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/for_each.h
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_FOR_EACH_H
+#define _LIBCPP___PSTL_STATPART_FOR_EACH_H
+
+#include <__algorithm/for_each.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __for_each<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Function>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __func) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__for_each(
+          std::move(__first), std::move(__last), [&](auto __partition_first, auto __partition_last) {
+            std::for_each(__partition_first, __partition_last, __func);
+          });
+    } else {
+      std::for_each(std::move(__first), std::move(__last), std::move(__func));
+      return __empty{};
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_FOR_EACH_H
diff --git a/libcxx/include/__pstl/backends/statpart/is_heap_until.h b/libcxx/include/__pstl/backends/statpart/is_heap_until.h
new file mode 100644
index 00000000000000..88e0c11de11a2e
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/is_heap_until.h
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_IS_HEAP_UNTIL_H
+#define _LIBCPP___PSTL_STATPART_IS_HEAP_UNTIL_H
+
+#include <__algorithm/is_heap_until.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __is_heap_until<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _RandomAccessIterator, class _Comp>
+  _LIBCPP_HIDE_FROM_ABI optional<_RandomAccessIterator>
+  operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
+      if (__last - __first < 2)
+        return __last; // Any sequence with less than 2 elements is a heap
+      // Run a parallel find in chunks over [first+1, last) to validate every element except the root.
+      return __statpart::__find(
+          __first + 1,
+          __last,
+          [__first, &__comp](_RandomAccessIterator __child_first, _RandomAccessIterator __child_last) {
+            // This algorithm assumes that __find() will never pass an empty brick,
+            // i.e. that __child_first != __child_last.
+            using _DifferenceType = typename std::iterator_traits<_RandomAccessIterator>::difference_type;
+
+            // Derive the indices of the children and the iterators of their parents
+            _DifferenceType __child_first_idx   = __child_first - __first;
+            _DifferenceType __child_last_idx    = __child_last - __first;
+            _RandomAccessIterator __parent      = __first + (__child_first_idx - 1) / 2;
+            _RandomAccessIterator __parent_last = __first + (__child_last_idx - 1) / 2;
+
+            // If we're starting from a right child => process this element separately in a prologue
+            if (__child_first_idx % 2 == 0) {
+              if (__comp(*__parent, *__child_first)) // Check the right child
+                return __child_first;
+              ++__parent;
+              ++__child_first;
+            }
+
+            // Iterate over the parents and check their left and right children
+            for (; __parent != __parent_last; ++__parent) {
+              if (__comp(*__parent, *__child_first)) // Check the left child
+                return __child_first;
+              ++__child_first;
+
+              if (__comp(*__parent, *__child_first)) // Check the right child
+                return __child_first;
+              ++__child_first;
+            }
+
+            // If we're ending with a right child => __parent_last also includes the left child.
+            // Process this accessible element separately in an epilogue.
+            if (__child_last_idx % 2 == 0) {
+              if (__comp(*__parent, *__child_first)) // Check the left child
+                return __child_first;
+            }
+
+            return __child_last; // No violations found in this brick
+          },
+          less<>{}, // `less` here means the lowest index among the matches
+          true      // `true` here means we want the first match, not the last
+      );
+    } else {
+      return std::is_heap_until(std::move(__first), std::move(__last), std::move(__comp));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_IS_HEAP_UNTIL_H
diff --git a/libcxx/include/__pstl/backends/statpart/merge.h b/libcxx/include/__pstl/backends/statpart/merge.h
new file mode 100644
index 00000000000000..bd9ef68d413a26
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/merge.h
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_MERGE_H
+#define _LIBCPP___PSTL_STATPART_MERGE_H
+
+#include <__algorithm/merge.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __merge<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardOutIterator, class _Comp>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> operator()(
+      _Policy&&,
+      _ForwardIterator1 __first1,
+      _ForwardIterator1 __last1,
+      _ForwardIterator2 __first2,
+      _ForwardIterator2 __last2,
+      _ForwardOutIterator __result,
+      _Comp __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      auto __res = __statpart::__merge(
+          __first1,
+          __last1,
+          __first2,
+          __last2,
+          __result,
+          __comp,
+          [](_ForwardIterator1 __brick_first1,
+             _ForwardIterator1 __brick_last1,
+             _ForwardIterator2 __brick_first2,
+             _ForwardIterator2 __brick_last2,
+             _ForwardOutIterator __brick_result,
+             _Comp __g_comp) {
+            std::merge(std::move(__brick_first1),
+                       std::move(__brick_last1),
+                       std::move(__brick_first2),
+                       std::move(__brick_last2),
+                       std::move(__brick_result),
+                       std::move(__g_comp));
+          });
+      if (!__res)
+        return nullopt;
+      return __result + (__last1 - __first1) + (__last2 - __first2);
+    } else {
+      return std::merge(__first1, __last1, __first2, __last2, __result, __comp);
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_MERGE_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index dfe7eea64cb542..30450755d9fad6 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2423,8 +2423,18 @@ module std {
         module find_end {
           header "__pstl/backends/statpart/find_end.h"
         }
-      }
-      module statpart_old {
+        module find_if {
+          header "__pstl/backends/statpart/find_if.h"
+        }
+        module for_each {
+          header "__pstl/backends/statpart/for_each.h"
+        }
+        module is_heap_until {
+          header "__pstl/backends/statpart/is_heap_until.h"
+        }
+        module merge {
+          header "__pstl/backends/statpart/merge.h"
+        }
         header "__pstl/backends/statpart.h"
       }
       module std_thread {

>From 7d328ddb9b6ccaee45d714b7419064bd41372c2d Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 13 Oct 2026 11:39:13 +0100
Subject: [PATCH 09/24] Reorg

---
 libcxx/include/CMakeLists.txt                 |   3 +
 libcxx/include/__pstl/backends/statpart.h     | 134 +-----------------
 .../__pstl/backends/statpart/min_element.h    |  85 +++++++++++
 .../__pstl/backends/statpart/minmax_element.h |  90 ++++++++++++
 .../__pstl/backends/statpart/mismatch.h       |  91 ++++++++++++
 libcxx/include/module.modulemap.in            |   9 ++
 6 files changed, 281 insertions(+), 131 deletions(-)
 create mode 100644 libcxx/include/__pstl/backends/statpart/min_element.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/minmax_element.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/mismatch.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 2edea9fad38c61..629488639a88f2 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -702,6 +702,9 @@ set(files
   __pstl/backends/statpart/for_each.h
   __pstl/backends/statpart/is_heap_until.h
   __pstl/backends/statpart/merge.h
+  __pstl/backends/statpart/min_element.h
+  __pstl/backends/statpart/minmax_element.h
+  __pstl/backends/statpart/mismatch.h
   __pstl/backends/std_thread.h
   __pstl/cpu_algos/any_of.h
   __pstl/cpu_algos/cpu_traits.h
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index 5396380a9c51da..101f6e536d5346 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -15,6 +15,9 @@
 #include <__pstl/backends/statpart/for_each.h>
 #include <__pstl/backends/statpart/is_heap_until.h>
 #include <__pstl/backends/statpart/merge.h>
+#include <__pstl/backends/statpart/min_element.h>
+#include <__pstl/backends/statpart/minmax_element.h>
+#include <__pstl/backends/statpart/mismatch.h>
 
 #include <__algorithm/find_end.h>
 #include <__algorithm/find_if.h>
@@ -78,137 +81,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl {
 
-template <class _ExecutionPolicy>
-struct __min_element<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator, class _Compare>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
-  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-      if (__first == __last) {
-        return __last; // nothing to do
-      }
-
-      _ForwardIterator __init = __first;
-      ++__first;
-      if (__first == __last) {
-        return __init; // the only element is the minimum
-      }
-
-      // A reduction that returns an iterator pointing to the lowest element, left bias in case of a tie
-      auto __iter_reduce = [&__comp](_ForwardIterator __lhs, _ForwardIterator __rhs) {
-        return __comp(*__rhs, *__lhs) ? __rhs : __lhs;
-      };
-
-      // Perform a parallel reduction of iterators [first+1, last) with 'first' as init.
-      return __statpart::__transform_reduce(
-          std::move(__first),
-          std::move(__last),
-          __identity{},      // No transformations
-          std::move(__init), // Use the first iterator as the init element
-          __iter_reduce,     // Reduction of 2 elements
-          [&__iter_reduce, &__comp](auto __brick_first, auto __brick_last, auto __brick_init) {
-            // Reduction of an iterator range + init element: use the serial version to find the minimum among
-            // the iterators and then reduce with the init element.
-            return __iter_reduce(__brick_init, std::min_element(__brick_first, __brick_last, __comp));
-          });
-    } else {
-      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
-      return std::min_element(std::move(__first), std::move(__last), std::move(__comp));
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __minmax_element<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator, class _Compare>
-  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator, _ForwardIterator>>
-  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-      using _IterPair = pair<_ForwardIterator, _ForwardIterator>;
-
-      if (__first == __last) {
-        return _IterPair{__last, __last}; // Nothing to do
-      }
-
-      _IterPair __init = {__first, __first};
-      ++__first;
-      if (__first == __last) {
-        return __init; // The only element is both the minimum and the maximum
-      }
-
-      // A reduction that returns a pair of iterators pointing to the minimum and maximum elements.
-      // In a case of a tie the minimum iterators are biased left and the maximum iterators are biased right.
-      auto __iter_reduce = [&__comp](_IterPair __lhs, _IterPair __rhs) {
-        return _IterPair{__comp(*__rhs.first, *__lhs.first) ? __rhs.first : __lhs.first,
-                         __comp(*__rhs.second, *__lhs.second) ? __lhs.second : __rhs.second};
-      };
-
-      // Perform a parallel reduction of iterators [first+1, last) with {first, first} as init.
-      return __statpart::__transform_reduce(
-          std::move(__first),
-          std::move(__last),
-          [](auto __it) { return _IterPair{__it, __it}; }, // Transform an iterator into an iterator pair
-          std::move(__init),                               // Use the pair of first iterators as the init element
-          __iter_reduce,                                   // Reduction of 2 minmax pairs
-          [&__iter_reduce, &__comp](auto __brick_first, auto __brick_last, auto __brick_init) {
-            // Reduction of an iterator range + init element: use the serial version to find the minmax among
-            // the iterators and then reduce it with the init element.
-            return __iter_reduce(__brick_init, std::minmax_element(__brick_first, __brick_last, __comp));
-          });
-    } else {
-      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
-      return std::minmax_element(std::move(__first), std::move(__last), std::move(__comp));
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __mismatch<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
-  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator1, _ForwardIterator2>>
-  operator()(_Policy&&,
-             _ForwardIterator1 __first1,
-             _ForwardIterator1 __last1,
-             _ForwardIterator2 __first2,
-             _ForwardIterator2 __last2,
-             _Predicate __pred) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
-      // Look for a mismatch only in the prefix of the two ranges.
-      auto __n = std::min(__last1 - __first1, __last2 - __first2);
-      // Find a position in the first range where the predicate is false against the corresponding position in the
-      // second range.
-      auto __res = __statpart::__find(
-          __first1,
-          __first1 + __n,
-          [&__pred, __first1, __first2](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1) {
-            // Run the sequential mismatch algorithm on these ranges:
-            //   [__brick_first1, __brick_last1) and
-            //   [__first2 + (__brick_first1 - __first1), __first2 + (__brick_last1 - __first1))
-            auto __brick_first2 = __first2 + (__brick_first1 - __first1);
-            return std::mismatch(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2), __pred)
-                .first;
-          },
-          less<>{}, // `less` here means the lowest index among the mismatches
-          true      // `true` here means we want the first mismatch, not the last
-      );
-      if (!__res) {
-        return std::nullopt; // Failed to run the algorithm, propagate the error.
-      }
-      auto __idx = *__res - __first1;
-      return pair<_ForwardIterator1, _ForwardIterator2>{std::move(*__res), __first2 + __idx};
-    } else {
-      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
-      // Unsequenced execution is also implicitly covered by the sequential implementation.
-      return std::mismatch(
-          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
-    }
-  }
-};
-
 template <class _ExecutionPolicy>
 struct __reverse<__statpart_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _BidirectionalIterator>
diff --git a/libcxx/include/__pstl/backends/statpart/min_element.h b/libcxx/include/__pstl/backends/statpart/min_element.h
new file mode 100644
index 00000000000000..09e3117c81d475
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/min_element.h
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_MIN_ELEMENT_H
+#define _LIBCPP___PSTL_STATPART_MIN_ELEMENT_H
+
+#include <__algorithm/min_element.h>
+#include <__config>
+#include <__functional/identity.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __min_element<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Compare>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      if (__first == __last) {
+        return __last; // nothing to do
+      }
+
+      _ForwardIterator __init = __first;
+      ++__first;
+      if (__first == __last) {
+        return __init; // the only element is the minimum
+      }
+
+      // A reduction that returns an iterator pointing to the lowest element, left bias in case of a tie
+      auto __iter_reduce = [&__comp](_ForwardIterator __lhs, _ForwardIterator __rhs) {
+        return __comp(*__rhs, *__lhs) ? __rhs : __lhs;
+      };
+
+      // Perform a parallel reduction of iterators [first+1, last) with 'first' as init.
+      return __statpart::__transform_reduce(
+          std::move(__first),
+          std::move(__last),
+          __identity{},      // No transformations
+          std::move(__init), // Use the first iterator as the init element
+          __iter_reduce,     // Reduction of 2 elements
+          [&__iter_reduce, &__comp](auto __brick_first, auto __brick_last, auto __brick_init) {
+            // Reduction of an iterator range + init element: use the serial version to find the minimum among
+            // the iterators and then reduce with the init element.
+            return __iter_reduce(__brick_init, std::min_element(__brick_first, __brick_last, __comp));
+          });
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::min_element(std::move(__first), std::move(__last), std::move(__comp));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_MIN_ELEMENT_H
diff --git a/libcxx/include/__pstl/backends/statpart/minmax_element.h b/libcxx/include/__pstl/backends/statpart/minmax_element.h
new file mode 100644
index 00000000000000..bde4bb515999b4
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/minmax_element.h
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_MINMAX_ELEMENT_H
+#define _LIBCPP___PSTL_STATPART_MINMAX_ELEMENT_H
+
+#include <__algorithm/minmax_element.h>
+#include <__config>
+#include <__functional/identity.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.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>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __minmax_element<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Compare>
+  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator, _ForwardIterator>>
+  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      using _IterPair = pair<_ForwardIterator, _ForwardIterator>;
+
+      if (__first == __last) {
+        return _IterPair{__last, __last}; // Nothing to do
+      }
+
+      _IterPair __init = {__first, __first};
+      ++__first;
+      if (__first == __last) {
+        return __init; // The only element is both the minimum and the maximum
+      }
+
+      // A reduction that returns a pair of iterators pointing to the minimum and maximum elements.
+      // In a case of a tie the minimum iterators are biased left and the maximum iterators are biased right.
+      auto __iter_reduce = [&__comp](_IterPair __lhs, _IterPair __rhs) {
+        return _IterPair{__comp(*__rhs.first, *__lhs.first) ? __rhs.first : __lhs.first,
+                         __comp(*__rhs.second, *__lhs.second) ? __lhs.second : __rhs.second};
+      };
+
+      // Perform a parallel reduction of iterators [first+1, last) with {first, first} as init.
+      return __statpart::__transform_reduce(
+          std::move(__first),
+          std::move(__last),
+          [](auto __it) { return _IterPair{__it, __it}; }, // Transform an iterator into an iterator pair
+          std::move(__init),                               // Use the pair of first iterators as the init element
+          __iter_reduce,                                   // Reduction of 2 minmax pairs
+          [&__iter_reduce, &__comp](auto __brick_first, auto __brick_last, auto __brick_init) {
+            // Reduction of an iterator range + init element: use the serial version to find the minmax among
+            // the iterators and then reduce it with the init element.
+            return __iter_reduce(__brick_init, std::minmax_element(__brick_first, __brick_last, __comp));
+          });
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::minmax_element(std::move(__first), std::move(__last), std::move(__comp));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_MINMAX_ELEMENT_H
diff --git a/libcxx/include/__pstl/backends/statpart/mismatch.h b/libcxx/include/__pstl/backends/statpart/mismatch.h
new file mode 100644
index 00000000000000..b049b690e12bf8
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/mismatch.h
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_MISMATCH_H
+#define _LIBCPP___PSTL_STATPART_MISMATCH_H
+
+#include <__algorithm/min.h>
+#include <__algorithm/mismatch.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.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>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __mismatch<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator1, _ForwardIterator2>>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      // Look for a mismatch only in the prefix of the two ranges.
+      auto __n = std::min(__last1 - __first1, __last2 - __first2);
+      // Find a position in the first range where the predicate is false against the corresponding position in the
+      // second range.
+      auto __res = __statpart::__find(
+          __first1,
+          __first1 + __n,
+          [&__pred, __first1, __first2](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1) {
+            // Run the sequential mismatch algorithm on these ranges:
+            //   [__brick_first1, __brick_last1) and
+            //   [__first2 + (__brick_first1 - __first1), __first2 + (__brick_last1 - __first1))
+            auto __brick_first2 = __first2 + (__brick_first1 - __first1);
+            return std::mismatch(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2), __pred)
+                .first;
+          },
+          less<>{}, // `less` here means the lowest index among the mismatches
+          true      // `true` here means we want the first mismatch, not the last
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      auto __idx = *__res - __first1;
+      return pair<_ForwardIterator1, _ForwardIterator2>{std::move(*__res), __first2 + __idx};
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      // Unsequenced execution is also implicitly covered by the sequential implementation.
+      return std::mismatch(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_MISMATCH_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 30450755d9fad6..a33e9441270119 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2435,6 +2435,15 @@ module std {
         module merge {
           header "__pstl/backends/statpart/merge.h"
         }
+        module min_element {
+          header "__pstl/backends/statpart/min_element.h"
+        }
+        module minmax_element {
+          header "__pstl/backends/statpart/minmax_element.h"
+        }
+        module mismatch {
+          header "__pstl/backends/statpart/mismatch.h"
+        }
         header "__pstl/backends/statpart.h"
       }
       module std_thread {

>From 45fec3699dd64df560d4457a9faa5952833b3797 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 13 Oct 2026 11:54:45 +0100
Subject: [PATCH 10/24] Reorg

---
 libcxx/include/CMakeLists.txt                 |   2 +
 libcxx/include/__pstl/backends/statpart.h     |  87 +--------------
 .../__pstl/backends/statpart/reverse.h        |  75 +++++++++++++
 .../include/__pstl/backends/statpart/search.h | 102 ++++++++++++++++++
 libcxx/include/module.modulemap.in            |   6 ++
 5 files changed, 187 insertions(+), 85 deletions(-)
 create mode 100644 libcxx/include/__pstl/backends/statpart/reverse.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/search.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 629488639a88f2..1da365a5bd0909 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -705,6 +705,8 @@ set(files
   __pstl/backends/statpart/min_element.h
   __pstl/backends/statpart/minmax_element.h
   __pstl/backends/statpart/mismatch.h
+  __pstl/backends/statpart/reverse.h
+  __pstl/backends/statpart/search.h
   __pstl/backends/std_thread.h
   __pstl/cpu_algos/any_of.h
   __pstl/cpu_algos/cpu_traits.h
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index 101f6e536d5346..ff9abb66477917 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -18,6 +18,8 @@
 #include <__pstl/backends/statpart/min_element.h>
 #include <__pstl/backends/statpart/minmax_element.h>
 #include <__pstl/backends/statpart/mismatch.h>
+#include <__pstl/backends/statpart/reverse.h>
+#include <__pstl/backends/statpart/search.h>
 
 #include <__algorithm/find_end.h>
 #include <__algorithm/find_if.h>
@@ -81,91 +83,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl {
 
-template <class _ExecutionPolicy>
-struct __reverse<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _BidirectionalIterator>
-  _LIBCPP_HIDE_FROM_ABI optional<__empty>
-  operator()(_Policy&&, _BidirectionalIterator __first, _BidirectionalIterator __last) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_BidirectionalIterator>::value) {
-      // Perform a chunked for_each on the first half of the range.
-      // Odd-sized ranges will leave the middle element untouched, which is correct for this algorithm:
-      // its reversed position is the same.
-      auto __n = (__last - __first) / 2;
-      return __statpart::__for_each(
-          __first, __first + __n, [__first, __last](_BidirectionalIterator __i, _BidirectionalIterator __j) {
-            // Derive the last position of the mirrored range by counting from the end.
-            _BidirectionalIterator __mirror_last = __last - (__i - __first);
-            // Swap the elements in the range of the first half with their mirrored counterparts in the second half.
-            std::swap_ranges(std::move(__i),
-                             std::move(__j),
-                             std::reverse_iterator<_BidirectionalIterator>(std::move(__mirror_last)));
-          });
-    } else {
-      // Non-random access iterators currently cannot be processed in parallel, use the sequential implementation.
-      std::reverse(std::move(__first), std::move(__last));
-      return __empty{};
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __search<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
-  operator()(_Policy&&,
-             _ForwardIterator1 __first1,
-             _ForwardIterator1 __last1,
-             _ForwardIterator2 __first2,
-             _ForwardIterator2 __last2,
-             _BinaryPredicate __pred) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
-      typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
-      _DifferenceType __size2 = __last2 - __first2; // The length of the needle to search for.
-      if (__size2 == 0) {
-        return __first1; // If the needle length is zero, the first iterator is returned.
-      }
-      _DifferenceType __size1 = __last1 - __first1;
-      if (__size1 < __size2) {
-        return __last1; // The range is too small to contain the requested number of consecutive elements.
-      }
-      // Calculate the length of the tail where a potential match cannot start by definition.
-      _DifferenceType __crop = __size2 - 1;
-      // We're only interested in the range where a potential match can start: [first, last - crop)
-      _ForwardIterator1 __last1_cropped = __last1 - __crop;
-      // Run a parallel chunked find_if, covering the range where a potential match can start.
-      auto __res = __statpart::__find(
-          __first1,
-          __last1_cropped,
-          [__first2, __last2, __crop, &__pred](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
-            // Uncrop the range to allow std::search to find a full match, which can go beyond __brick_last.
-            _ForwardIterator1 __brick_last_uncropped = __brick_last + __crop;
-            // Run a serial std::search inside each of the chunks in parallel.
-            _ForwardIterator1 __ret = std::search(__brick_first, __brick_last_uncropped, __first2, __last2, __pred);
-            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
-            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __find().
-            return __ret == __brick_last_uncropped ? __brick_last : __ret;
-          },
-          less<>{}, // `less` here means the lowest index among the matches
-          true      // `true` here means we want the first match, not the last
-      );
-      if (!__res) {
-        return std::nullopt; // Failed to run the algorithm, propagate the error.
-      }
-      if (*__res == __last1_cropped) {
-        return __last1; // No match was found in the range.
-      }
-      return *__res; // Return the successful match.
-    } else {
-      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
-      return std::search(
-          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
-    }
-  }
-};
-
 template <class _ExecutionPolicy>
 struct __search_n<__statpart_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Size, class _Tp, class _Predicate>
diff --git a/libcxx/include/__pstl/backends/statpart/reverse.h b/libcxx/include/__pstl/backends/statpart/reverse.h
new file mode 100644
index 00000000000000..4e3d147475568b
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/reverse.h
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_REVERSE_H
+#define _LIBCPP___PSTL_STATPART_REVERSE_H
+
+#include <__algorithm/reverse.h>
+#include <__algorithm/swap_ranges.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/reverse_iterator.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __reverse<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _BidirectionalIterator>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&&, _BidirectionalIterator __first, _BidirectionalIterator __last) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_BidirectionalIterator>::value) {
+      // Perform a chunked for_each on the first half of the range.
+      // Odd-sized ranges will leave the middle element untouched, which is correct for this algorithm:
+      // its reversed position is the same.
+      auto __n = (__last - __first) / 2;
+      return __statpart::__for_each(
+          __first, __first + __n, [__first, __last](_BidirectionalIterator __i, _BidirectionalIterator __j) {
+            // Derive the last position of the mirrored range by counting from the end.
+            _BidirectionalIterator __mirror_last = __last - (__i - __first);
+            // Swap the elements in the range of the first half with their mirrored counterparts in the second half.
+            std::swap_ranges(std::move(__i),
+                             std::move(__j),
+                             std::reverse_iterator<_BidirectionalIterator>(std::move(__mirror_last)));
+          });
+    } else {
+      // Non-random access iterators currently cannot be processed in parallel, use the sequential implementation.
+      std::reverse(std::move(__first), std::move(__last));
+      return __empty{};
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_REVERSE_H
diff --git a/libcxx/include/__pstl/backends/statpart/search.h b/libcxx/include/__pstl/backends/statpart/search.h
new file mode 100644
index 00000000000000..a831fb8ef63d0e
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/search.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_SEARCH_H
+#define _LIBCPP___PSTL_STATPART_SEARCH_H
+
+#include <__algorithm/search.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __search<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _BinaryPredicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      typedef typename std::iterator_traits<_ForwardIterator1>::difference_type _DifferenceType;
+      _DifferenceType __size2 = __last2 - __first2; // The length of the needle to search for.
+      if (__size2 == 0) {
+        return __first1; // If the needle length is zero, the first iterator is returned.
+      }
+      _DifferenceType __size1 = __last1 - __first1;
+      if (__size1 < __size2) {
+        return __last1; // The range is too small to contain the requested number of consecutive elements.
+      }
+      // Calculate the length of the tail where a potential match cannot start by definition.
+      _DifferenceType __crop = __size2 - 1;
+      // We're only interested in the range where a potential match can start: [first, last - crop)
+      _ForwardIterator1 __last1_cropped = __last1 - __crop;
+      // Run a parallel chunked find_if, covering the range where a potential match can start.
+      auto __res = __statpart::__find(
+          __first1,
+          __last1_cropped,
+          [__first2, __last2, __crop, &__pred](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+            // Uncrop the range to allow std::search to find a full match, which can go beyond __brick_last.
+            _ForwardIterator1 __brick_last_uncropped = __brick_last + __crop;
+            // Run a serial std::search inside each of the chunks in parallel.
+            _ForwardIterator1 __ret = std::search(__brick_first, __brick_last_uncropped, __first2, __last2, __pred);
+            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
+            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __find().
+            return __ret == __brick_last_uncropped ? __brick_last : __ret;
+          },
+          less<>{}, // `less` here means the lowest index among the matches
+          true      // `true` here means we want the first match, not the last
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (*__res == __last1_cropped) {
+        return __last1; // No match was found in the range.
+      }
+      return *__res; // Return the successful match.
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::search(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_SEARCH_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index a33e9441270119..42b219a06ec8d3 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2444,6 +2444,12 @@ module std {
         module mismatch {
           header "__pstl/backends/statpart/mismatch.h"
         }
+        module reverse {
+          header "__pstl/backends/statpart/reverse.h"
+        }
+        module search {
+          header "__pstl/backends/statpart/search.h"
+        }
         header "__pstl/backends/statpart.h"
       }
       module std_thread {

>From eb220f8e97f99dd81c34718dab66d3ab13c50043 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 13 Oct 2026 15:19:02 +0100
Subject: [PATCH 11/24] Reorg

---
 libcxx/include/CMakeLists.txt                 |   4 +
 libcxx/include/__pstl/backends/statpart.h     | 161 +-----------------
 .../__pstl/backends/statpart/search_n.h       | 102 +++++++++++
 .../__pstl/backends/statpart/stable_sort.h    |  61 +++++++
 .../__pstl/backends/statpart/swap_ranges.h    |  70 ++++++++
 .../__pstl/backends/statpart/transform.h      | 102 +++++++++++
 libcxx/include/module.modulemap.in            |  12 ++
 7 files changed, 355 insertions(+), 157 deletions(-)
 create mode 100644 libcxx/include/__pstl/backends/statpart/search_n.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/stable_sort.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/swap_ranges.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/transform.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 1da365a5bd0909..f2657b9810faa0 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -707,6 +707,10 @@ set(files
   __pstl/backends/statpart/mismatch.h
   __pstl/backends/statpart/reverse.h
   __pstl/backends/statpart/search.h
+  __pstl/backends/statpart/search_n.h
+  __pstl/backends/statpart/stable_sort.h
+  __pstl/backends/statpart/swap_ranges.h
+  __pstl/backends/statpart/transform.h
   __pstl/backends/std_thread.h
   __pstl/cpu_algos/any_of.h
   __pstl/cpu_algos/cpu_traits.h
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index ff9abb66477917..61c484f91318f2 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -20,6 +20,10 @@
 #include <__pstl/backends/statpart/mismatch.h>
 #include <__pstl/backends/statpart/reverse.h>
 #include <__pstl/backends/statpart/search.h>
+#include <__pstl/backends/statpart/search_n.h>
+#include <__pstl/backends/statpart/stable_sort.h>
+#include <__pstl/backends/statpart/swap_ranges.h>
+#include <__pstl/backends/statpart/transform.h>
 
 #include <__algorithm/find_end.h>
 #include <__algorithm/find_if.h>
@@ -83,163 +87,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl {
 
-template <class _ExecutionPolicy>
-struct __search_n<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator, class _Size, class _Tp, class _Predicate>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
-  operator()(_Policy&&,
-             _ForwardIterator __first,
-             _ForwardIterator __last,
-             _Size __count,
-             const _Tp& __value,
-             _Predicate __pred) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-      typedef typename std::iterator_traits<_ForwardIterator>::difference_type _DifferenceType;
-      _DifferenceType __integral_count = std::__convert_to_integral(__count);
-      if (__integral_count <= 0) {
-        return __first; // If the count is non-positive, the first iterator is returned.
-      }
-      _DifferenceType __size = __last - __first;
-      if (__size < __integral_count) {
-        return __last; // The range is too small to contain the requested number of consecutive elements.
-      }
-      // Calculate the length of the tail where a potential match cannot start by definition.
-      _DifferenceType __crop = __integral_count - 1;
-      // We're only interested in the range where a potential match can start: [first, last - crop)
-      _ForwardIterator __last2 = __last - __crop;
-      // Run a parallel chunked find_if, covering the range where a potential match can start.
-      auto __res = __statpart::__find(
-          __first,
-          __last2,
-          [__integral_count, __crop, &__value, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
-            // Uncrop the range to allow std::search_n to find a full match, which can go beyond __brick_last.
-            _ForwardIterator __brick_last_uncropped = __brick_last + __crop;
-            // Run a serial std::search_n inside each of the chunks in parallel.
-            _ForwardIterator __ret =
-                std::search_n(__brick_first, __brick_last_uncropped, __integral_count, __value, __pred);
-            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
-            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __find().
-            return __ret == __brick_last_uncropped ? __brick_last : __ret;
-          },
-          less<>{}, // `less` here means the lowest index among the matches
-          true      // `true` here means we want the first match, not the last
-      );
-      if (!__res) {
-        return std::nullopt; // Failed to run the algorithm, propagate the error.
-      }
-      if (*__res == __last2) {
-        return __last; // No match was found in the range.
-      }
-      return *__res; // Return the successful match.
-    } else {
-      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
-      return std::search_n(std::move(__first), std::move(__last), __count, __value, std::move(__pred));
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __stable_sort<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _RandomAccessIterator, class _Comp>
-  _LIBCPP_HIDE_FROM_ABI optional<__empty>
-  operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
-      return __statpart::__stable_sort(
-          __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) {
-            std::stable_sort(__g_first, __g_last, __g_comp);
-          });
-    } else {
-      std::stable_sort(__first, __last, __comp);
-      return __empty{};
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __swap_ranges<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
-      _Policy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
-      auto __res = __statpart::__for_each_iter_pair(
-          __first1,
-          __last1,
-          __first2,
-          [](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1, _ForwardIterator2 __brick_first2) {
-            std::swap_ranges(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2));
-          });
-      if (!__res) {
-        return std::nullopt; // Failed to run the algorithm, propagate the error.
-      }
-      return __first2 + (__last1 - __first1);
-    } else {
-      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
-      return std::swap_ranges(std::move(__first1), std::move(__last1), std::move(__first2));
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __transform<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _UnaryOperation>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> operator()(
-      _Policy&&, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result, _UnaryOperation __op)
-      const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
-      __statpart::__for_each(
-          __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
-            return std::transform(__brick_first, __brick_last, __result + (__brick_first - __first), __op);
-          });
-      return __result + (__last - __first);
-    } else {
-      return std::transform(__first, __last, __result, __op);
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __transform_binary<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy,
-            class _ForwardIterator1,
-            class _ForwardIterator2,
-            class _ForwardOutIterator,
-            class _BinaryOperation>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
-  operator()(_Policy&&,
-             _ForwardIterator1 __first1,
-             _ForwardIterator1 __last1,
-             _ForwardIterator2 __first2,
-             _ForwardOutIterator __result,
-             _BinaryOperation __op) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
-      auto __res = __statpart::__for_each(
-          __first1,
-          __last1,
-          [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
-            return std::transform(
-                __brick_first,
-                __brick_last,
-                __first2 + (__brick_first - __first1),
-                __result + (__brick_first - __first1),
-                __op);
-          });
-      if (!__res)
-        return nullopt;
-      return __result + (__last1 - __first1);
-    } else {
-      return std::transform(__first1, __last1, __first2, __result, __op);
-    }
-  }
-};
-
 template <class _ExecutionPolicy>
 struct __transform_reduce<__statpart_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
diff --git a/libcxx/include/__pstl/backends/statpart/search_n.h b/libcxx/include/__pstl/backends/statpart/search_n.h
new file mode 100644
index 00000000000000..1ab5b72f2c5b67
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/search_n.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_SEARCH_N_H
+#define _LIBCPP___PSTL_STATPART_SEARCH_N_H
+
+#include <__algorithm/search_n.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/convert_to_integral.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __search_n<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Size, class _Tp, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+  operator()(_Policy&&,
+             _ForwardIterator __first,
+             _ForwardIterator __last,
+             _Size __count,
+             const _Tp& __value,
+             _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      typedef typename std::iterator_traits<_ForwardIterator>::difference_type _DifferenceType;
+      _DifferenceType __integral_count = std::__convert_to_integral(__count);
+      if (__integral_count <= 0) {
+        return __first; // If the count is non-positive, the first iterator is returned.
+      }
+      _DifferenceType __size = __last - __first;
+      if (__size < __integral_count) {
+        return __last; // The range is too small to contain the requested number of consecutive elements.
+      }
+      // Calculate the length of the tail where a potential match cannot start by definition.
+      _DifferenceType __crop = __integral_count - 1;
+      // We're only interested in the range where a potential match can start: [first, last - crop)
+      _ForwardIterator __last2 = __last - __crop;
+      // Run a parallel chunked find_if, covering the range where a potential match can start.
+      auto __res = __statpart::__find(
+          __first,
+          __last2,
+          [__integral_count, __crop, &__value, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            // Uncrop the range to allow std::search_n to find a full match, which can go beyond __brick_last.
+            _ForwardIterator __brick_last_uncropped = __brick_last + __crop;
+            // Run a serial std::search_n inside each of the chunks in parallel.
+            _ForwardIterator __ret =
+                std::search_n(__brick_first, __brick_last_uncropped, __integral_count, __value, __pred);
+            // The returned iterator is either a match inside [__brick_first, __brick_last) or a miss encoded as
+            // __brick_last_uncropped. Return the miss as __brick_last to conform to expectations of __find().
+            return __ret == __brick_last_uncropped ? __brick_last : __ret;
+          },
+          less<>{}, // `less` here means the lowest index among the matches
+          true      // `true` here means we want the first match, not the last
+      );
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (*__res == __last2) {
+        return __last; // No match was found in the range.
+      }
+      return *__res; // Return the successful match.
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::search_n(std::move(__first), std::move(__last), __count, __value, std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_SEARCH_N_H
diff --git a/libcxx/include/__pstl/backends/statpart/stable_sort.h b/libcxx/include/__pstl/backends/statpart/stable_sort.h
new file mode 100644
index 00000000000000..22708ba4a8fcd1
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/stable_sort.h
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_STABLE_SORT_H
+#define _LIBCPP___PSTL_STATPART_STABLE_SORT_H
+
+#include <__algorithm/stable_sort.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __stable_sort<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _RandomAccessIterator, class _Comp>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
+      return __statpart::__stable_sort(
+          __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) {
+            std::stable_sort(__g_first, __g_last, __g_comp);
+          });
+    } else {
+      std::stable_sort(__first, __last, __comp);
+      return __empty{};
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_STABLE_SORT_H
diff --git a/libcxx/include/__pstl/backends/statpart/swap_ranges.h b/libcxx/include/__pstl/backends/statpart/swap_ranges.h
new file mode 100644
index 00000000000000..71a4c40cebe516
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/swap_ranges.h
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_SWAP_RANGES_H
+#define _LIBCPP___PSTL_STATPART_SWAP_RANGES_H
+
+#include <__algorithm/swap_ranges.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __swap_ranges<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+      _Policy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      auto __res = __statpart::__for_each_iter_pair(
+          __first1,
+          __last1,
+          __first2,
+          [](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1, _ForwardIterator2 __brick_first2) {
+            std::swap_ranges(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2));
+          });
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      return __first2 + (__last1 - __first1);
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::swap_ranges(std::move(__first1), std::move(__last1), std::move(__first2));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_SWAP_RANGES_H
diff --git a/libcxx/include/__pstl/backends/statpart/transform.h b/libcxx/include/__pstl/backends/statpart/transform.h
new file mode 100644
index 00000000000000..69914bc2c5055b
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/transform.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_TRANSFORM_H
+#define _LIBCPP___PSTL_STATPART_TRANSFORM_H
+
+#include <__algorithm/transform.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __transform<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _UnaryOperation>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> operator()(
+      _Policy&&, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result, _UnaryOperation __op)
+      const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      __statpart::__for_each(
+          __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            return std::transform(__brick_first, __brick_last, __result + (__brick_first - __first), __op);
+          });
+      return __result + (__last - __first);
+    } else {
+      return std::transform(__first, __last, __result, __op);
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __transform_binary<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy,
+            class _ForwardIterator1,
+            class _ForwardIterator2,
+            class _ForwardOutIterator,
+            class _BinaryOperation>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardOutIterator __result,
+             _BinaryOperation __op) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
+      auto __res = __statpart::__for_each(
+          __first1,
+          __last1,
+          [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
+            return std::transform(
+                __brick_first,
+                __brick_last,
+                __first2 + (__brick_first - __first1),
+                __result + (__brick_first - __first1),
+                __op);
+          });
+      if (!__res)
+        return nullopt;
+      return __result + (__last1 - __first1);
+    } else {
+      return std::transform(__first1, __last1, __first2, __result, __op);
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_TRANSFORM_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 42b219a06ec8d3..92c2118c8760e8 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2450,6 +2450,18 @@ module std {
         module search {
           header "__pstl/backends/statpart/search.h"
         }
+        module search_n {
+          header "__pstl/backends/statpart/search_n.h"
+        }
+        module stable_sort {
+          header "__pstl/backends/statpart/stable_sort.h"
+        }
+        module swap_ranges {
+          header "__pstl/backends/statpart/swap_ranges.h"
+        }
+        module transform {
+          header "__pstl/backends/statpart/transform.h"
+        }
         header "__pstl/backends/statpart.h"
       }
       module std_thread {

>From 1211da0a6b1341e93648297795d0f9c08710f696 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 13 Oct 2026 15:40:36 +0100
Subject: [PATCH 12/24] Reorg

---
 libcxx/include/CMakeLists.txt                 |   3 +
 libcxx/include/__pstl/backends/statpart.h     | 207 +-----------------
 .../backends/statpart/transform_reduce.h      | 126 +++++++++++
 .../backends/statpart/uninitialized_copy.h    |  69 ++++++
 .../backends/statpart/uninitialized_move.h    |  69 ++++++
 libcxx/include/module.modulemap.in            |   9 +
 6 files changed, 279 insertions(+), 204 deletions(-)
 create mode 100644 libcxx/include/__pstl/backends/statpart/transform_reduce.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/uninitialized_copy.h
 create mode 100644 libcxx/include/__pstl/backends/statpart/uninitialized_move.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index f2657b9810faa0..e3670e150f16cb 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -711,6 +711,9 @@ set(files
   __pstl/backends/statpart/stable_sort.h
   __pstl/backends/statpart/swap_ranges.h
   __pstl/backends/statpart/transform.h
+  __pstl/backends/statpart/transform_reduce.h
+  __pstl/backends/statpart/uninitialized_copy.h
+  __pstl/backends/statpart/uninitialized_move.h
   __pstl/backends/std_thread.h
   __pstl/cpu_algos/any_of.h
   __pstl/cpu_algos/cpu_traits.h
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index 61c484f91318f2..665d3d36d8a437 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -24,209 +24,8 @@
 #include <__pstl/backends/statpart/stable_sort.h>
 #include <__pstl/backends/statpart/swap_ranges.h>
 #include <__pstl/backends/statpart/transform.h>
-
-#include <__algorithm/find_end.h>
-#include <__algorithm/find_if.h>
-#include <__algorithm/for_each.h>
-#include <__algorithm/is_heap_until.h>
-#include <__algorithm/lower_bound.h>
-#include <__algorithm/merge.h>
-#include <__algorithm/min.h>
-#include <__algorithm/min_element.h>
-#include <__algorithm/minmax_element.h>
-#include <__algorithm/mismatch.h>
-#include <__algorithm/move.h>
-#include <__algorithm/reverse.h>
-#include <__algorithm/search.h>
-#include <__algorithm/search_n.h>
-#include <__algorithm/stable_sort.h>
-#include <__algorithm/swap_ranges.h>
-#include <__algorithm/transform.h>
-#include <__algorithm/upper_bound.h>
-#include <__atomic/atomic.h>
-#include <__config>
-#include <__functional/identity.h>
-#include <__functional/operations.h>
-#include <__iterator/concepts.h>
-#include <__iterator/iterator_traits.h>
-#include <__iterator/move_iterator.h>
-#include <__iterator/next.h>
-#include <__iterator/reverse_iterator.h>
-#include <__memory/allocator.h>
-#include <__memory/construct_at.h>
-#include <__memory/destroy.h>
-#include <__memory/uninitialized_algorithms.h>
-#include <__memory/unique_ptr.h>
-#include <__numeric/reduce.h>
-#include <__numeric/transform_reduce.h>
-#include <__optional/nullopt_t.h>
-#include <__optional/optional.h>
-#include <__pstl/backend_fwd.h>
-#include <__pstl/cpu_algos/cpu_traits.h>
-#include <__pstl/cpu_algos/find_if.h>
-#include <__thread/thread.h>
-#include <__type_traits/is_assignable.h>
-#include <__type_traits/is_constructible.h>
-#include <__type_traits/is_execution_policy.h>
-#include <__type_traits/is_trivially_copyable.h>
-#include <__utility/convert_to_integral.h>
-#include <__utility/empty.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>
-
-#if _LIBCPP_STD_VER >= 17
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
-namespace __pstl {
-
-template <class _ExecutionPolicy>
-struct __transform_reduce<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
-  _LIBCPP_HIDE_FROM_ABI optional<_Tp>
-  operator()(_Policy&&,
-             _ForwardIterator __first,
-             _ForwardIterator __last,
-             _Tp __init,
-             _BinaryOperation __reduce,
-             _UnaryOperation __transform) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
-      return __statpart::__transform_reduce(
-          std::move(__first),
-          std::move(__last),
-          [__transform](_ForwardIterator __iter) { return __transform(*__iter); },
-          std::move(__init),
-          __reduce,
-          [__transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) {
-            return std::transform_reduce(
-                std::move(__brick_first),
-                std::move(__brick_last),
-                std::move(__brick_init),
-                std::move(__reduce),
-                std::move(__transform));
-          });
-    } else {
-      return std::transform_reduce(
-          std::move(__first), std::move(__last), std::move(__init), std::move(__reduce), std::move(__transform));
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __transform_reduce_binary<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy,
-            class _ForwardIterator1,
-            class _ForwardIterator2,
-            class _Tp,
-            class _BinaryOperation1,
-            class _BinaryOperation2>
-  _LIBCPP_HIDE_FROM_ABI optional<_Tp> operator()(
-      _Policy&&,
-      _ForwardIterator1 __first1,
-      _ForwardIterator1 __last1,
-      _ForwardIterator2 __first2,
-      _Tp __init,
-      _BinaryOperation1 __reduce,
-      _BinaryOperation2 __transform) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
-      return __statpart::__transform_reduce(
-          __first1,
-          std::move(__last1),
-          [__first1, __first2, __transform](_ForwardIterator1 __iter) {
-            return __transform(*__iter, *(__first2 + (__iter - __first1)));
-          },
-          std::move(__init),
-          std::move(__reduce),
-          [__first1, __first2, __reduce, __transform](
-              _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) {
-            return std::transform_reduce(
-                __brick_first,
-                std::move(__brick_last),
-                __first2 + (__brick_first - __first1),
-                std::move(__brick_init),
-                std::move(__reduce),
-                std::move(__transform));
-          });
-    } else {
-      return std::transform_reduce(
-          std::move(__first1),
-          std::move(__last1),
-          std::move(__first2),
-          std::move(__init),
-          std::move(__reduce),
-          std::move(__transform));
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __uninitialized_copy<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
-      _Policy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
-      auto __res = __statpart::__for_each_iter_pair(
-          __first,
-          __last,
-          __result,
-          [](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _ForwardIterator2 __brick_result) {
-            std::uninitialized_copy(std::move(__brick_first), std::move(__brick_last), std::move(__brick_result));
-          });
-      if (!__res) {
-        return std::nullopt; // Failed to run the algorithm, propagate the error.
-      }
-      return __result + (__last - __first);
-    } else {
-      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
-      return std::uninitialized_copy(std::move(__first), std::move(__last), std::move(__result));
-    }
-  }
-};
-
-template <class _ExecutionPolicy>
-struct __uninitialized_move<__statpart_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
-  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
-      _Policy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result) const noexcept {
-    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
-                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
-      auto __res = __statpart::__for_each_iter_pair(
-          __first,
-          __last,
-          __result,
-          [](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _ForwardIterator2 __brick_result) {
-            std::uninitialized_move(std::move(__brick_first), std::move(__brick_last), std::move(__brick_result));
-          });
-      if (!__res) {
-        return std::nullopt; // Failed to run the algorithm, propagate the error.
-      }
-      return __result + (__last - __first);
-    } else {
-      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
-      return std::uninitialized_move(std::move(__first), std::move(__last), std::move(__result));
-    }
-  }
-};
-
-} // namespace __pstl
-_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP_STD_VER >= 17
-
-_LIBCPP_POP_MACROS
+#include <__pstl/backends/statpart/transform_reduce.h>
+#include <__pstl/backends/statpart/uninitialized_copy.h>
+#include <__pstl/backends/statpart/uninitialized_move.h>
 
 #endif // _LIBCPP___PSTL_STATPART_H
diff --git a/libcxx/include/__pstl/backends/statpart/transform_reduce.h b/libcxx/include/__pstl/backends/statpart/transform_reduce.h
new file mode 100644
index 00000000000000..c57fc7f0c269c8
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/transform_reduce.h
@@ -0,0 +1,126 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_TRANSFORM_REDUCE_H
+#define _LIBCPP___PSTL_STATPART_TRANSFORM_REDUCE_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__numeric/transform_reduce.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/empty.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __transform_reduce<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
+  _LIBCPP_HIDE_FROM_ABI optional<_Tp>
+  operator()(_Policy&&,
+             _ForwardIterator __first,
+             _ForwardIterator __last,
+             _Tp __init,
+             _BinaryOperation __reduce,
+             _UnaryOperation __transform) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__transform_reduce(
+          std::move(__first),
+          std::move(__last),
+          [__transform](_ForwardIterator __iter) { return __transform(*__iter); },
+          std::move(__init),
+          __reduce,
+          [__transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) {
+            return std::transform_reduce(
+                std::move(__brick_first),
+                std::move(__brick_last),
+                std::move(__brick_init),
+                std::move(__reduce),
+                std::move(__transform));
+          });
+    } else {
+      return std::transform_reduce(
+          std::move(__first), std::move(__last), std::move(__init), std::move(__reduce), std::move(__transform));
+    }
+  }
+};
+
+template <class _ExecutionPolicy>
+struct __transform_reduce_binary<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy,
+            class _ForwardIterator1,
+            class _ForwardIterator2,
+            class _Tp,
+            class _BinaryOperation1,
+            class _BinaryOperation2>
+  _LIBCPP_HIDE_FROM_ABI optional<_Tp> operator()(
+      _Policy&&,
+      _ForwardIterator1 __first1,
+      _ForwardIterator1 __last1,
+      _ForwardIterator2 __first2,
+      _Tp __init,
+      _BinaryOperation1 __reduce,
+      _BinaryOperation2 __transform) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      return __statpart::__transform_reduce(
+          __first1,
+          std::move(__last1),
+          [__first1, __first2, __transform](_ForwardIterator1 __iter) {
+            return __transform(*__iter, *(__first2 + (__iter - __first1)));
+          },
+          std::move(__init),
+          std::move(__reduce),
+          [__first1, __first2, __reduce, __transform](
+              _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) {
+            return std::transform_reduce(
+                __brick_first,
+                std::move(__brick_last),
+                __first2 + (__brick_first - __first1),
+                std::move(__brick_init),
+                std::move(__reduce),
+                std::move(__transform));
+          });
+    } else {
+      return std::transform_reduce(
+          std::move(__first1),
+          std::move(__last1),
+          std::move(__first2),
+          std::move(__init),
+          std::move(__reduce),
+          std::move(__transform));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_TRANSFORM_REDUCE_H
diff --git a/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h b/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h
new file mode 100644
index 00000000000000..1c2fba6295ff26
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_UNITIALIZED_COPY_H
+#define _LIBCPP___PSTL_STATPART_UNITIALIZED_COPY_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/uninitialized_algorithms.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __uninitialized_copy<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+      _Policy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      auto __res = __statpart::__for_each_iter_pair(
+          __first,
+          __last,
+          __result,
+          [](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _ForwardIterator2 __brick_result) {
+            std::uninitialized_copy(std::move(__brick_first), std::move(__brick_last), std::move(__brick_result));
+          });
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      return __result + (__last - __first);
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::uninitialized_copy(std::move(__first), std::move(__last), std::move(__result));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_UNITIALIZED_COPY_H
diff --git a/libcxx/include/__pstl/backends/statpart/uninitialized_move.h b/libcxx/include/__pstl/backends/statpart/uninitialized_move.h
new file mode 100644
index 00000000000000..5596b16b087b4b
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/uninitialized_move.h
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_STATPART_UNITIALIZED_MOVE_H
+#define _LIBCPP___PSTL_STATPART_UNITIALIZED_MOVE_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/uninitialized_algorithms.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _ExecutionPolicy>
+struct __uninitialized_move<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+      _Policy&&, _ForwardIterator1 __first, _ForwardIterator1 __last, _ForwardIterator2 __result) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      auto __res = __statpart::__for_each_iter_pair(
+          __first,
+          __last,
+          __result,
+          [](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _ForwardIterator2 __brick_result) {
+            std::uninitialized_move(std::move(__brick_first), std::move(__brick_last), std::move(__brick_result));
+          });
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      return __result + (__last - __first);
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      return std::uninitialized_move(std::move(__first), std::move(__last), std::move(__result));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_STATPART_UNITIALIZED_MOVE_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 92c2118c8760e8..4540b7ccf77c9d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2462,6 +2462,15 @@ module std {
         module transform {
           header "__pstl/backends/statpart/transform.h"
         }
+        module transform_reduce {
+          header "__pstl/backends/statpart/transform_reduce.h"
+        }
+        module uninitialized_copy {
+          header "__pstl/backends/statpart/uninitialized_copy.h"
+        }
+        module uninitialized_move {
+          header "__pstl/backends/statpart/uninitialized_move.h"
+        }
         header "__pstl/backends/statpart.h"
       }
       module std_thread {

>From dfa5a4b9fdcbb40d449f195e37e530755e02b023 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 13 Oct 2026 17:29:52 +0100
Subject: [PATCH 13/24] Polished the comments, added an assertion on the min
 partition size, added earlier bailing out when there's not enough elements.

---
 .../include/__pstl/backends/statpart/basis.h  | 47 +++++++++++--------
 1 file changed, 28 insertions(+), 19 deletions(-)

diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
index 75dc2a5e159dcf..a5d66d808b8dd5 100644
--- a/libcxx/include/__pstl/backends/statpart/basis.h
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -14,6 +14,7 @@
 #include <__algorithm/min.h>
 #include <__algorithm/move.h>
 #include <__algorithm/upper_bound.h>
+#include <__assert>
 #include <__atomic/atomic.h>
 #include <__config>
 #include <__functional/identity.h>
@@ -52,24 +53,27 @@ namespace __pstl {
 
 namespace __statpart {
 
-// The backbone of the backend: applies the function to each of the indices [0, __chunk_count] in parallel.
+// The backbone of the backend: applies the function to each of the indices [0, __chunk_count) in parallel.
 // The actual number of parallel workers and the order of application is unspecified.
 _LIBCPP_EXPORTED_FROM_ABI void
 __apply(size_t __chunk_count, void* __context, void (*__func)(void* __context, size_t __chunk)) noexcept;
 
-// The maximum number of partitions to be processed per each CPU
+// The maximum number of partitions to be processed per CPU
 constexpr inline size_t __max_partitions_per_cpu = 8;
 
 // The minimum number of elements to sort serially in a single partition
 constexpr inline size_t __min_sort_partition_size = 256;
 
 enum class __partitioning_result {
-  // returned when the partitioning result is not nullopt
+  // Returned when the partitioning result is not a nullopt.
   __ok,
-  // returned when there is not enough element to produce a single partition or the final number of partitions is less
-  // than 2, i.e. there's no reason to process in parallel
+  // Returned when there are not enough element to produce a single partition or the final number of partitions is fewer
+  // than 2, i.e. there's no reason to process the input in parallel.
   __not_enough_elements,
-  // later: returned memory couldn't be allocated for the stashed forward iterators
+  // There's fewer than 2 processors available in the system, or their number is unknown, which is treated as having
+  // a single processor. In either case, fall back to serial processing.
+  __no_parallelism,
+  // Reserved for later: returned when memory could not be allocated for the stashed forward iterators.
   __bad_alloc
 };
 
@@ -79,9 +83,9 @@ struct _LIBCPP_HIDE_FROM_ABI __iterator_range {
   _Iterator __last;
 };
 
-// __iterator_partitions<Iter> holds a finite per-determined set of partitions and allows to query each iterator range
+// __iterator_partitions<Iter> holds a finite pre-determined set of partitions and allows querying each iterator range
 // in O(1) time.
-// TODO: Later to support forward iterators via a second implicit template argument.
+// TODO: Support forward iterators later via a second implicit template argument and its specializations.
 template <class _Iterator>
 struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
   _LIBCPP_HIDE_FROM_ABI size_t __partitions_count() const { return __partitions_count_; }
@@ -106,11 +110,11 @@ struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
   __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t, size_t) noexcept;
 };
 
-// Splits the input iterator range into a finite set of partitions, such as that every iterator sub-range can queried in
+// Splits the input iterator range into a finite set of partitions, such that every iterator sub-range can queried in
 // a O(1) time later.
-// In case partitioning failed returns nullopt and reports the reason in __result.
+// If partitioning fails, returns nullopt and reports the reason in __result.
 // __min_partition_size specifies the minimal number of elements in every partition.
-// __prefix_to_skip and __suffix_to_skip allow to optionally trim the input range by specified numbers of elements
+// __prefix_to_skip and __suffix_to_skip allows optionally trimming the input range by the specified number of elements
 // before partitioning.
 // __workers_count is normally implicitly queried from hardware_concurrency() and should be explicitly specified only in
 // unit tests.
@@ -123,13 +127,19 @@ _LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partit
     size_t __prefix_to_skip     = 0,
     size_t __suffix_to_skip     = 0,
     size_t __workers_count      = thread::hardware_concurrency()) noexcept {
-  // forward iteratos to be supported later
+  // Forward iterators will be supported later.
   static_assert(__has_random_access_iterator_category_or_concept<_ForwardIterator>::value);
-  // TODO: assert( __min_partition_size > 0 )?
-  // TODO: assert( __workers_count > 0 )?
+
+  _LIBCPP_ASSERT_INTERNAL(__min_partition_size >= 1, "minimum partition size must be at least 1 element");
+
+  if (__workers_count < 2) {
+    // There's no available parallelism in the system, no reason to perform partitioning.
+    __result = __partitioning_result::__no_parallelism;
+    return {};
+  }
 
   size_t __count = static_cast<size_t>(std::distance(__first, __last));
-  if (__count < __prefix_to_skip + __suffix_to_skip) {
+  if (__count <= __prefix_to_skip + __suffix_to_skip) {
     __result = __partitioning_result::__not_enough_elements;
     return {};
   }
@@ -139,7 +149,6 @@ _LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partit
   size_t __partition_count = std::min(__max_partitions, __effective_count / __min_partition_size);
 
   if (__partition_count < 2) {
-    // TODO: verify that's what we want
     __result = __partitioning_result::__not_enough_elements;
     return {}; // not enough input data to process in parallel => no reason to build partitions
   }
@@ -155,7 +164,7 @@ _LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partit
 }
 
 // for_each with explicit partitioning:
-// calls __func in parallel with every iterator ranges provided in __partitions
+// calls __func in parallel with every iterator range provided in __partitions.
 template <class _Iterator, class _Functor>
 _LIBCPP_HIDE_FROM_ABI void __for_each_partition(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {
   struct __ctx_t {
@@ -169,7 +178,7 @@ _LIBCPP_HIDE_FROM_ABI void __for_each_partition(const __iterator_partitions<_Ite
   });
 }
 
-// Calls __func(index) for every index in [0, __count) in parallel
+// Calls __func(index) for every index in [0, __count) in parallel.
 template <class _Functor>
 _LIBCPP_HIDE_FROM_ABI void __for_each_index(size_t __count, _Functor __func) {
   __statpart::__apply(__count, &__func, [](void* __context, size_t __index) {
@@ -177,7 +186,7 @@ _LIBCPP_HIDE_FROM_ABI void __for_each_index(size_t __count, _Functor __func) {
   });
 }
 
-// for_each that calls __func in parallel against every partition index available in __partitions
+// for_each that calls __func in parallel for every partition index available in __partitions.
 template <class _Iterator, class _Functor>
 _LIBCPP_HIDE_FROM_ABI void
 __for_each_partition_index(const __iterator_partitions<_Iterator>& __partitions, _Functor __func) {

>From 42cb3b18e1c5a72869a90e751e0d6f99ba895090 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 14 Oct 2026 09:35:40 +0100
Subject: [PATCH 14/24] Reverted the default on Apple to libdispatch, added a
 verbose check in statpart.cpp

---
 libcxx/CMakeLists.txt        | 2 +-
 libcxx/src/pstl/statpart.cpp | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 55b7a5fc709b37..5478c38afa781d 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -321,7 +321,7 @@ option(LIBCXX_HAS_EXTERNAL_THREAD_API
 option(LIBCXX_HAS_C11_THREAD_API "Ignore auto-detection and force use of C11 thread API" OFF)
 
 if (APPLE)
-  set(LIBCXX_PSTL_BACKEND_DEFAULT_VALUE "statpart")
+  set(LIBCXX_PSTL_BACKEND_DEFAULT_VALUE "libdispatch")
 elseif(LIBCXX_ENABLE_THREADS)
   set(LIBCXX_PSTL_BACKEND_DEFAULT_VALUE "std_thread")
 else()
diff --git a/libcxx/src/pstl/statpart.cpp b/libcxx/src/pstl/statpart.cpp
index 903ebbf000128e..6822288fa71a1e 100644
--- a/libcxx/src/pstl/statpart.cpp
+++ b/libcxx/src/pstl/statpart.cpp
@@ -8,11 +8,16 @@
 
 #include <__config>
 #include <__pstl/backends/statpart.h>
-#include <dispatch/dispatch.h>
 
 // Hardcoded to use libdispatch for now.
 // CMake switches to be introduced later.
 
+#if __has_include(<dispatch/dispatch.h>)
+#  include <dispatch/dispatch.h>
+#else
+#  error "Currently statpart only supports parallelism provided by libdispatch."
+#endif
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl::__statpart {

>From eaf172271662f3a24999193ed83396900a356d58 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 14 Oct 2026 09:43:17 +0100
Subject: [PATCH 15/24] Match the signature of __partition more closely when
 declaring a friend

---
 libcxx/include/__pstl/backends/statpart/basis.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
index a5d66d808b8dd5..01b5211fd67c18 100644
--- a/libcxx/include/__pstl/backends/statpart/basis.h
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -106,7 +106,7 @@ struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
   size_t __partitions_count_;
 
   template <class _Iter>
-  friend optional<__iterator_partitions<_Iter>>
+  friend optional<__iterator_partitions<_Iter>> _LIBCPP_HIDE_FROM_ABI
   __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t, size_t) noexcept;
 };
 

>From 2ae9c49fa3916fb4d882902503b51767b8ca079a Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 14 Oct 2026 11:31:09 +0100
Subject: [PATCH 16/24] More typo fixes

---
 libcxx/include/__pstl/backend.h                 | 2 +-
 libcxx/include/__pstl/backends/statpart/basis.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__pstl/backend.h b/libcxx/include/__pstl/backend.h
index 75ccb5063c2919..1626a929f9707d 100644
--- a/libcxx/include/__pstl/backend.h
+++ b/libcxx/include/__pstl/backend.h
@@ -35,7 +35,7 @@ _LIBCPP_PUSH_MACROS
 #    include <__pstl/backends/statpart.h>
 #  endif
 
-// statpart pulls <cerrno> in transitively via __thread/thread.h, make sure this include is not is conditional/flaky
+// statpart pulls <cerrno> in transitively via __thread/thread.h, make sure this include is not conditional/flaky.
 #  include <cerrno>
 
 #endif // _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
index 01b5211fd67c18..470785bd8b3f47 100644
--- a/libcxx/include/__pstl/backends/statpart/basis.h
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -110,7 +110,7 @@ struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
   __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t, size_t) noexcept;
 };
 
-// Splits the input iterator range into a finite set of partitions, such that every iterator sub-range can queried in
+// Splits the input iterator range into a finite set of partitions, such that every iterator sub-range can be queried in
 // a O(1) time later.
 // If partitioning fails, returns nullopt and reports the reason in __result.
 // __min_partition_size specifies the minimal number of elements in every partition.

>From 0200644cf5f98efbea976a3d30e64c7e7055eb11 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 14 Oct 2026 17:54:19 +0100
Subject: [PATCH 17/24] Fixed the include guards

---
 libcxx/include/__pstl/backends/statpart.h                   | 6 +++---
 libcxx/include/__pstl/backends/statpart/basis.h             | 6 +++---
 libcxx/include/__pstl/backends/statpart/find_end.h          | 6 +++---
 libcxx/include/__pstl/backends/statpart/find_if.h           | 6 +++---
 libcxx/include/__pstl/backends/statpart/for_each.h          | 6 +++---
 libcxx/include/__pstl/backends/statpart/is_heap_until.h     | 6 +++---
 libcxx/include/__pstl/backends/statpart/merge.h             | 6 +++---
 libcxx/include/__pstl/backends/statpart/min_element.h       | 6 +++---
 libcxx/include/__pstl/backends/statpart/minmax_element.h    | 6 +++---
 libcxx/include/__pstl/backends/statpart/mismatch.h          | 6 +++---
 libcxx/include/__pstl/backends/statpart/reverse.h           | 6 +++---
 libcxx/include/__pstl/backends/statpart/search.h            | 6 +++---
 libcxx/include/__pstl/backends/statpart/search_n.h          | 6 +++---
 libcxx/include/__pstl/backends/statpart/stable_sort.h       | 6 +++---
 libcxx/include/__pstl/backends/statpart/swap_ranges.h       | 6 +++---
 libcxx/include/__pstl/backends/statpart/transform.h         | 6 +++---
 libcxx/include/__pstl/backends/statpart/transform_reduce.h  | 6 +++---
 .../include/__pstl/backends/statpart/uninitialized_copy.h   | 6 +++---
 .../include/__pstl/backends/statpart/uninitialized_move.h   | 6 +++---
 19 files changed, 57 insertions(+), 57 deletions(-)

diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index 665d3d36d8a437..a77671588874ff 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_H
-#define _LIBCPP___PSTL_STATPART_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_H
 
 #include <__pstl/backends/statpart/basis.h>
 #include <__pstl/backends/statpart/find_end.h>
@@ -28,4 +28,4 @@
 #include <__pstl/backends/statpart/uninitialized_copy.h>
 #include <__pstl/backends/statpart/uninitialized_move.h>
 
-#endif // _LIBCPP___PSTL_STATPART_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_H
diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
index 470785bd8b3f47..754946dc977207 100644
--- a/libcxx/include/__pstl/backends/statpart/basis.h
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_BASIS_H
-#define _LIBCPP___PSTL_STATPART_BASIS_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_BASIS_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_BASIS_H
 
 #include <__algorithm/lower_bound.h>
 #include <__algorithm/merge.h>
@@ -500,4 +500,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_BASIS_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_BASIS_H
diff --git a/libcxx/include/__pstl/backends/statpart/find_end.h b/libcxx/include/__pstl/backends/statpart/find_end.h
index 2f022024077258..5324d840219120 100644
--- a/libcxx/include/__pstl/backends/statpart/find_end.h
+++ b/libcxx/include/__pstl/backends/statpart/find_end.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_FIND_END_H
-#define _LIBCPP___PSTL_STATPART_FIND_END_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_FIND_END_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_FIND_END_H
 
 #include <__algorithm/find_end.h>
 #include <__config>
@@ -99,4 +99,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_FIND_END_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_FIND_END_H
diff --git a/libcxx/include/__pstl/backends/statpart/find_if.h b/libcxx/include/__pstl/backends/statpart/find_if.h
index c7273a75e54bba..0913e91a18e3f2 100644
--- a/libcxx/include/__pstl/backends/statpart/find_if.h
+++ b/libcxx/include/__pstl/backends/statpart/find_if.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_FIND_IF_H
-#define _LIBCPP___PSTL_STATPART_FIND_IF_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_FIND_IF_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_FIND_IF_H
 
 #include <__algorithm/find_if.h>
 #include <__config>
@@ -64,4 +64,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_FIND_IF_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_FIND_IF_H
diff --git a/libcxx/include/__pstl/backends/statpart/for_each.h b/libcxx/include/__pstl/backends/statpart/for_each.h
index b2199a828cb185..53aeef91fad574 100644
--- a/libcxx/include/__pstl/backends/statpart/for_each.h
+++ b/libcxx/include/__pstl/backends/statpart/for_each.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_FOR_EACH_H
-#define _LIBCPP___PSTL_STATPART_FOR_EACH_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_FOR_EACH_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_FOR_EACH_H
 
 #include <__algorithm/for_each.h>
 #include <__config>
@@ -60,4 +60,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_FOR_EACH_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_FOR_EACH_H
diff --git a/libcxx/include/__pstl/backends/statpart/is_heap_until.h b/libcxx/include/__pstl/backends/statpart/is_heap_until.h
index 88e0c11de11a2e..e983a4835272a3 100644
--- a/libcxx/include/__pstl/backends/statpart/is_heap_until.h
+++ b/libcxx/include/__pstl/backends/statpart/is_heap_until.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_IS_HEAP_UNTIL_H
-#define _LIBCPP___PSTL_STATPART_IS_HEAP_UNTIL_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_IS_HEAP_UNTIL_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_IS_HEAP_UNTIL_H
 
 #include <__algorithm/is_heap_until.h>
 #include <__config>
@@ -102,4 +102,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_IS_HEAP_UNTIL_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_IS_HEAP_UNTIL_H
diff --git a/libcxx/include/__pstl/backends/statpart/merge.h b/libcxx/include/__pstl/backends/statpart/merge.h
index bd9ef68d413a26..5c3ccc7d596576 100644
--- a/libcxx/include/__pstl/backends/statpart/merge.h
+++ b/libcxx/include/__pstl/backends/statpart/merge.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_MERGE_H
-#define _LIBCPP___PSTL_STATPART_MERGE_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_MERGE_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_MERGE_H
 
 #include <__algorithm/merge.h>
 #include <__config>
@@ -85,4 +85,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_MERGE_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_MERGE_H
diff --git a/libcxx/include/__pstl/backends/statpart/min_element.h b/libcxx/include/__pstl/backends/statpart/min_element.h
index 09e3117c81d475..d267c54732ab91 100644
--- a/libcxx/include/__pstl/backends/statpart/min_element.h
+++ b/libcxx/include/__pstl/backends/statpart/min_element.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_MIN_ELEMENT_H
-#define _LIBCPP___PSTL_STATPART_MIN_ELEMENT_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_MIN_ELEMENT_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_MIN_ELEMENT_H
 
 #include <__algorithm/min_element.h>
 #include <__config>
@@ -82,4 +82,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_MIN_ELEMENT_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_MIN_ELEMENT_H
diff --git a/libcxx/include/__pstl/backends/statpart/minmax_element.h b/libcxx/include/__pstl/backends/statpart/minmax_element.h
index bde4bb515999b4..40138be1b6e735 100644
--- a/libcxx/include/__pstl/backends/statpart/minmax_element.h
+++ b/libcxx/include/__pstl/backends/statpart/minmax_element.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_MINMAX_ELEMENT_H
-#define _LIBCPP___PSTL_STATPART_MINMAX_ELEMENT_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_MINMAX_ELEMENT_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_MINMAX_ELEMENT_H
 
 #include <__algorithm/minmax_element.h>
 #include <__config>
@@ -87,4 +87,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_MINMAX_ELEMENT_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_MINMAX_ELEMENT_H
diff --git a/libcxx/include/__pstl/backends/statpart/mismatch.h b/libcxx/include/__pstl/backends/statpart/mismatch.h
index b049b690e12bf8..e2a4ee64da1b28 100644
--- a/libcxx/include/__pstl/backends/statpart/mismatch.h
+++ b/libcxx/include/__pstl/backends/statpart/mismatch.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_MISMATCH_H
-#define _LIBCPP___PSTL_STATPART_MISMATCH_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_MISMATCH_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_MISMATCH_H
 
 #include <__algorithm/min.h>
 #include <__algorithm/mismatch.h>
@@ -88,4 +88,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_MISMATCH_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_MISMATCH_H
diff --git a/libcxx/include/__pstl/backends/statpart/reverse.h b/libcxx/include/__pstl/backends/statpart/reverse.h
index 4e3d147475568b..9b9aee1e6ddbde 100644
--- a/libcxx/include/__pstl/backends/statpart/reverse.h
+++ b/libcxx/include/__pstl/backends/statpart/reverse.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_REVERSE_H
-#define _LIBCPP___PSTL_STATPART_REVERSE_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_REVERSE_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_REVERSE_H
 
 #include <__algorithm/reverse.h>
 #include <__algorithm/swap_ranges.h>
@@ -72,4 +72,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_REVERSE_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_REVERSE_H
diff --git a/libcxx/include/__pstl/backends/statpart/search.h b/libcxx/include/__pstl/backends/statpart/search.h
index a831fb8ef63d0e..8c238b6fe055f1 100644
--- a/libcxx/include/__pstl/backends/statpart/search.h
+++ b/libcxx/include/__pstl/backends/statpart/search.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_SEARCH_H
-#define _LIBCPP___PSTL_STATPART_SEARCH_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_H
 
 #include <__algorithm/search.h>
 #include <__config>
@@ -99,4 +99,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_SEARCH_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_H
diff --git a/libcxx/include/__pstl/backends/statpart/search_n.h b/libcxx/include/__pstl/backends/statpart/search_n.h
index 1ab5b72f2c5b67..394f8823328665 100644
--- a/libcxx/include/__pstl/backends/statpart/search_n.h
+++ b/libcxx/include/__pstl/backends/statpart/search_n.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_SEARCH_N_H
-#define _LIBCPP___PSTL_STATPART_SEARCH_N_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_N_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_N_H
 
 #include <__algorithm/search_n.h>
 #include <__config>
@@ -99,4 +99,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_SEARCH_N_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_SEARCH_N_H
diff --git a/libcxx/include/__pstl/backends/statpart/stable_sort.h b/libcxx/include/__pstl/backends/statpart/stable_sort.h
index 22708ba4a8fcd1..aa42da2a453c49 100644
--- a/libcxx/include/__pstl/backends/statpart/stable_sort.h
+++ b/libcxx/include/__pstl/backends/statpart/stable_sort.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_STABLE_SORT_H
-#define _LIBCPP___PSTL_STATPART_STABLE_SORT_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_STABLE_SORT_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_STABLE_SORT_H
 
 #include <__algorithm/stable_sort.h>
 #include <__config>
@@ -58,4 +58,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_STABLE_SORT_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_STABLE_SORT_H
diff --git a/libcxx/include/__pstl/backends/statpart/swap_ranges.h b/libcxx/include/__pstl/backends/statpart/swap_ranges.h
index 71a4c40cebe516..0e6c50aedef02b 100644
--- a/libcxx/include/__pstl/backends/statpart/swap_ranges.h
+++ b/libcxx/include/__pstl/backends/statpart/swap_ranges.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_SWAP_RANGES_H
-#define _LIBCPP___PSTL_STATPART_SWAP_RANGES_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_SWAP_RANGES_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_SWAP_RANGES_H
 
 #include <__algorithm/swap_ranges.h>
 #include <__config>
@@ -67,4 +67,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_SWAP_RANGES_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_SWAP_RANGES_H
diff --git a/libcxx/include/__pstl/backends/statpart/transform.h b/libcxx/include/__pstl/backends/statpart/transform.h
index 69914bc2c5055b..0e303ff4334dfc 100644
--- a/libcxx/include/__pstl/backends/statpart/transform.h
+++ b/libcxx/include/__pstl/backends/statpart/transform.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_TRANSFORM_H
-#define _LIBCPP___PSTL_STATPART_TRANSFORM_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_H
 
 #include <__algorithm/transform.h>
 #include <__config>
@@ -99,4 +99,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_TRANSFORM_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_H
diff --git a/libcxx/include/__pstl/backends/statpart/transform_reduce.h b/libcxx/include/__pstl/backends/statpart/transform_reduce.h
index c57fc7f0c269c8..80110503e696dd 100644
--- a/libcxx/include/__pstl/backends/statpart/transform_reduce.h
+++ b/libcxx/include/__pstl/backends/statpart/transform_reduce.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_TRANSFORM_REDUCE_H
-#define _LIBCPP___PSTL_STATPART_TRANSFORM_REDUCE_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_REDUCE_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_REDUCE_H
 
 #include <__config>
 #include <__iterator/concepts.h>
@@ -123,4 +123,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_TRANSFORM_REDUCE_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_TRANSFORM_REDUCE_H
diff --git a/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h b/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h
index 1c2fba6295ff26..e9dd9f026ceba0 100644
--- a/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h
+++ b/libcxx/include/__pstl/backends/statpart/uninitialized_copy.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_UNITIALIZED_COPY_H
-#define _LIBCPP___PSTL_STATPART_UNITIALIZED_COPY_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_COPY_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_COPY_H
 
 #include <__config>
 #include <__iterator/concepts.h>
@@ -66,4 +66,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_UNITIALIZED_COPY_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_COPY_H
diff --git a/libcxx/include/__pstl/backends/statpart/uninitialized_move.h b/libcxx/include/__pstl/backends/statpart/uninitialized_move.h
index 5596b16b087b4b..5b763c28b4d86a 100644
--- a/libcxx/include/__pstl/backends/statpart/uninitialized_move.h
+++ b/libcxx/include/__pstl/backends/statpart/uninitialized_move.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___PSTL_STATPART_UNITIALIZED_MOVE_H
-#define _LIBCPP___PSTL_STATPART_UNITIALIZED_MOVE_H
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_MOVE_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_MOVE_H
 
 #include <__config>
 #include <__iterator/concepts.h>
@@ -66,4 +66,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___PSTL_STATPART_UNITIALIZED_MOVE_H
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_UNITIALIZED_MOVE_H

>From b7469c4c65db2bde6e339bc94a33b68f5da84d7c Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 15 Oct 2026 12:38:12 +0100
Subject: [PATCH 18/24] Removed the misleading comment

---
 libcxx/src/pstl/statpart.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxx/src/pstl/statpart.cpp b/libcxx/src/pstl/statpart.cpp
index 6822288fa71a1e..09fb8ddd5b3699 100644
--- a/libcxx/src/pstl/statpart.cpp
+++ b/libcxx/src/pstl/statpart.cpp
@@ -10,7 +10,6 @@
 #include <__pstl/backends/statpart.h>
 
 // Hardcoded to use libdispatch for now.
-// CMake switches to be introduced later.
 
 #if __has_include(<dispatch/dispatch.h>)
 #  include <dispatch/dispatch.h>

>From e0e302dc6c7526c9e8e8a3808c32b81dfed3281f Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 15 Oct 2026 12:39:20 +0100
Subject: [PATCH 19/24] Qualify a function call

---
 libcxx/include/__pstl/backends/statpart/basis.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
index 754946dc977207..89f6a8c3e8b43d 100644
--- a/libcxx/include/__pstl/backends/statpart/basis.h
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -220,7 +220,7 @@ _LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each_iter_pair(
     _RandomAccessIterator1 __last1,
     _RandomAccessIterator2 __first2,
     _BrickFunction __f) {
-  return __for_each(
+  return __statpart::__for_each(
       __first1,
       __last1,
       [__first1, __first2, __f = std::move(__f)](

>From 746a7cc30bd38c8d2628fff4a3de36e2e9bff0bf Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 15 Oct 2026 16:18:58 +0100
Subject: [PATCH 20/24] __partition() no longer uses return arguments

---
 .../include/__pstl/backends/statpart/basis.h  | 101 ++++-----
 .../pstl.statpart.partition.pass.cpp          | 198 +++++++++---------
 2 files changed, 147 insertions(+), 152 deletions(-)

diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
index 89f6a8c3e8b43d..2efe82f7c07a36 100644
--- a/libcxx/include/__pstl/backends/statpart/basis.h
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -64,7 +64,7 @@ constexpr inline size_t __max_partitions_per_cpu = 8;
 // The minimum number of elements to sort serially in a single partition
 constexpr inline size_t __min_sort_partition_size = 256;
 
-enum class __partitioning_result {
+enum class __partitioning_status {
   // Returned when the partitioning result is not a nullopt.
   __ok,
   // Returned when there are not enough element to produce a single partition or the final number of partitions is fewer
@@ -77,6 +77,9 @@ enum class __partitioning_result {
   __bad_alloc
 };
 
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __partitioning_result;
+
 template <class _Iterator>
 struct _LIBCPP_HIDE_FROM_ABI __iterator_range {
   _Iterator __first;
@@ -106,8 +109,16 @@ struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
   size_t __partitions_count_;
 
   template <class _Iter>
-  friend optional<__iterator_partitions<_Iter>> _LIBCPP_HIDE_FROM_ABI
-  __partition(_Iter, _Iter, __partitioning_result&, size_t, size_t, size_t, size_t) noexcept;
+  friend __partitioning_result<_Iter> _LIBCPP_HIDE_FROM_ABI
+  __partition(_Iter, _Iter, size_t, size_t, size_t, size_t) noexcept;
+};
+
+// This is basically a barebones std::expected<__iterator_partitions<_Iterator>, __partitioning_status>.
+// __partition() uses this to avoid resorting to return arguments.
+template <class _Iterator>
+struct _LIBCPP_HIDE_FROM_ABI __partitioning_result {
+  optional<__iterator_partitions<_Iterator>> __value_;
+  __partitioning_status __status_ = __partitioning_status::__ok;
 };
 
 // Splits the input iterator range into a finite set of partitions, such that every iterator sub-range can be queried in
@@ -119,14 +130,13 @@ struct _LIBCPP_HIDE_FROM_ABI __iterator_partitions {
 // __workers_count is normally implicitly queried from hardware_concurrency() and should be explicitly specified only in
 // unit tests.
 template <class _ForwardIterator>
-_LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partition(
-    _ForwardIterator __first,
-    _ForwardIterator __last,
-    __partitioning_result& __result,
-    size_t __min_partition_size = 1,
-    size_t __prefix_to_skip     = 0,
-    size_t __suffix_to_skip     = 0,
-    size_t __workers_count      = thread::hardware_concurrency()) noexcept {
+_LIBCPP_HIDE_FROM_ABI __partitioning_result<_ForwardIterator>
+__partition(_ForwardIterator __first,
+            _ForwardIterator __last,
+            size_t __min_partition_size = 1,
+            size_t __prefix_to_skip     = 0,
+            size_t __suffix_to_skip     = 0,
+            size_t __workers_count      = thread::hardware_concurrency()) noexcept {
   // Forward iterators will be supported later.
   static_assert(__has_random_access_iterator_category_or_concept<_ForwardIterator>::value);
 
@@ -134,14 +144,12 @@ _LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partit
 
   if (__workers_count < 2) {
     // There's no available parallelism in the system, no reason to perform partitioning.
-    __result = __partitioning_result::__no_parallelism;
-    return {};
+    return {nullopt, __partitioning_status::__no_parallelism};
   }
 
   size_t __count = static_cast<size_t>(std::distance(__first, __last));
   if (__count <= __prefix_to_skip + __suffix_to_skip) {
-    __result = __partitioning_result::__not_enough_elements;
-    return {};
+    return {nullopt, __partitioning_status::__not_enough_elements};
   }
 
   size_t __effective_count = __count - __prefix_to_skip - __suffix_to_skip;
@@ -149,8 +157,8 @@ _LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partit
   size_t __partition_count = std::min(__max_partitions, __effective_count / __min_partition_size);
 
   if (__partition_count < 2) {
-    __result = __partitioning_result::__not_enough_elements;
-    return {}; // not enough input data to process in parallel => no reason to build partitions
+    // not enough input data to process in parallel => no reason to build partitions
+    return {nullopt, __partitioning_status::__not_enough_elements};
   }
 
   __iterator_partitions<_ForwardIterator> __p;
@@ -159,8 +167,7 @@ _LIBCPP_HIDE_FROM_ABI optional<__iterator_partitions<_ForwardIterator>> __partit
   __p.__partition_size_   = __effective_count / __partition_count;
   __p.__remainder_        = __effective_count % __partition_count;
   __p.__partitions_count_ = __partition_count;
-  __result                = __partitioning_result::__ok;
-  return __p;
+  return {std::move(__p), __partitioning_status::__ok};
 }
 
 // for_each with explicit partitioning:
@@ -199,12 +206,11 @@ template <class _Iterator, class _Functor>
 _LIBCPP_HIDE_FROM_ABI optional<__empty> __for_each(_Iterator __first, _Iterator __last, _Functor __func) {
   if (__first == __last)
     return __empty{};
-  __partitioning_result __partition_result;
-  auto __partitions = __statpart::__partition(__first, __last, __partition_result);
-  if (__partitions) {
-    __statpart::__for_each_partition(*__partitions, std::move(__func));
+  auto __partitions = __statpart::__partition(__first, __last);
+  if (__partitions.__value_) {
+    __statpart::__for_each_partition(*__partitions.__value_, std::move(__func));
     return __empty{};
-  } else if (__partition_result == __partitioning_result::__bad_alloc) {
+  } else if (__partitions.__status_ == __partitioning_status::__bad_alloc) {
     return nullopt;
   } else {
     __func(__first, __last);
@@ -269,10 +275,9 @@ _LIBCPP_HIDE_FROM_ABI optional<_Value> __transform_reduce(
     return __init;
 
   // Split into partitions with at least 3 elements in each
-  __partitioning_result __partitioning_result;
-  auto __partitions = __statpart::__partition(__first, __last, __partitioning_result, 3);
-  if (!__partitions) {
-    if (__partitioning_result == __partitioning_result::__bad_alloc) {
+  auto __partitions = __statpart::__partition(__first, __last, 3);
+  if (!__partitions.__value_) {
+    if (__partitions.__status_ == __partitioning_status::__bad_alloc) {
       // Failed to allocate memory for the partitions, propagate the error up.
       return nullopt;
     } else {
@@ -281,7 +286,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_Value> __transform_reduce(
     }
   }
 
-  auto __destroy = [__count = __partitions->__partitions_count()](_Value* __ptr) {
+  auto __destroy = [__count = __partitions.__value_->__partitions_count()](_Value* __ptr) {
     std::destroy_n(__ptr, __count);
     std::allocator<_Value>().deallocate(__ptr, __count);
   };
@@ -289,11 +294,11 @@ _LIBCPP_HIDE_FROM_ABI optional<_Value> __transform_reduce(
   // TODO: use __uninitialized_buffer
   // TODO: allocate one element per worker instead of one element per chunk
   unique_ptr<_Value[], decltype(__destroy)> __values(
-      std::allocator<_Value>().allocate(__partitions->__partitions_count()), __destroy);
+      std::allocator<_Value>().allocate(__partitions.__value_->__partitions_count()), __destroy);
 
   // __dispatch_apply is noexcept
-  __statpart::__for_each_partition_index(*__partitions, [&](size_t __index) {
-    auto __range = __partitions->__partition(__index);
+  __statpart::__for_each_partition_index(*__partitions.__value_, [&](size_t __index) {
+    auto __range = __partitions.__value_->__partition(__index);
     std::__construct_at(
         __values.get() + __index,
         __reduction(__range.__first + 2,
@@ -303,7 +308,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_Value> __transform_reduce(
 
   return std::reduce(
       std::make_move_iterator(__values.get()),
-      std::make_move_iterator(__values.get() + __partitions->__partitions_count()),
+      std::make_move_iterator(__values.get() + __partitions.__value_->__partitions_count()),
       std::move(__init),
       __combiner);
 }
@@ -331,10 +336,9 @@ __merge(_RandomAccessIterator1 __first1,
                  auto __find_cutpoint,
                  auto __merge_sub_ranges) -> optional<__empty> {
     // Partition the longest input range evenly.
-    __partitioning_result __partitioning_result;
-    auto __partitions = __statpart::__partition(__long_first, __long_last, __partitioning_result);
-    if (!__partitions) {
-      if (__partitioning_result == __partitioning_result::__bad_alloc)
+    auto __partitions = __statpart::__partition(__long_first, __long_last);
+    if (!__partitions.__value_) {
+      if (__partitions.__status_ == __partitioning_status::__bad_alloc)
         return nullopt;
       // Not enough elements to run in parallel, merge everything serially.
       __merge_sub_ranges(__long_first, __long_last, __short_first, __short_last, __result);
@@ -342,9 +346,9 @@ __merge(_RandomAccessIterator1 __first1,
     }
 
     // Process the partitions of the longest range in parallel.
-    __statpart::__for_each_partition_index(*__partitions, [&](size_t __index) {
+    __statpart::__for_each_partition_index(*__partitions.__value_, [&](size_t __index) {
       // Get the sub-range inside the longer input range.
-      auto __range = __partitions->__partition(__index);
+      auto __range = __partitions.__value_->__partition(__index);
 
       // Find the matching sub-range of the shorter input range: it will hold the elements that come after the last
       // element of the previous long partition and up to the last element of this partition.
@@ -352,7 +356,7 @@ __merge(_RandomAccessIterator1 __first1,
       auto __short_begin =
           __index == 0 ? __short_first : __find_cutpoint(__short_first, __short_last, __range.__first[-1]);
       auto __short_end =
-          __index == __partitions->__partitions_count() - 1
+          __index == __partitions.__value_->__partitions_count() - 1
               ? __short_last
               : __find_cutpoint(__short_first, __short_last, __range.__last[-1]);
 
@@ -399,10 +403,9 @@ _LIBCPP_HIDE_FROM_ABI optional<__empty>
 __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
   const auto __size = __last - __first;
 
-  __partitioning_result __partitioning_result;
-  auto __partitions = __statpart::__partition(__first, __last, __partitioning_result, __min_sort_partition_size);
-  if (!__partitions) {
-    if (__partitioning_result == __partitioning_result::__bad_alloc)
+  auto __partitions = __statpart::__partition(__first, __last, __min_sort_partition_size);
+  if (!__partitions.__value_) {
+    if (__partitions.__status_ == __partitioning_status::__bad_alloc)
       return nullopt;
     // Not enough elements to run in parallel, sort everything serially.
     __leaf_sort(__first, __last, __comp);
@@ -428,23 +431,25 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
   *__first = std::move(__values.get()[__size - 1]);
 
   __statpart::__for_each_partition(
-      *__partitions, [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) {
+      *__partitions.__value_,
+      [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) {
         __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp);
       });
 
   // A chunk span is a run of __chunk_span_size consecutive partitions, the last chunk can be shorter in case of odd
   // number of chunk spans. Each pass merges the chunk spans pairwise, so the chunk span size doubles and the chunk
   // count is halved (rounded up).
-  const size_t __partition_count = __partitions->__partitions_count();
+  const size_t __partition_count = __partitions.__value_->__partitions_count();
   size_t __chunk_span_size       = 1;
   size_t __chunk_spans           = __partition_count;
 
   // Offsets of the beginning and the end of the chunk from __first
   auto __chunk_begin = [&](size_t __chunk) {
-    return __partitions->__partition(__chunk * __chunk_span_size).__first - __first;
+    return __partitions.__value_->__partition(__chunk * __chunk_span_size).__first - __first;
   };
   auto __chunk_end = [&](size_t __chunk) {
-    return __partitions->__partition(std::min((__chunk + 1) * __chunk_span_size, __partition_count) - 1).__last -
+    return __partitions.__value_->__partition(std::min((__chunk + 1) * __chunk_span_size, __partition_count) - 1)
+               .__last -
            __first;
   };
 
diff --git a/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp b/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp
index e9c973b94e7a23..457d97a39831de 100644
--- a/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.statpart.partition.pass.cpp
@@ -13,10 +13,9 @@
 // UNSUPPORTED: libcpp-has-no-incomplete-pstl
 
 // template <class Iterator>
-// optional<__iterator_partitions<Iterator>>
+// __partitioning_result<Iterator>
 // __partition(Iterator __first,
 //             Iterator __last,
-//             __partitioning_result& __result,
 //             size_t __min_partition_size,
 //             size_t __prefix_to_skip,
 //             size_t __suffix_to_skip,
@@ -38,140 +37,131 @@ void test_partition() {
 
   { // 1 element, 8 workers: no partitions
     Container v(1);
-    std::__pstl::__statpart::__partitioning_result result;
-    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 1, 0, 0, 8);
-    assert(partitions == std::nullopt);
-    assert(result == std::__pstl::__statpart::__partitioning_result::__not_enough_elements);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 1, 0, 0, 8);
+    assert(partitions.__value_ == std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__not_enough_elements);
   }
   { // 2 elements, 8 workers: 2 partitions
     // [0..1), [1..2)
     Container v(2);
-    std::__pstl::__statpart::__partitioning_result result;
-    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 1, 0, 0, 8);
-    assert(partitions != std::nullopt);
-    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
-    assert(partitions->__partitions_count() == 2);
-    assert(partitions->__end() == v.end());
-    assert(part_eq(partitions->__partition(0), v, 0, 1));
-    assert(part_eq(partitions->__partition(1), v, 1, 2));
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 1, 0, 0, 8);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 2);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 1));
+    assert(part_eq(partitions.__value_->__partition(1), v, 1, 2));
   }
   { // 2 elements, min_size=2, 8 workers: no partitions
     // [0..1), [1..2)
     Container v(2);
-    std::__pstl::__statpart::__partitioning_result result;
-    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 1, 2, 0, 8);
-    assert(partitions == std::nullopt);
-    assert(result == std::__pstl::__statpart::__partitioning_result::__not_enough_elements);
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 1, 2, 0, 8);
+    assert(partitions.__value_ == std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__not_enough_elements);
   }
   { // 20 elements, 2 workers: 16 partitions
     // [0..2), [2..4), [4..6), [6..8), [8..9), [9..10), ..., [19, 20)
     Container v(20);
-    std::__pstl::__statpart::__partitioning_result result;
-    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 1, 0, 0, 2);
-    assert(partitions != std::nullopt);
-    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
-    assert(partitions->__partitions_count() == 16);
-    assert(partitions->__end() == v.end());
-    assert(part_eq(partitions->__partition(0), v, 0, 2));
-    assert(part_eq(partitions->__partition(1), v, 2, 4));
-    assert(part_eq(partitions->__partition(2), v, 4, 6));
-    assert(part_eq(partitions->__partition(3), v, 6, 8));
-    assert(part_eq(partitions->__partition(4), v, 8, 9));
-    assert(part_eq(partitions->__partition(5), v, 9, 10));
-    assert(part_eq(partitions->__partition(6), v, 10, 11));
-    assert(part_eq(partitions->__partition(7), v, 11, 12));
-    assert(part_eq(partitions->__partition(8), v, 12, 13));
-    assert(part_eq(partitions->__partition(9), v, 13, 14));
-    assert(part_eq(partitions->__partition(10), v, 14, 15));
-    assert(part_eq(partitions->__partition(11), v, 15, 16));
-    assert(part_eq(partitions->__partition(12), v, 16, 17));
-    assert(part_eq(partitions->__partition(13), v, 17, 18));
-    assert(part_eq(partitions->__partition(14), v, 18, 19));
-    assert(part_eq(partitions->__partition(15), v, 19, 20));
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 1, 0, 0, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 16);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 2));
+    assert(part_eq(partitions.__value_->__partition(1), v, 2, 4));
+    assert(part_eq(partitions.__value_->__partition(2), v, 4, 6));
+    assert(part_eq(partitions.__value_->__partition(3), v, 6, 8));
+    assert(part_eq(partitions.__value_->__partition(4), v, 8, 9));
+    assert(part_eq(partitions.__value_->__partition(5), v, 9, 10));
+    assert(part_eq(partitions.__value_->__partition(6), v, 10, 11));
+    assert(part_eq(partitions.__value_->__partition(7), v, 11, 12));
+    assert(part_eq(partitions.__value_->__partition(8), v, 12, 13));
+    assert(part_eq(partitions.__value_->__partition(9), v, 13, 14));
+    assert(part_eq(partitions.__value_->__partition(10), v, 14, 15));
+    assert(part_eq(partitions.__value_->__partition(11), v, 15, 16));
+    assert(part_eq(partitions.__value_->__partition(12), v, 16, 17));
+    assert(part_eq(partitions.__value_->__partition(13), v, 17, 18));
+    assert(part_eq(partitions.__value_->__partition(14), v, 18, 19));
+    assert(part_eq(partitions.__value_->__partition(15), v, 19, 20));
   }
   { // 20 elements, min_size=2, 2 workers: 10 partitions
     // [0..2), [2..4), [4..6), ..., [18, 20)
     Container v(20);
-    std::__pstl::__statpart::__partitioning_result result;
-    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 2, 0, 0, 2);
-    assert(partitions != std::nullopt);
-    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
-    assert(partitions->__partitions_count() == 10);
-    assert(partitions->__end() == v.end());
-    assert(part_eq(partitions->__partition(0), v, 0, 2));
-    assert(part_eq(partitions->__partition(1), v, 2, 4));
-    assert(part_eq(partitions->__partition(2), v, 4, 6));
-    assert(part_eq(partitions->__partition(3), v, 6, 8));
-    assert(part_eq(partitions->__partition(4), v, 8, 10));
-    assert(part_eq(partitions->__partition(5), v, 10, 12));
-    assert(part_eq(partitions->__partition(6), v, 12, 14));
-    assert(part_eq(partitions->__partition(7), v, 14, 16));
-    assert(part_eq(partitions->__partition(8), v, 16, 18));
-    assert(part_eq(partitions->__partition(9), v, 18, 20));
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 2, 0, 0, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 10);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 2));
+    assert(part_eq(partitions.__value_->__partition(1), v, 2, 4));
+    assert(part_eq(partitions.__value_->__partition(2), v, 4, 6));
+    assert(part_eq(partitions.__value_->__partition(3), v, 6, 8));
+    assert(part_eq(partitions.__value_->__partition(4), v, 8, 10));
+    assert(part_eq(partitions.__value_->__partition(5), v, 10, 12));
+    assert(part_eq(partitions.__value_->__partition(6), v, 12, 14));
+    assert(part_eq(partitions.__value_->__partition(7), v, 14, 16));
+    assert(part_eq(partitions.__value_->__partition(8), v, 16, 18));
+    assert(part_eq(partitions.__value_->__partition(9), v, 18, 20));
   }
   { // 20 elements, min_size=3, 2 workers: 6 partitions
     // [0..4), [4..8), [8..11), [11..14), [14..17), [17..20)
     Container v(20);
-    std::__pstl::__statpart::__partitioning_result result;
-    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 3, 0, 0, 2);
-    assert(partitions != std::nullopt);
-    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
-    assert(partitions->__partitions_count() == 6);
-    assert(partitions->__end() == v.end());
-    assert(part_eq(partitions->__partition(0), v, 0, 4));
-    assert(part_eq(partitions->__partition(1), v, 4, 8));
-    assert(part_eq(partitions->__partition(2), v, 8, 11));
-    assert(part_eq(partitions->__partition(3), v, 11, 14));
-    assert(part_eq(partitions->__partition(4), v, 14, 17));
-    assert(part_eq(partitions->__partition(5), v, 17, 20));
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 3, 0, 0, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 6);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 4));
+    assert(part_eq(partitions.__value_->__partition(1), v, 4, 8));
+    assert(part_eq(partitions.__value_->__partition(2), v, 8, 11));
+    assert(part_eq(partitions.__value_->__partition(3), v, 11, 14));
+    assert(part_eq(partitions.__value_->__partition(4), v, 14, 17));
+    assert(part_eq(partitions.__value_->__partition(5), v, 17, 20));
   }
   { // 20 elements, min_size=3, prefix_skip=1, 2 workers: 6 partitions
     // [1..5), [5..8), [8..11), [11..14), [14..17), [17..20)
     Container v(20);
-    std::__pstl::__statpart::__partitioning_result result;
-    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 3, 1, 0, 2);
-    assert(partitions != std::nullopt);
-    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
-    assert(partitions->__partitions_count() == 6);
-    assert(partitions->__end() == v.end());
-    assert(part_eq(partitions->__partition(0), v, 1, 5));
-    assert(part_eq(partitions->__partition(1), v, 5, 8));
-    assert(part_eq(partitions->__partition(2), v, 8, 11));
-    assert(part_eq(partitions->__partition(3), v, 11, 14));
-    assert(part_eq(partitions->__partition(4), v, 14, 17));
-    assert(part_eq(partitions->__partition(5), v, 17, 20));
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 3, 1, 0, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 6);
+    assert(partitions.__value_->__end() == v.end());
+    assert(part_eq(partitions.__value_->__partition(0), v, 1, 5));
+    assert(part_eq(partitions.__value_->__partition(1), v, 5, 8));
+    assert(part_eq(partitions.__value_->__partition(2), v, 8, 11));
+    assert(part_eq(partitions.__value_->__partition(3), v, 11, 14));
+    assert(part_eq(partitions.__value_->__partition(4), v, 14, 17));
+    assert(part_eq(partitions.__value_->__partition(5), v, 17, 20));
   }
   { // 20 elements, min_size=3, suffix_skip=1, 2 workers: 6 partitions
     // [0..4), [4..8), [8..11), [11..14), [14..17), [17..20)
     Container v(20);
-    std::__pstl::__statpart::__partitioning_result result;
-    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 3, 0, 1, 2);
-    assert(partitions != std::nullopt);
-    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
-    assert(partitions->__partitions_count() == 6);
-    assert(partitions->__end() == std::prev(v.end(), 1));
-    assert(part_eq(partitions->__partition(0), v, 0, 4));
-    assert(part_eq(partitions->__partition(1), v, 4, 7));
-    assert(part_eq(partitions->__partition(2), v, 7, 10));
-    assert(part_eq(partitions->__partition(3), v, 10, 13));
-    assert(part_eq(partitions->__partition(4), v, 13, 16));
-    assert(part_eq(partitions->__partition(5), v, 16, 19));
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 3, 0, 1, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 6);
+    assert(partitions.__value_->__end() == std::prev(v.end(), 1));
+    assert(part_eq(partitions.__value_->__partition(0), v, 0, 4));
+    assert(part_eq(partitions.__value_->__partition(1), v, 4, 7));
+    assert(part_eq(partitions.__value_->__partition(2), v, 7, 10));
+    assert(part_eq(partitions.__value_->__partition(3), v, 10, 13));
+    assert(part_eq(partitions.__value_->__partition(4), v, 13, 16));
+    assert(part_eq(partitions.__value_->__partition(5), v, 16, 19));
   }
   { // 20 elements, min_size=3, prefix_skip=1, suffix_skip=1, 2 workers: 6 partitions
     // [0..4), [4..8), [8..11), [11..14), [14..17), [17..20)
     Container v(20);
-    std::__pstl::__statpart::__partitioning_result result;
-    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), result, 3, 1, 1, 2);
-    assert(partitions != std::nullopt);
-    assert(result == std::__pstl::__statpart::__partitioning_result::__ok);
-    assert(partitions->__partitions_count() == 6);
-    assert(partitions->__end() == std::prev(v.end(), 1));
-    assert(part_eq(partitions->__partition(0), v, 1, 4));
-    assert(part_eq(partitions->__partition(1), v, 4, 7));
-    assert(part_eq(partitions->__partition(2), v, 7, 10));
-    assert(part_eq(partitions->__partition(3), v, 10, 13));
-    assert(part_eq(partitions->__partition(4), v, 13, 16));
-    assert(part_eq(partitions->__partition(5), v, 16, 19));
+    const auto partitions = std::__pstl::__statpart::__partition(v.begin(), v.end(), 3, 1, 1, 2);
+    assert(partitions.__value_ != std::nullopt);
+    assert(partitions.__status_ == std::__pstl::__statpart::__partitioning_status::__ok);
+    assert(partitions.__value_->__partitions_count() == 6);
+    assert(partitions.__value_->__end() == std::prev(v.end(), 1));
+    assert(part_eq(partitions.__value_->__partition(0), v, 1, 4));
+    assert(part_eq(partitions.__value_->__partition(1), v, 4, 7));
+    assert(part_eq(partitions.__value_->__partition(2), v, 7, 10));
+    assert(part_eq(partitions.__value_->__partition(3), v, 10, 13));
+    assert(part_eq(partitions.__value_->__partition(4), v, 13, 16));
+    assert(part_eq(partitions.__value_->__partition(5), v, 16, 19));
   }
 }
 

>From 7ed5cb6b3dbab77dcd119404349f668033697241 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 15 Oct 2026 18:22:59 +0100
Subject: [PATCH 21/24] Brought a custom implementation of any_of() back

---
 libcxx/include/CMakeLists.txt                 |   3 +-
 libcxx/include/__pstl/backends/statpart.h     |   1 +
 .../include/__pstl/backends/statpart/any_of.h | 109 ++++++++++++++++++
 .../include/__pstl/backends/statpart/basis.h  |  12 +-
 libcxx/include/module.modulemap.in            |   3 +
 5 files changed, 121 insertions(+), 7 deletions(-)
 create mode 100644 libcxx/include/__pstl/backends/statpart/any_of.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 91081893079c1b..3a436816468991 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -695,7 +695,8 @@ set(files
   __pstl/backends/default.h
   __pstl/backends/libdispatch.h
   __pstl/backends/serial.h
-  __pstl/backends/statpart.h  
+  __pstl/backends/statpart.h
+  __pstl/backends/statpart/any_of.h
   __pstl/backends/statpart/basis.h
   __pstl/backends/statpart/find_end.h
   __pstl/backends/statpart/find_if.h
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index a77671588874ff..a3a9427fb96e7e 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___PSTL_BACKENDS_STATPART_H
 #define _LIBCPP___PSTL_BACKENDS_STATPART_H
 
+#include <__pstl/backends/statpart/any_of.h>
 #include <__pstl/backends/statpart/basis.h>
 #include <__pstl/backends/statpart/find_end.h>
 #include <__pstl/backends/statpart/find_if.h>
diff --git a/libcxx/include/__pstl/backends/statpart/any_of.h b/libcxx/include/__pstl/backends/statpart/any_of.h
new file mode 100644
index 00000000000000..5b966e6a651379
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/any_of.h
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_ANY_OF_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_ANY_OF_H
+
+#include <__algorithm/any_of.h>
+#include <__assert>
+#include <__atomic/atomic.h>
+#include <__atomic/memory_order.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__optional/nullopt_t.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
+#include <cstdint>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
+namespace __pstl {
+
+template <class _Index, class _Brick>
+_LIBCPP_HIDE_FROM_ABI optional<bool> __parallel_or(_Index __first, _Index __last, _Brick __f) {
+  std::atomic<bool> __found(false);
+  auto __ret = __statpart::__for_each(__first, __last, [__f, &__found](_Index __i, _Index __j) {
+    if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) {
+      __found.store(true, std::memory_order_relaxed);
+    }
+  });
+  if (!__ret)
+    return nullopt;
+  return static_cast<bool>(__found);
+}
+
+// TODO: check whether __simd_first() can be used here
+template <class _Index, class _DifferenceType, class _Pred>
+_LIBCPP_HIDE_FROM_ABI bool __simd_or(_Index __first, _DifferenceType __n, _Pred __pred) noexcept {
+  _DifferenceType __block_size = 4 < __n ? 4 : __n;
+  const _Index __last          = __first + __n;
+  while (__last != __first) {
+    int32_t __flag = 1;
+    _PSTL_PRAGMA_SIMD_REDUCTION(& : __flag)
+    for (_DifferenceType __i = 0; __i < __block_size; ++__i)
+      if (__pred(*(__first + __i)))
+        __flag = 0;
+    if (!__flag)
+      return true;
+
+    __first += __block_size;
+    if (__last - __first >= __block_size << 1) {
+      // Double the block _Size.  Any unnecessary iterations can be amortized against work done so far.
+      __block_size <<= 1;
+    } else {
+      __block_size = __last - __first;
+    }
+  }
+  return false;
+}
+
+template <class _ExecutionPolicy>
+struct __any_of<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<bool>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __pstl::__parallel_or(
+          __first, __last, [&__policy, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            using _AnyOfUnseq = __pstl::__any_of<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            auto __res = _AnyOfUnseq()(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __pred);
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+            return *std::move(__res);
+          });
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __pstl::__simd_or(__first, __last - __first, __pred);
+    } else {
+      return std::any_of(__first, __last, __pred);
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_ANY_OF_H
diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
index 2efe82f7c07a36..a59e9f18e4cb28 100644
--- a/libcxx/include/__pstl/backends/statpart/basis.h
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -129,16 +129,16 @@ struct _LIBCPP_HIDE_FROM_ABI __partitioning_result {
 // before partitioning.
 // __workers_count is normally implicitly queried from hardware_concurrency() and should be explicitly specified only in
 // unit tests.
-template <class _ForwardIterator>
-_LIBCPP_HIDE_FROM_ABI __partitioning_result<_ForwardIterator>
-__partition(_ForwardIterator __first,
-            _ForwardIterator __last,
+template <class _Iterator>
+_LIBCPP_HIDE_FROM_ABI __partitioning_result<_Iterator>
+__partition(_Iterator __first,
+            _Iterator __last,
             size_t __min_partition_size = 1,
             size_t __prefix_to_skip     = 0,
             size_t __suffix_to_skip     = 0,
             size_t __workers_count      = thread::hardware_concurrency()) noexcept {
   // Forward iterators will be supported later.
-  static_assert(__has_random_access_iterator_category_or_concept<_ForwardIterator>::value);
+  static_assert(__has_random_access_iterator_category_or_concept<_Iterator>::value);
 
   _LIBCPP_ASSERT_INTERNAL(__min_partition_size >= 1, "minimum partition size must be at least 1 element");
 
@@ -161,7 +161,7 @@ __partition(_ForwardIterator __first,
     return {nullopt, __partitioning_status::__not_enough_elements};
   }
 
-  __iterator_partitions<_ForwardIterator> __p;
+  __iterator_partitions<_Iterator> __p;
   __p.__base_             = __first + __prefix_to_skip;
   __p.__count_            = __effective_count;
   __p.__partition_size_   = __effective_count / __partition_count;
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 4f63030a73cf32..19e2298c504e4b 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2422,6 +2422,9 @@ module std {
         export std_core.utility_core.empty
       }
       module statpart {
+        module any_of {
+          header "__pstl/backends/statpart/any_of.h"
+        }
         module basis {
           header "__pstl/backends/statpart/basis.h"
         }

>From 88f1fc9008fb1ec84d57ada72b99af3bf40d6276 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 16 Oct 2026 12:47:18 +0100
Subject: [PATCH 22/24] Brought back fill() as well

---
 libcxx/include/CMakeLists.txt                 |  1 +
 libcxx/include/__pstl/backends/statpart.h     |  1 +
 .../include/__pstl/backends/statpart/fill.h   | 70 +++++++++++++++++++
 libcxx/include/module.modulemap.in            |  3 +
 4 files changed, 75 insertions(+)
 create mode 100644 libcxx/include/__pstl/backends/statpart/fill.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 3a436816468991..ab985fb3579932 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -698,6 +698,7 @@ set(files
   __pstl/backends/statpart.h
   __pstl/backends/statpart/any_of.h
   __pstl/backends/statpart/basis.h
+  __pstl/backends/statpart/fill.h
   __pstl/backends/statpart/find_end.h
   __pstl/backends/statpart/find_if.h
   __pstl/backends/statpart/for_each.h
diff --git a/libcxx/include/__pstl/backends/statpart.h b/libcxx/include/__pstl/backends/statpart.h
index a3a9427fb96e7e..82665e66557ec1 100644
--- a/libcxx/include/__pstl/backends/statpart.h
+++ b/libcxx/include/__pstl/backends/statpart.h
@@ -11,6 +11,7 @@
 
 #include <__pstl/backends/statpart/any_of.h>
 #include <__pstl/backends/statpart/basis.h>
+#include <__pstl/backends/statpart/fill.h>
 #include <__pstl/backends/statpart/find_end.h>
 #include <__pstl/backends/statpart/find_if.h>
 #include <__pstl/backends/statpart/for_each.h>
diff --git a/libcxx/include/__pstl/backends/statpart/fill.h b/libcxx/include/__pstl/backends/statpart/fill.h
new file mode 100644
index 00000000000000..1195505fcb00f0
--- /dev/null
+++ b/libcxx/include/__pstl/backends/statpart/fill.h
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_BACKENDS_STATPART_FILL_H
+#define _LIBCPP___PSTL_BACKENDS_STATPART_FILL_H
+
+#include <__algorithm/fill.h>
+#include <__assert>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/backends/statpart/basis.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/empty.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace __pstl {
+
+template <class _Index, class _DifferenceType, class _Tp>
+_LIBCPP_HIDE_FROM_ABI _Index __simd_fill_n(_Index __first, _DifferenceType __n, const _Tp& __value) noexcept {
+  _PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED
+  _PSTL_PRAGMA_SIMD
+  for (_DifferenceType __i = 0; __i < __n; ++__i)
+    __first[__i] = __value;
+  return __first + __n;
+}
+
+template <class _ExecutionPolicy>
+struct __fill<__statpart_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _Tp>
+  _LIBCPP_HIDE_FROM_ABI optional<__empty>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      return __statpart::__for_each(
+          __first, __last, [&__policy, &__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            using _FillUnseq = __pstl::__fill<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            [[maybe_unused]] auto __res =
+                _FillUnseq()(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __value);
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+          });
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      __pstl::__simd_fill_n(__first, __last - __first, __value);
+      return __empty{};
+    } else {
+      std::fill(__first, __last, __value);
+      return __empty{};
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+#endif // _LIBCPP___PSTL_BACKENDS_STATPART_FILL_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 19e2298c504e4b..0998d26d205f66 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2428,6 +2428,9 @@ module std {
         module basis {
           header "__pstl/backends/statpart/basis.h"
         }
+        module fill {
+          header "__pstl/backends/statpart/fill.h"
+        }
         module find_end {
           header "__pstl/backends/statpart/find_end.h"
         }

>From 25e852e271fe86cd7525a955a284dc8616fc5a87 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 16 Oct 2026 13:03:03 +0100
Subject: [PATCH 23/24] Brought back the unseq codepath in find_if()

---
 .../include/__pstl/backends/statpart/basis.h  |  2 +
 .../__pstl/backends/statpart/find_if.h        | 53 +++++++++++++++++--
 2 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__pstl/backends/statpart/basis.h b/libcxx/include/__pstl/backends/statpart/basis.h
index a59e9f18e4cb28..349d16ae57d27c 100644
--- a/libcxx/include/__pstl/backends/statpart/basis.h
+++ b/libcxx/include/__pstl/backends/statpart/basis.h
@@ -64,6 +64,8 @@ constexpr inline size_t __max_partitions_per_cpu = 8;
 // The minimum number of elements to sort serially in a single partition
 constexpr inline size_t __min_sort_partition_size = 256;
 
+constexpr inline size_t __lane_size = 64;
+
 enum class __partitioning_status {
   // Returned when the partitioning result is not a nullopt.
   __ok,
diff --git a/libcxx/include/__pstl/backends/statpart/find_if.h b/libcxx/include/__pstl/backends/statpart/find_if.h
index 0913e91a18e3f2..8130d99d810c69 100644
--- a/libcxx/include/__pstl/backends/statpart/find_if.h
+++ b/libcxx/include/__pstl/backends/statpart/find_if.h
@@ -35,21 +35,68 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl {
 
+template <class _Index, class _DifferenceType, class _Compare>
+_LIBCPP_HIDE_FROM_ABI _Index
+__simd_first(_Index __first, _DifferenceType __begin, _DifferenceType __end, _Compare __comp) noexcept {
+  // Experiments show good block sizes like this
+  const _DifferenceType __block_size                                    = 8;
+  alignas(__statpart::__lane_size) _DifferenceType __lane[__block_size] = {0};
+  while (__end - __begin >= __block_size) {
+    _DifferenceType __found = 0;
+    _PSTL_PRAGMA_SIMD_REDUCTION(| : __found) for (_DifferenceType __i = __begin; __i < __begin + __block_size; ++__i) {
+      const _DifferenceType __t = __comp(__first, __i);
+      __lane[__i - __begin]     = __t;
+      __found |= __t;
+    }
+    if (__found) {
+      _DifferenceType __i;
+      // This will vectorize
+      for (__i = 0; __i < __block_size; ++__i) {
+        if (__lane[__i]) {
+          break;
+        }
+      }
+      return __first + __begin + __i;
+    }
+    __begin += __block_size;
+  }
+
+  // Keep remainder scalar
+  while (__begin != __end) {
+    if (__comp(__first, __begin)) {
+      return __first + __begin;
+    }
+    ++__begin;
+  }
+  return __first + __end;
+}
+
 template <class _ExecutionPolicy>
 struct __find_if<__statpart_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Predicate>
   _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
-  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept {
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept {
     if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
                   __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
       return __statpart::__find(
           std::move(__first),
           std::move(__last),
-          [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
-            return std::find_if(__brick_first, __brick_last, __pred);
+          [&__policy, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+            using _FindIfUnseq =
+                __pstl::__find_if<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            auto __res = _FindIfUnseq()(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __pred);
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
+            return *std::move(__res);
           },
           less<>{},
           true);
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      using __diff_t = __iterator_difference_type<_ForwardIterator>;
+      return __pstl::__simd_first(
+          __first, __diff_t(0), __last - __first, [&__pred](_ForwardIterator __iter, __diff_t __i) {
+            return __pred(__iter[__i]);
+          });
     } else {
       return std::find_if(std::move(__first), std::move(__last), std::move(__pred));
     }

>From 5977033c8d2ed76aa9644f966e75dc5cd7e5d457 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 16 Oct 2026 13:14:34 +0100
Subject: [PATCH 24/24] Brought back unseq in for_each()

---
 .../__pstl/backends/statpart/for_each.h       | 21 +++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__pstl/backends/statpart/for_each.h b/libcxx/include/__pstl/backends/statpart/for_each.h
index 53aeef91fad574..7fecc50a9cce12 100644
--- a/libcxx/include/__pstl/backends/statpart/for_each.h
+++ b/libcxx/include/__pstl/backends/statpart/for_each.h
@@ -34,17 +34,34 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 namespace __pstl {
 
+template <class _Iterator, class _DifferenceType, class _Function>
+_LIBCPP_HIDE_FROM_ABI _Iterator __simd_for_each(_Iterator __first, _DifferenceType __n, _Function __f) noexcept {
+  _PSTL_PRAGMA_SIMD
+  for (_DifferenceType __i = 0; __i < __n; ++__i)
+    __f(__first[__i]);
+
+  return __first + __n;
+}
+
 template <class _ExecutionPolicy>
 struct __for_each<__statpart_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Function>
   _LIBCPP_HIDE_FROM_ABI optional<__empty>
-  operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __func) const noexcept {
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Function __func) const noexcept {
     if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
                   __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
       return __statpart::__for_each(
           std::move(__first), std::move(__last), [&](auto __partition_first, auto __partition_last) {
-            std::for_each(__partition_first, __partition_last, __func);
+            using _ForEachUnseq =
+                __pstl::__for_each<__statpart_backend_tag, __remove_parallel_policy_t<_ExecutionPolicy>>;
+            [[maybe_unused]] auto __res =
+                _ForEachUnseq()(std::__remove_parallel_policy(__policy), __partition_first, __partition_last, __func);
+            _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
           });
+    } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+                         __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+      __pstl::__simd_for_each(__first, __last - __first, __func);
+      return __empty{};
     } else {
       std::for_each(std::move(__first), std::move(__last), std::move(__func));
       return __empty{};



More information about the libcxx-commits mailing list