[libcxx-commits] [libcxx] [libc++][c++17] P0452: Implementing PSTL overloads for `std::transform_{ex, in}clusive_scan` (PR #195548)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue May 5 14:04:39 PDT 2026
https://github.com/PaulXiCao updated https://github.com/llvm/llvm-project/pull/195548
>From 8301a5ae47251c0c760aa9dc39b114f23cc5532b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 12:44:33 +0200
Subject: [PATCH 01/23] mark paper status as complete
---
libcxx/docs/Status/Cxx17Papers.csv | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/docs/Status/Cxx17Papers.csv b/libcxx/docs/Status/Cxx17Papers.csv
index ba2ceeedc2ce8..c3e6c4d16c6b4 100644
--- a/libcxx/docs/Status/Cxx17Papers.csv
+++ b/libcxx/docs/Status/Cxx17Papers.csv
@@ -95,7 +95,7 @@
"`P0317R1 <https://wg21.link/P0317R1>`__","Directory Entry Caching for Filesystem","2017-02 (Kona)","|Complete|","7","`#103684 <https://github.com/llvm/llvm-project/issues/103684>`__",""
"`P0430R2 <https://wg21.link/P0430R2>`__","File system library on non-POSIX-like operating systems","2017-02 (Kona)","|Complete|","7","`#103685 <https://github.com/llvm/llvm-project/issues/103685>`__",""
"`P0433R2 <https://wg21.link/P0433R2>`__","Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library","2017-02 (Kona)","|Complete|","14","`#103686 <https://github.com/llvm/llvm-project/issues/103686>`__",""
-"`P0452R1 <https://wg21.link/P0452R1>`__","Unifying <numeric> Parallel Algorithms","2017-02 (Kona)","|Partial|","","`#99948 <https://github.com/llvm/llvm-project/issues/99948>`__","The changes to ``std::transform_inclusive_scan`` and ``std::transform_exclusive_scan`` have not yet been implemented."
+"`P0452R1 <https://wg21.link/P0452R1>`__","Unifying <numeric> Parallel Algorithms","2017-02 (Kona)","|Complete|","","`#99948 <https://github.com/llvm/llvm-project/issues/99948>`__",""
"`P0467R2 <https://wg21.link/P0467R2>`__","Iterator Concerns for Parallel Algorithms","2017-02 (Kona)","|Partial|","","`#99949 <https://github.com/llvm/llvm-project/issues/99949>`__",""
"`P0492R2 <https://wg21.link/P0492R2>`__","Proposed Resolution of C++17 National Body Comments for Filesystems","2017-02 (Kona)","|Complete|","7","`#103687 <https://github.com/llvm/llvm-project/issues/103687>`__",""
"`P0518R1 <https://wg21.link/P0518R1>`__","Allowing copies as arguments to function objects given to parallel algorithms in response to CH11","2017-02 (Kona)","|Nothing To Do|","","`#103689 <https://github.com/llvm/llvm-project/issues/103689>`__",""
>From 60d06f0b569478b21882830fcd886bffdc5d3cfe Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 12:44:47 +0200
Subject: [PATCH 02/23] backend_fwd: __transform_exclusive_scan
---
libcxx/include/__pstl/backend_fwd.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index a52e6db954d0c..3cad5b8c461f0 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -303,6 +303,17 @@ struct __is_sorted;
// optional<bool>
// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Comp&& __comp) const noexcept;
+template <class _Backend, class _ExecutionPolicy>
+struct __transform_exclusive_scan;
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2,
+// class _Tp, class _BinaryOperation, class _UnaryOperation>
+// optional<_ForwardIterator2>
+// operator()(_Policy&&,
+// _ForwardIterator1 __first, _ForwardIterator1 __last,
+// _ForwardIterator2 __result,
+// _Tp __init,
+// _BinaryOperation __binary_op,
+// _UnaryOperation __unary_op) const noexcept;
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
>From 74bfc8ad3df48b1b158aa55e4a8bf3553cb66e5f Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 19:05:10 +0200
Subject: [PATCH 03/23] backend_fwd: __transform_inclusive_scan
---
libcxx/include/__pstl/backend_fwd.h | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index 3cad5b8c461f0..bf0e3cd47488f 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -314,6 +314,27 @@ struct __transform_exclusive_scan;
// _Tp __init,
// _BinaryOperation __binary_op,
// _UnaryOperation __unary_op) const noexcept;
+
+template <class _Backend, class _ExecutionPolicy>
+struct __transform_inclusive_scan;
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2,
+// class _BinaryOperation, class _UnaryOperation>
+// optional<_ForwardIterator2>
+// operator()(_Policy&&,
+// _ForwardIterator1 __first, _ForwardIterator1 __last,
+// _ForwardIterator2 __result,
+// _BinaryOperation __binary_op,
+// _UnaryOperation __unary_op) const noexcept;
+//
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2,
+// class _BinaryOperation, class _UnaryOperation, class _Tp>
+// optional<_ForwardIterator2>
+// operator()(_Policy&&,
+// _ForwardIterator1 __first, _ForwardIterator1 __last,
+// _ForwardIterator2 __result,
+// _BinaryOperation __binary_op,
+// _UnaryOperation __unary_op,
+// _Tp __init) const noexcept;
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
>From 6077b955a9d72c7da60438adafa5a6a6cd6b850b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 19:17:45 +0200
Subject: [PATCH 04/23] transform_exclusive_scan for __serial_backend_tag
---
libcxx/include/__pstl/backends/serial.h | 27 +++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/libcxx/include/__pstl/backends/serial.h b/libcxx/include/__pstl/backends/serial.h
index f4142016ccc79..a96b79eded118 100644
--- a/libcxx/include/__pstl/backends/serial.h
+++ b/libcxx/include/__pstl/backends/serial.h
@@ -16,6 +16,7 @@
#include <__algorithm/stable_sort.h>
#include <__algorithm/transform.h>
#include <__config>
+#include <__numeric/transform_exclusive_scan.h>
#include <__numeric/transform_reduce.h>
#include <__pstl/backend_fwd.h>
#include <__utility/empty.h>
@@ -175,6 +176,32 @@ struct __transform_reduce_binary<__serial_backend_tag, _ExecutionPolicy> {
}
};
+template <class _ExecutionPolicy>
+struct __transform_exclusive_scan<__serial_backend_tag, _ExecutionPolicy> {
+ template <class _Policy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _Tp,
+ class _BinaryOperation,
+ class _UnaryOperation>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+ _Policy&&,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _Tp __init,
+ _BinaryOperation&& __binary_op,
+ _UnaryOperation&& __unary_op) const noexcept {
+ return std::transform_exclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__init),
+ std::forward<_BinaryOperation>(__binary_op),
+ std::forward<_UnaryOperation>(__unary_op));
+ }
+};
+
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
>From f869e770057cda22d20014a175210a2cb47b4649 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 21:31:32 +0200
Subject: [PATCH 05/23] transform_inclusive_scan for __serial_backend_tag
---
libcxx/include/__pstl/backends/serial.h | 46 +++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/libcxx/include/__pstl/backends/serial.h b/libcxx/include/__pstl/backends/serial.h
index a96b79eded118..5bae6397bcc53 100644
--- a/libcxx/include/__pstl/backends/serial.h
+++ b/libcxx/include/__pstl/backends/serial.h
@@ -17,6 +17,7 @@
#include <__algorithm/transform.h>
#include <__config>
#include <__numeric/transform_exclusive_scan.h>
+#include <__numeric/transform_inclusive_scan.h>
#include <__numeric/transform_reduce.h>
#include <__pstl/backend_fwd.h>
#include <__utility/empty.h>
@@ -202,6 +203,51 @@ struct __transform_exclusive_scan<__serial_backend_tag, _ExecutionPolicy> {
}
};
+template <class _ExecutionPolicy>
+struct __transform_inclusive_scan<__serial_backend_tag, _ExecutionPolicy> {
+ template <class _Policy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _BinaryOperation,
+ class _UnaryOperation>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2>
+ operator()(_Policy&&,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _BinaryOperation&& __binary_op,
+ _UnaryOperation&& __unary_op) const noexcept {
+ return std::transform_inclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::forward<_BinaryOperation>(__binary_op),
+ std::forward<_UnaryOperation>(__unary_op));
+ }
+
+ template <class _Policy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _BinaryOperation,
+ class _UnaryOperation,
+ class _Tp>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+ _Policy&&,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _BinaryOperation&& __binary_op,
+ _UnaryOperation&& __unary_op,
+ _Tp __init) const noexcept {
+ return std::transform_inclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::forward<_BinaryOperation>(__binary_op),
+ std::forward<_UnaryOperation>(__unary_op),
+ std::move(__init));
+ }
+};
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
>From 5dd255fe68ac956e2735e94cc67c265f8c822c4b Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 21:42:37 +0200
Subject: [PATCH 06/23] transform_*_scan for default_backend
---
libcxx/include/__pstl/backends/default.h | 77 ++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index be90715af13b5..9762124f3d9ce 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -21,6 +21,8 @@
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/next.h>
+#include <__numeric/transform_exclusive_scan.h>
+#include <__numeric/transform_inclusive_scan.h>
#include <__pstl/backend_fwd.h>
#include <__pstl/dispatch.h>
#include <__utility/empty.h>
@@ -420,6 +422,81 @@ struct __is_sorted<__default_backend_tag, _ExecutionPolicy> {
}
};
+//////////////////////////////////////////////////////////////
+// transform_*clusive_scan family
+//////////////////////////////////////////////////////////////
+template <class _ExecutionPolicy>
+struct __transform_exclusive_scan<__default_backend_tag, _ExecutionPolicy> {
+ template <class _Policy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _Tp,
+ class _BinaryOperation,
+ class _UnaryOperation>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+ _Policy&&,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _Tp __init,
+ _BinaryOperation&& __binary_op,
+ _UnaryOperation&& __unary_op) const noexcept {
+ return std::transform_exclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__init),
+ std::forward<_BinaryOperation>(__binary_op),
+ std::forward<_UnaryOperation>(__unary_op));
+ }
+};
+
+template <class _ExecutionPolicy>
+struct __transform_inclusive_scan<__default_backend_tag, _ExecutionPolicy> {
+ template <class _Policy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _BinaryOperation,
+ class _UnaryOperation>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2>
+ operator()(_Policy&&,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _BinaryOperation&& __binary_op,
+ _UnaryOperation&& __unary_op) const noexcept {
+ return std::transform_inclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::forward<_BinaryOperation>(__binary_op),
+ std::forward<_UnaryOperation>(__unary_op));
+ }
+
+ template <class _Policy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _BinaryOperation,
+ class _UnaryOperation,
+ class _Tp>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+ _Policy&&,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _BinaryOperation&& __binary_op,
+ _UnaryOperation&& __unary_op,
+ _Tp __init) const noexcept {
+ return std::transform_inclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::forward<_BinaryOperation>(__binary_op),
+ std::forward<_UnaryOperation>(__unary_op),
+ std::move(__init));
+ }
+};
+
//////////////////////////////////////////////////////////////
// transform family
//////////////////////////////////////////////////////////////
>From ba42c590fcdf6d8072217f7d4fc4a138f0e81c88 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 21:56:43 +0200
Subject: [PATCH 07/23] pstl: transform_exclusive_scan
---
libcxx/include/__numeric/pstl.h | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/libcxx/include/__numeric/pstl.h b/libcxx/include/__numeric/pstl.h
index fe7b2cc7a82cc..442b32e8ab12a 100644
--- a/libcxx/include/__numeric/pstl.h
+++ b/libcxx/include/__numeric/pstl.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___NUMERIC_PSTL_H
#define _LIBCPP___NUMERIC_PSTL_H
+#include "__pstl/backend_fwd.h"
#include <__config>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -165,6 +166,36 @@ _LIBCPP_HIDE_FROM_ABI _Tp transform_reduce(
std::move(__transform));
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _Tp,
+ class _BinaryOperation,
+ class _UnaryOperation,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardIterator2 transform_exclusive_scan(
+ _ExecutionPolicy&& __policy,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _Tp __init,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "transform_exclusive_scan requires ForwardIterators");
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "transform_exclusive_scan requires ForwardIterators");
+ using _Implementation =
+ __pstl::__dispatch<__pstl::__transform_exclusive_scan, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy),
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__init),
+ std::move(__binary_op),
+ std::move(__unary_op));
+}
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_HAS_EXPERIMENTAL_PSTL && _LIBCPP_STD_VER >= 17
>From 966477d08be10e8c7886db1ef2f5cb2e67b64aea Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 21:59:45 +0200
Subject: [PATCH 08/23] pstl: transform_inclusive_scan
---
libcxx/include/__numeric/pstl.h | 57 +++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/libcxx/include/__numeric/pstl.h b/libcxx/include/__numeric/pstl.h
index 442b32e8ab12a..41ba3c85c2366 100644
--- a/libcxx/include/__numeric/pstl.h
+++ b/libcxx/include/__numeric/pstl.h
@@ -196,6 +196,63 @@ _LIBCPP_HIDE_FROM_ABI _ForwardIterator2 transform_exclusive_scan(
std::move(__unary_op));
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _BinaryOperation,
+ class _UnaryOperation,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardIterator2 transform_inclusive_scan(
+ _ExecutionPolicy&& __policy,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "transform_inclusive_scan requires ForwardIterators");
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "transform_inclusive_scan requires ForwardIterators");
+ using _Implementation =
+ __pstl::__dispatch<__pstl::__transform_inclusive_scan, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy),
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__binary_op),
+ std::move(__unary_op));
+}
+
+template <class _ExecutionPolicy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _Tp,
+ class _BinaryOperation,
+ class _UnaryOperation,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardIterator2 transform_inclusive_scan(
+ _ExecutionPolicy&& __policy,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op,
+ _Tp __init) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "transform_inclusive_scan requires ForwardIterators");
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "transform_inclusive_scan requires ForwardIterators");
+ using _Implementation =
+ __pstl::__dispatch<__pstl::__transform_inclusive_scan, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy),
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__binary_op),
+ std::move(__unary_op),
+ std::move(__init));
+}
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_HAS_EXPERIMENTAL_PSTL && _LIBCPP_STD_VER >= 17
>From db659b7bd9c74b172ec29b7425336485b65420f3 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 22:21:30 +0200
Subject: [PATCH 09/23] tests
---
.../pstl.transform_exclusive_scan.pass.cpp | 73 +++++++++++
.../pstl.transform_inclusive_scan.pass.cpp | 118 ++++++++++++++++++
2 files changed, 191 insertions(+)
create mode 100644 libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
create mode 100644 libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
diff --git a/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
new file mode 100644
index 0000000000000..506c83ea6ccbd
--- /dev/null
+++ b/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// <numeric>
+
+// template<class ExecutionPolicy,
+// class ForwardIterator1, class ForwardIterator2, class T,
+// class BinaryOperation, class UnaryOperation>
+// ForwardIterator2
+// transform_exclusive_scan(ExecutionPolicy&& exec,
+// ForwardIterator1 first, ForwardIterator1 last,
+// ForwardIterator2 result,
+// T init,
+// BinaryOperation binary_op,
+// UnaryOperation unary_op);
+
+#include <cassert>
+#include <numeric>
+#include <string>
+#include <vector>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "type_algorithms.h"
+
+template <class Iter>
+struct Test {
+ template <class Policy>
+ void operator()(Policy&& policy) {
+ for (int size : {0, 1, 2, 100, 350}) {
+ std::vector<int> a(size);
+ for (int i = 0; i != size; ++i)
+ a[i] = i;
+
+ std::vector<int> expected(size);
+ std::transform_exclusive_scan(
+ a.begin(), a.end(), expected.begin(), 0, std::plus{}, [](int x) { return x + 1; });
+
+ std::vector<int> result(size);
+ auto ret = std::transform_exclusive_scan(
+ policy,
+ Iter(std::data(a)),
+ Iter(std::data(a) + std::size(a)),
+ std::data(result),
+ 0,
+ [check = std::string("Banane")](int i, int j) {
+ assert(check == "Banane");
+ return i + j;
+ },
+ [check = std::string("Banane")](int i) {
+ assert(check == "Banane");
+ return i + 1;
+ });
+ static_assert(std::is_same_v<decltype(ret), int*>);
+ assert(ret == std::data(result) + size);
+ assert(result == expected);
+ }
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
+ return 0;
+}
diff --git a/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
new file mode 100644
index 0000000000000..54c800a29f243
--- /dev/null
+++ b/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
@@ -0,0 +1,118 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// <numeric>
+
+// template<class ExecutionPolicy,
+// class ForwardIterator1, class ForwardIterator2,
+// class BinaryOperation, class UnaryOperation>
+// ForwardIterator2
+// transform_inclusive_scan(ExecutionPolicy&& exec,
+// ForwardIterator1 first, ForwardIterator1 last,
+// ForwardIterator2 result,
+// BinaryOperation binary_op,
+// UnaryOperation unary_op);
+//
+// template<class ExecutionPolicy,
+// class ForwardIterator1, class ForwardIterator2,
+// class BinaryOperation, class UnaryOperation, class T>
+// ForwardIterator2
+// transform_inclusive_scan(ExecutionPolicy&& exec,
+// ForwardIterator1 first, ForwardIterator1 last,
+// ForwardIterator2 result,
+// BinaryOperation binary_op,
+// UnaryOperation unary_op,
+// T init);
+
+#include <cassert>
+#include <numeric>
+#include <string>
+#include <vector>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "type_algorithms.h"
+
+template <class Iter>
+struct TestNoInit {
+ template <class Policy>
+ void operator()(Policy&& policy) {
+ for (int size : {0, 1, 2, 100, 350}) {
+ std::vector<int> a(size);
+ for (int i = 0; i != size; ++i)
+ a[i] = i + 1;
+
+ std::vector<int> expected(size);
+ std::transform_inclusive_scan(
+ a.begin(), a.end(), expected.begin(), std::plus{}, [](int x) { return x + 1; });
+
+ std::vector<int> result(size);
+ auto ret = std::transform_inclusive_scan(
+ policy,
+ Iter(std::data(a)),
+ Iter(std::data(a) + std::size(a)),
+ std::data(result),
+ [check = std::string("Banane")](int i, int j) {
+ assert(check == "Banane");
+ return i + j;
+ },
+ [check = std::string("Banane")](int i) {
+ assert(check == "Banane");
+ return i + 1;
+ });
+ static_assert(std::is_same_v<decltype(ret), int*>);
+ assert(ret == std::data(result) + size);
+ assert(result == expected);
+ }
+ }
+};
+
+template <class Iter>
+struct TestWithInit {
+ template <class Policy>
+ void operator()(Policy&& policy) {
+ for (int size : {0, 1, 2, 100, 350}) {
+ std::vector<int> a(size);
+ for (int i = 0; i != size; ++i)
+ a[i] = i;
+
+ std::vector<int> expected(size);
+ std::transform_inclusive_scan(
+ a.begin(), a.end(), expected.begin(), std::plus{}, [](int x) { return x + 1; }, 100);
+
+ std::vector<int> result(size);
+ auto ret = std::transform_inclusive_scan(
+ policy,
+ Iter(std::data(a)),
+ Iter(std::data(a) + std::size(a)),
+ std::data(result),
+ [check = std::string("Banane")](int i, int j) {
+ assert(check == "Banane");
+ return i + j;
+ },
+ [check = std::string("Banane")](int i) {
+ assert(check == "Banane");
+ return i + 1;
+ },
+ 100);
+ static_assert(std::is_same_v<decltype(ret), int*>);
+ assert(ret == std::data(result) + size);
+ assert(result == expected);
+ }
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<TestNoInit>{});
+ types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<TestWithInit>{});
+ return 0;
+}
>From 177f4cae3a22124503a5e5ba7e72d63aa7397ae6 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Sun, 3 May 2026 22:30:57 +0200
Subject: [PATCH 10/23] format tests
---
.../pstl.transform_exclusive_scan.pass.cpp | 3 +--
.../pstl.transform_inclusive_scan.pass.cpp | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
index 506c83ea6ccbd..d796bb5e75425 100644
--- a/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
@@ -42,8 +42,7 @@ struct Test {
a[i] = i;
std::vector<int> expected(size);
- std::transform_exclusive_scan(
- a.begin(), a.end(), expected.begin(), 0, std::plus{}, [](int x) { return x + 1; });
+ std::transform_exclusive_scan(a.begin(), a.end(), expected.begin(), 0, std::plus{}, [](int x) { return x + 1; });
std::vector<int> result(size);
auto ret = std::transform_exclusive_scan(
diff --git a/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
index 54c800a29f243..0951790a56ba2 100644
--- a/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
@@ -52,8 +52,7 @@ struct TestNoInit {
a[i] = i + 1;
std::vector<int> expected(size);
- std::transform_inclusive_scan(
- a.begin(), a.end(), expected.begin(), std::plus{}, [](int x) { return x + 1; });
+ std::transform_inclusive_scan(a.begin(), a.end(), expected.begin(), std::plus{}, [](int x) { return x + 1; });
std::vector<int> result(size);
auto ret = std::transform_inclusive_scan(
>From 0837bb2f6c26e4c503da270b8d6c10c73e590ffa Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 4 May 2026 21:25:58 +0200
Subject: [PATCH 11/23] cpu traits: comments about transform_scans
---
libcxx/include/__pstl/cpu_algos/cpu_traits.h | 27 ++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/libcxx/include/__pstl/cpu_algos/cpu_traits.h b/libcxx/include/__pstl/cpu_algos/cpu_traits.h
index ec1622419d049..93baf43928c9c 100644
--- a/libcxx/include/__pstl/cpu_algos/cpu_traits.h
+++ b/libcxx/include/__pstl/cpu_algos/cpu_traits.h
@@ -66,6 +66,33 @@ namespace __pstl {
// Size of SIMD lanes.
// TODO: Merge this with __native_vector_size from __algorithm/simd_utils.h
//
+// Optional extended operations
+// ============================
+// Backends may specialize these to provide a parallel implementation.
+// If not specialized, the dispatch chain falls through to the next backend (typically default.h serial).
+//
+// template <class _RandomAccessIterator1, class _RandomAccessIterator2,
+// class _Tp, class _BinaryOperation, class _UnaryOperation>
+// optional<_RandomAccessIterator2>
+// __transform_exclusive_scan(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
+// _RandomAccessIterator2 __result, _Tp __init,
+// _BinaryOperation __binary_op, _UnaryOperation __unary_op);
+//
+// // without init (_Tp{} used as identity for chunk-0 offset)
+// template <class _RandomAccessIterator1, class _RandomAccessIterator2,
+// class _BinaryOperation, class _UnaryOperation>
+// optional<_RandomAccessIterator2>
+// __transform_inclusive_scan(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
+// _RandomAccessIterator2 __result,
+// _BinaryOperation __binary_op, _UnaryOperation __unary_op);
+//
+// // with init
+// template <class _RandomAccessIterator1, class _RandomAccessIterator2,
+// class _BinaryOperation, class _UnaryOperation, class _Tp>
+// optional<_RandomAccessIterator2>
+// __transform_inclusive_scan(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last,
+// _RandomAccessIterator2 __result,
+// _BinaryOperation __binary_op, _UnaryOperation __unary_op, _Tp __init);
//
// Exception handling
// ==================
>From 4664633a6fbad34ae77c32c96dfa237c0ac2a6da Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 4 May 2026 22:08:37 +0200
Subject: [PATCH 12/23] cpu_algos: dispatch for transform_exclusive_scan
---
libcxx/include/CMakeLists.txt | 1 +
.../include/__pstl/cpu_algos/transform_scan.h | 79 +++++++++++++++++++
2 files changed, 80 insertions(+)
create mode 100644 libcxx/include/__pstl/cpu_algos/transform_scan.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 497aadfd799bf..7dcf26ad24c84 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -675,6 +675,7 @@ set(files
__pstl/cpu_algos/stable_sort.h
__pstl/cpu_algos/transform.h
__pstl/cpu_algos/transform_reduce.h
+ __pstl/cpu_algos/transform_scan.h
__pstl/dispatch.h
__pstl/handle_exception.h
__random/bernoulli_distribution.h
diff --git a/libcxx/include/__pstl/cpu_algos/transform_scan.h b/libcxx/include/__pstl/cpu_algos/transform_scan.h
new file mode 100644
index 0000000000000..ea89ccad8aca0
--- /dev/null
+++ b/libcxx/include/__pstl/cpu_algos/transform_scan.h
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_CPU_ALGOS_TRANSFORM_SCAN_H
+#define _LIBCPP___PSTL_CPU_ALGOS_TRANSFORM_SCAN_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__numeric/transform_exclusive_scan.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/cpu_algos/cpu_traits.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+#include <optional>
+
+#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
+namespace __pstl {
+
+template <class _Backend, class _RawExecutionPolicy>
+struct __cpu_parallel_transform_exclusive_scan {
+ template <class _Policy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _Tp,
+ class _BinaryOperation,
+ class _UnaryOperation>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+ _Policy&&,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _Tp __init,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op) const noexcept {
+ if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+ return __cpu_traits<_Backend>::__transform_exclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__init),
+ std::move(__binary_op),
+ std::move(__unary_op));
+ } else {
+ return std::transform_exclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__init),
+ std::move(__binary_op),
+ std::move(__unary_op));
+ }
+ }
+};
+
+} // namespace __pstl
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_CPU_ALGOS_TRANSFORM_SCAN_H
>From 65b4840d7925eebc050ca58d8409cdefbda8ad8f Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 4 May 2026 22:12:34 +0200
Subject: [PATCH 13/23] cpu_algos: dispatch for transform_inclusive_scans
---
.../include/__pstl/cpu_algos/transform_scan.h | 62 +++++++++++++++++++
1 file changed, 62 insertions(+)
diff --git a/libcxx/include/__pstl/cpu_algos/transform_scan.h b/libcxx/include/__pstl/cpu_algos/transform_scan.h
index ea89ccad8aca0..9f6a5597179b8 100644
--- a/libcxx/include/__pstl/cpu_algos/transform_scan.h
+++ b/libcxx/include/__pstl/cpu_algos/transform_scan.h
@@ -13,6 +13,7 @@
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__numeric/transform_exclusive_scan.h>
+#include <__numeric/transform_inclusive_scan.h>
#include <__pstl/backend_fwd.h>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__type_traits/is_execution_policy.h>
@@ -69,6 +70,67 @@ struct __cpu_parallel_transform_exclusive_scan {
}
};
+template <class _Backend, class _RawExecutionPolicy>
+struct __cpu_parallel_transform_inclusive_scan {
+ template <class _Policy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _BinaryOperation,
+ class _UnaryOperation>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2>
+ operator()(_Policy&&,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op) const noexcept {
+ if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+ return __cpu_traits<_Backend>::__transform_inclusive_scan(
+ std::move(__first), std::move(__last), std::move(__result), std::move(__binary_op), std::move(__unary_op));
+ } else {
+ return std::transform_inclusive_scan(
+ std::move(__first), std::move(__last), std::move(__result), std::move(__binary_op), std::move(__unary_op));
+ }
+ }
+
+ template <class _Policy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _BinaryOperation,
+ class _UnaryOperation,
+ class _Tp>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator2> operator()(
+ _Policy&&,
+ _ForwardIterator1 __first,
+ _ForwardIterator1 __last,
+ _ForwardIterator2 __result,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op,
+ _Tp __init) const noexcept {
+ if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+ return __cpu_traits<_Backend>::__transform_inclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__binary_op),
+ std::move(__unary_op),
+ std::move(__init));
+ } else {
+ return std::transform_inclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__binary_op),
+ std::move(__unary_op),
+ std::move(__init));
+ }
+ }
+};
+
} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD
>From 4ea6e12093998890cdf6df87379519fdee945b4a Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 4 May 2026 23:19:00 +0200
Subject: [PATCH 14/23] libdispatch: __transform_exclusive_scan
---
libcxx/include/__pstl/backends/libdispatch.h | 77 ++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 88d4231d29a0a..ea90f2f311698 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -255,6 +255,83 @@ struct __cpu_traits<__libdispatch_backend_tag> {
__combiner);
}
+ template < class _RandomAccessIterator1,
+ class _RandomAccessIterator2,
+ class _Tp,
+ class _BinaryOperation,
+ class _UnaryOperation>
+ _LIBCPP_HIDE_FROM_ABI static optional<_RandomAccessIterator2> __transform_exclusive_scan(
+ _RandomAccessIterator1 __first,
+ _RandomAccessIterator1 __last,
+ _RandomAccessIterator2 __result,
+ _Tp __init,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op) noexcept {
+ auto __n = __last - __first;
+ if (__n == 0)
+ return __result;
+
+ auto __partitions = __libdispatch::__partition_chunks(__n);
+ auto __chunk_count = __partitions.__chunk_count_;
+
+ auto __destroy = [__chunk_count](_Tp* __ptr) {
+ std::destroy_n(__ptr, __chunk_count);
+ std::allocator<_Tp>().deallocate(__ptr, __chunk_count);
+ };
+ unique_ptr<_Tp[], decltype(__destroy)> __chunk_totals(
+ [&]() -> _Tp* {
+# if _LIBCPP_HAS_EXCEPTIONS
+ try {
+# endif
+ return std::allocator<_Tp>().allocate(__chunk_count);
+# if _LIBCPP_HAS_EXCEPTIONS
+ } catch (const std::bad_alloc&) {
+ return nullptr;
+ }
+# endif
+ }(),
+ std::move(__destroy));
+ if (!__chunk_totals)
+ return nullopt;
+
+ // Phase 1: parallel chunk totals
+ __libdispatch::__dispatch_apply(__chunk_count, [&](size_t __chunk) {
+ auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
+ auto __index = __chunk == 0 ? 0
+ : (__chunk * __partitions.__chunk_size_) +
+ (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+ std::__construct_at(
+ __chunk_totals.get() + __chunk,
+ std::transform_reduce(
+ __first + __index, __first + __index + __this_chunk_size, _Tp{}, __binary_op, __unary_op));
+ });
+
+ // Phase 2: serial exclusive prefix of totals to per-chunk offsets (in-place)
+ std::exclusive_scan(
+ __chunk_totals.get(),
+ __chunk_totals.get() + __chunk_count,
+ __chunk_totals.get(),
+ std::move(__init),
+ __binary_op);
+
+ // Phase 3: parallel per-chunk serial scan
+ __libdispatch::__dispatch_apply(__chunk_count, [&](size_t __chunk) {
+ auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
+ auto __index = __chunk == 0 ? 0
+ : (__chunk * __partitions.__chunk_size_) +
+ (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+ std::transform_exclusive_scan(
+ __first + __index,
+ __first + __index + __this_chunk_size,
+ __result + __index,
+ std::move(__chunk_totals.get()[__chunk]),
+ __binary_op,
+ __unary_op);
+ });
+
+ return __result + __n;
+ }
+
template <class _RandomAccessIterator, class _Comp, class _LeafSort>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
>From a0be67f38624a5d068425908181d5ecd2153740e Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Mon, 4 May 2026 23:21:04 +0200
Subject: [PATCH 15/23] test: add missing includes
---
.../pstl.transform_exclusive_scan.pass.cpp | 1 +
.../pstl.transform_inclusive_scan.pass.cpp | 1 +
2 files changed, 2 insertions(+)
diff --git a/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
index d796bb5e75425..9efae4cd907ed 100644
--- a/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
@@ -24,6 +24,7 @@
// UnaryOperation unary_op);
#include <cassert>
+#include <functional>
#include <numeric>
#include <string>
#include <vector>
diff --git a/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
index 0951790a56ba2..1130f07d3da16 100644
--- a/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
@@ -34,6 +34,7 @@
// T init);
#include <cassert>
+#include <functional>
#include <numeric>
#include <string>
#include <vector>
>From fbb6ab849c9d3fd850a5252dc46e4a32d86ca7ad Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 5 May 2026 20:57:59 +0200
Subject: [PATCH 16/23] libdispatch: add missing includes
---
libcxx/include/__pstl/backends/libdispatch.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index ea90f2f311698..58516013d1be3 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -25,7 +25,9 @@
#include <__memory/destroy.h>
#include <__memory/unique_ptr.h>
#include <__new/exceptions.h>
+#include <__numeric/exclusive_scan.h>
#include <__numeric/reduce.h>
+#include <__numeric/transform_exclusive_scan.h>
#include <__pstl/backend_fwd.h>
#include <__pstl/cpu_algos/any_of.h>
#include <__pstl/cpu_algos/cpu_traits.h>
>From 3f852fe2c4c0f2dea04adc1e13deb536a1d21490 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 5 May 2026 21:23:31 +0200
Subject: [PATCH 17/23] libdispatch: __transform_inclusive_scan w/ init
---
libcxx/include/__pstl/backends/libdispatch.h | 78 ++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 58516013d1be3..4ecd84daa73a8 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -28,6 +28,7 @@
#include <__numeric/exclusive_scan.h>
#include <__numeric/reduce.h>
#include <__numeric/transform_exclusive_scan.h>
+#include <__numeric/transform_inclusive_scan.h>
#include <__pstl/backend_fwd.h>
#include <__pstl/cpu_algos/any_of.h>
#include <__pstl/cpu_algos/cpu_traits.h>
@@ -334,6 +335,83 @@ struct __cpu_traits<__libdispatch_backend_tag> {
return __result + __n;
}
+ template < class _RandomAccessIterator1,
+ class _RandomAccessIterator2,
+ class _BinaryOperation,
+ class _UnaryOperation,
+ class _Tp>
+ _LIBCPP_HIDE_FROM_ABI static optional<_RandomAccessIterator2> __transform_inclusive_scan(
+ _RandomAccessIterator1 __first,
+ _RandomAccessIterator1 __last,
+ _RandomAccessIterator2 __result,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op,
+ _Tp __init) noexcept {
+ auto __n = __last - __first;
+ if (__n == 0)
+ return __result;
+
+ auto __partitions = __libdispatch::__partition_chunks(__n);
+ auto __chunk_count = __partitions.__chunk_count_;
+
+ auto __destroy = [__chunk_count](_Tp* __ptr) {
+ std::destroy_n(__ptr, __chunk_count);
+ std::allocator<_Tp>().deallocate(__ptr, __chunk_count);
+ };
+ unique_ptr<_Tp[], decltype(__destroy)> __chunk_totals(
+ [&]() -> _Tp* {
+# if _LIBCPP_HAS_EXCEPTIONS
+ try {
+# endif
+ return std::allocator<_Tp>().allocate(__chunk_count);
+# if _LIBCPP_HAS_EXCEPTIONS
+ } catch (const std::bad_alloc&) {
+ return nullptr;
+ }
+# endif
+ }(),
+ std::move(__destroy));
+ if (!__chunk_totals)
+ return nullopt;
+
+ // Phase 1: parallel chunk totals
+ __libdispatch::__dispatch_apply(__chunk_count, [&](size_t __chunk) {
+ auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
+ auto __index = __chunk == 0 ? 0
+ : (__chunk * __partitions.__chunk_size_) +
+ (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+ std::__construct_at(
+ __chunk_totals.get() + __chunk,
+ std::transform_reduce(
+ __first + __index, __first + __index + __this_chunk_size, _Tp{}, __binary_op, __unary_op));
+ });
+
+ // Phase 2: serial exclusive prefix of totals to per-chunk offsets (in-place)
+ std::exclusive_scan(
+ __chunk_totals.get(),
+ __chunk_totals.get() + __chunk_count,
+ __chunk_totals.get(),
+ std::move(__init),
+ __binary_op);
+
+ // Phase 3: parallel per-chunk serial scan
+ __libdispatch::__dispatch_apply(__chunk_count, [&](size_t __chunk) {
+ auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
+ auto __index = __chunk == 0 ? 0
+ : (__chunk * __partitions.__chunk_size_) +
+ (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+ std::transform_inclusive_scan(
+ __first + __index,
+ __first + __index + __this_chunk_size,
+ __result + __index,
+ __binary_op,
+ __unary_op,
+ std::move(__chunk_totals.get()[__chunk]));
+ });
+
+ return __result + __n;
+ }
+
template <class _RandomAccessIterator, class _Comp, class _LeafSort>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) {
>From ba63fcc06a32df2a2fd918940cd18bfed89e91a6 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 5 May 2026 21:36:37 +0200
Subject: [PATCH 18/23] libdispatch: __transform_inclusive_scan w/o init
---
libcxx/include/__pstl/backends/libdispatch.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 4ecd84daa73a8..c6118e9d4bf47 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -39,6 +39,7 @@
#include <__pstl/cpu_algos/stable_sort.h>
#include <__pstl/cpu_algos/transform.h>
#include <__pstl/cpu_algos/transform_reduce.h>
+#include <__type_traits/invoke.h>
#include <__utility/empty.h>
#include <__utility/exception_guard.h>
#include <__utility/move.h>
@@ -335,6 +336,23 @@ struct __cpu_traits<__libdispatch_backend_tag> {
return __result + __n;
}
+ template < class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryOperation, class _UnaryOperation>
+ _LIBCPP_HIDE_FROM_ABI static optional<_RandomAccessIterator2> __transform_inclusive_scan(
+ _RandomAccessIterator1 __first,
+ _RandomAccessIterator1 __last,
+ _RandomAccessIterator2 __result,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op) noexcept {
+ using _Tp = invoke_result_t<_UnaryOperation, iter_reference_t<_RandomAccessIterator1>>;
+ return __transform_inclusive_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__binary_op),
+ std::move(__unary_op),
+ _Tp{});
+ }
+
template < class _RandomAccessIterator1,
class _RandomAccessIterator2,
class _BinaryOperation,
>From 042f435bf68a5f7e0160ee8644b69d42224ddfb2 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 5 May 2026 22:22:59 +0200
Subject: [PATCH 19/23] libdispatch: DRY. unify impls
---
libcxx/include/__pstl/backends/libdispatch.h | 132 +++++++++----------
1 file changed, 62 insertions(+), 70 deletions(-)
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index c6118e9d4bf47..e5a0a9c151c65 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -259,18 +259,21 @@ struct __cpu_traits<__libdispatch_backend_tag> {
__combiner);
}
+private:
template < class _RandomAccessIterator1,
class _RandomAccessIterator2,
class _Tp,
class _BinaryOperation,
- class _UnaryOperation>
- _LIBCPP_HIDE_FROM_ABI static optional<_RandomAccessIterator2> __transform_exclusive_scan(
+ class _UnaryOperation,
+ class _Phase3Func>
+ _LIBCPP_HIDE_FROM_ABI static optional<_RandomAccessIterator2> __transform_scan(
_RandomAccessIterator1 __first,
_RandomAccessIterator1 __last,
_RandomAccessIterator2 __result,
_Tp __init,
_BinaryOperation __binary_op,
- _UnaryOperation __unary_op) noexcept {
+ _UnaryOperation __unary_op,
+ _Phase3Func __phase3) noexcept {
auto __n = __last - __first;
if (__n == 0)
return __result;
@@ -324,18 +327,50 @@ struct __cpu_traits<__libdispatch_backend_tag> {
auto __index = __chunk == 0 ? 0
: (__chunk * __partitions.__chunk_size_) +
(__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
- std::transform_exclusive_scan(
- __first + __index,
- __first + __index + __this_chunk_size,
- __result + __index,
- std::move(__chunk_totals.get()[__chunk]),
- __binary_op,
- __unary_op);
+ __phase3(__first + __index,
+ __first + __index + __this_chunk_size,
+ __result + __index,
+ std::move(__chunk_totals.get()[__chunk]));
});
return __result + __n;
}
+public:
+ template < class _RandomAccessIterator1,
+ class _RandomAccessIterator2,
+ class _Tp,
+ class _BinaryOperation,
+ class _UnaryOperation>
+ _LIBCPP_HIDE_FROM_ABI static optional<_RandomAccessIterator2> __transform_exclusive_scan(
+ _RandomAccessIterator1 __first,
+ _RandomAccessIterator1 __last,
+ _RandomAccessIterator2 __result,
+ _Tp __init,
+ _BinaryOperation __binary_op,
+ _UnaryOperation __unary_op) noexcept {
+ auto __phase3 = [&](_RandomAccessIterator1 __chunk_first,
+ _RandomAccessIterator1 __chunk_last,
+ _RandomAccessIterator2 __chunk_result,
+ _Tp __chunk_offset) {
+ std::transform_exclusive_scan(
+ std::move(__chunk_first),
+ std::move(__chunk_last),
+ std::move(__chunk_result),
+ std::move(__chunk_offset),
+ __binary_op,
+ __unary_op);
+ };
+ return __transform_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__init),
+ __binary_op,
+ __unary_op,
+ std::move(__phase3));
+ }
+
template < class _RandomAccessIterator1, class _RandomAccessIterator2, class _BinaryOperation, class _UnaryOperation>
_LIBCPP_HIDE_FROM_ABI static optional<_RandomAccessIterator2> __transform_inclusive_scan(
_RandomAccessIterator1 __first,
@@ -365,69 +400,26 @@ struct __cpu_traits<__libdispatch_backend_tag> {
_BinaryOperation __binary_op,
_UnaryOperation __unary_op,
_Tp __init) noexcept {
- auto __n = __last - __first;
- if (__n == 0)
- return __result;
-
- auto __partitions = __libdispatch::__partition_chunks(__n);
- auto __chunk_count = __partitions.__chunk_count_;
-
- auto __destroy = [__chunk_count](_Tp* __ptr) {
- std::destroy_n(__ptr, __chunk_count);
- std::allocator<_Tp>().deallocate(__ptr, __chunk_count);
- };
- unique_ptr<_Tp[], decltype(__destroy)> __chunk_totals(
- [&]() -> _Tp* {
-# if _LIBCPP_HAS_EXCEPTIONS
- try {
-# endif
- return std::allocator<_Tp>().allocate(__chunk_count);
-# if _LIBCPP_HAS_EXCEPTIONS
- } catch (const std::bad_alloc&) {
- return nullptr;
- }
-# endif
- }(),
- std::move(__destroy));
- if (!__chunk_totals)
- return nullopt;
-
- // Phase 1: parallel chunk totals
- __libdispatch::__dispatch_apply(__chunk_count, [&](size_t __chunk) {
- auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
- auto __index = __chunk == 0 ? 0
- : (__chunk * __partitions.__chunk_size_) +
- (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
- std::__construct_at(
- __chunk_totals.get() + __chunk,
- std::transform_reduce(
- __first + __index, __first + __index + __this_chunk_size, _Tp{}, __binary_op, __unary_op));
- });
-
- // Phase 2: serial exclusive prefix of totals to per-chunk offsets (in-place)
- std::exclusive_scan(
- __chunk_totals.get(),
- __chunk_totals.get() + __chunk_count,
- __chunk_totals.get(),
- std::move(__init),
- __binary_op);
-
- // Phase 3: parallel per-chunk serial scan
- __libdispatch::__dispatch_apply(__chunk_count, [&](size_t __chunk) {
- auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
- auto __index = __chunk == 0 ? 0
- : (__chunk * __partitions.__chunk_size_) +
- (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+ auto __phase3 = [&](_RandomAccessIterator1 __chunk_first,
+ _RandomAccessIterator1 __chunk_last,
+ _RandomAccessIterator2 __chunk_result,
+ _Tp __chunk_offset) {
std::transform_inclusive_scan(
- __first + __index,
- __first + __index + __this_chunk_size,
- __result + __index,
+ std::move(__chunk_first),
+ std::move(__chunk_last),
+ std::move(__chunk_result),
__binary_op,
__unary_op,
- std::move(__chunk_totals.get()[__chunk]));
- });
-
- return __result + __n;
+ std::move(__chunk_offset));
+ };
+ return __transform_scan(
+ std::move(__first),
+ std::move(__last),
+ std::move(__result),
+ std::move(__init),
+ std::move(__binary_op),
+ std::move(__unary_op),
+ std::move(__phase3));
}
template <class _RandomAccessIterator, class _Comp, class _LeafSort>
>From dd786e10fa234e69bc8c6a1540433257bba4d669 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 5 May 2026 22:26:00 +0200
Subject: [PATCH 20/23] libdispatch: add missing move
---
libcxx/include/__pstl/backends/libdispatch.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index e5a0a9c151c65..6f45905f3cf2f 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -276,7 +276,7 @@ struct __cpu_traits<__libdispatch_backend_tag> {
_Phase3Func __phase3) noexcept {
auto __n = __last - __first;
if (__n == 0)
- return __result;
+ return std::move(__result);
auto __partitions = __libdispatch::__partition_chunks(__n);
auto __chunk_count = __partitions.__chunk_count_;
>From ebab0b242572187b6ae5007fa5eae4d367fca84a Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 5 May 2026 22:32:36 +0200
Subject: [PATCH 21/23] libdispatch: connect to cpu_algos/
---
libcxx/include/__pstl/backends/libdispatch.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 6f45905f3cf2f..ac96e46f3d19a 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -39,6 +39,7 @@
#include <__pstl/cpu_algos/stable_sort.h>
#include <__pstl/cpu_algos/transform.h>
#include <__pstl/cpu_algos/transform_reduce.h>
+#include <__pstl/cpu_algos/transform_scan.h>
#include <__type_traits/invoke.h>
#include <__utility/empty.h>
#include <__utility/exception_guard.h>
@@ -546,6 +547,14 @@ template <class _ExecutionPolicy>
struct __transform_reduce<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_transform_reduce<__libdispatch_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __transform_exclusive_scan<__libdispatch_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_transform_exclusive_scan<__libdispatch_backend_tag, _ExecutionPolicy> {};
+
+template <class _ExecutionPolicy>
+struct __transform_inclusive_scan<__libdispatch_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_transform_inclusive_scan<__libdispatch_backend_tag, _ExecutionPolicy> {};
+
template <class _ExecutionPolicy>
struct __transform_reduce_binary<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_transform_reduce_binary<__libdispatch_backend_tag, _ExecutionPolicy> {};
>From 4f3c703e1d2c7d54a71e999c4ff68f381b8f86dc Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 5 May 2026 22:39:49 +0200
Subject: [PATCH 22/23] tests: force multiple chunks independent of hardware
---
libcxx/include/__pstl/backends/libdispatch.h | 8 ++++----
.../pstl.transform_exclusive_scan.pass.cpp | 2 +-
.../pstl.transform_inclusive_scan.pass.cpp | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index ac96e46f3d19a..3e0c4bcfdc703 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -547,6 +547,10 @@ template <class _ExecutionPolicy>
struct __transform_reduce<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_transform_reduce<__libdispatch_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __transform_reduce_binary<__libdispatch_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_transform_reduce_binary<__libdispatch_backend_tag, _ExecutionPolicy> {};
+
template <class _ExecutionPolicy>
struct __transform_exclusive_scan<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_transform_exclusive_scan<__libdispatch_backend_tag, _ExecutionPolicy> {};
@@ -555,10 +559,6 @@ template <class _ExecutionPolicy>
struct __transform_inclusive_scan<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_transform_inclusive_scan<__libdispatch_backend_tag, _ExecutionPolicy> {};
-template <class _ExecutionPolicy>
-struct __transform_reduce_binary<__libdispatch_backend_tag, _ExecutionPolicy>
- : __cpu_parallel_transform_reduce_binary<__libdispatch_backend_tag, _ExecutionPolicy> {};
-
// Not mandatory, but better optimized
template <class _ExecutionPolicy>
struct __any_of<__libdispatch_backend_tag, _ExecutionPolicy>
diff --git a/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
index 9efae4cd907ed..936fade43c57e 100644
--- a/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/transform.exclusive.scan/pstl.transform_exclusive_scan.pass.cpp
@@ -37,7 +37,7 @@ template <class Iter>
struct Test {
template <class Policy>
void operator()(Policy&& policy) {
- for (int size : {0, 1, 2, 100, 350}) {
+ for (int size : {0, 1, 2, 100, 350, 10000}) {
std::vector<int> a(size);
for (int i = 0; i != size; ++i)
a[i] = i;
diff --git a/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp b/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
index 1130f07d3da16..fb476f582a833 100644
--- a/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
+++ b/libcxx/test/std/numerics/numeric.ops/transform.inclusive.scan/pstl.transform_inclusive_scan.pass.cpp
@@ -47,7 +47,7 @@ template <class Iter>
struct TestNoInit {
template <class Policy>
void operator()(Policy&& policy) {
- for (int size : {0, 1, 2, 100, 350}) {
+ for (int size : {0, 1, 2, 100, 350, 10000}) {
std::vector<int> a(size);
for (int i = 0; i != size; ++i)
a[i] = i + 1;
>From 41f6daaa40e257e8979f456fa7a5510bc694d6ab Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 5 May 2026 23:04:13 +0200
Subject: [PATCH 23/23] use clang-format v22.1
---
libcxx/include/__pstl/backends/libdispatch.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 3e0c4bcfdc703..79260ad3f86c7 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -241,7 +241,7 @@ struct __cpu_traits<__libdispatch_backend_tag> {
auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
auto __index = __chunk == 0 ? 0
: (__chunk * __partitions.__chunk_size_) +
- (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+ (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
if (__this_chunk_size != 1) {
std::__construct_at(
__values.get() + __chunk,
@@ -307,7 +307,7 @@ struct __cpu_traits<__libdispatch_backend_tag> {
auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
auto __index = __chunk == 0 ? 0
: (__chunk * __partitions.__chunk_size_) +
- (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+ (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
std::__construct_at(
__chunk_totals.get() + __chunk,
std::transform_reduce(
@@ -327,7 +327,7 @@ struct __cpu_traits<__libdispatch_backend_tag> {
auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
auto __index = __chunk == 0 ? 0
: (__chunk * __partitions.__chunk_size_) +
- (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+ (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
__phase3(__first + __index,
__first + __index + __this_chunk_size,
__result + __index,
More information about the libcxx-commits
mailing list