[libcxx-commits] [libcxx] [libc++][pstl] Generic implementation of parallel std::is_sorted_until (PR #178756)
Michael G. Kazakov via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jan 30 02:27:49 PST 2026
https://github.com/mikekazakov updated https://github.com/llvm/llvm-project/pull/178756
>From 05dc9334346b08ef79a48764f3d9764c20d9358a Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sat, 24 Jan 2026 11:20:56 +0000
Subject: [PATCH 1/5] Implementation of std::is_sorted_until
---
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__algorithm/pstl.h | 25 +++
libcxx/include/__pstl/backend_fwd.h | 5 +
libcxx/include/__pstl/backends/default.h | 32 +++
libcxx/include/__pstl/index_iterator.h | 135 +++++++++++++
libcxx/include/module.modulemap.in | 1 +
.../algorithms/pstl.index_iterator.pass.cpp | 95 +++++++++
.../is.sorted/pstl.is_sorted_until.pass.cpp | 188 ++++++++++++++++++
.../pstl.is_sorted_until_comp.pass.cpp | 187 +++++++++++++++++
9 files changed, 669 insertions(+)
create mode 100644 libcxx/include/__pstl/index_iterator.h
create mode 100644 libcxx/test/libcxx/algorithms/pstl.index_iterator.pass.cpp
create mode 100644 libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp
create mode 100644 libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 494c21bd30019..c65167be97a44 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -669,6 +669,7 @@ set(files
__pstl/cpu_algos/transform_reduce.h
__pstl/dispatch.h
__pstl/handle_exception.h
+ __pstl/index_iterator.h
__random/bernoulli_distribution.h
__random/binomial_distribution.h
__random/cauchy_distribution.h
diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index 10625ea3f8e3d..178f5e9fa5400 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -654,6 +654,31 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
std::move(__op));
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0 >
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+is_sorted_until(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "is_sorted_until requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__is_sorted_until, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), less{});
+}
+
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Comp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+is_sorted_until(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Comp __comp) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "is_sorted_until requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__is_sorted_until, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__comp));
+}
+
template <class _ExecutionPolicy,
class _ForwardIterator,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index a52e6db954d0c..c6c00087105dd 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -297,6 +297,11 @@ struct __reduce;
// operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last,
// _Tp __init, _BinaryOperation __op) const noexcept;
+struct __is_sorted_until;
+// template <class _Policy, class _ForwardIterator, class _Comp>
+// optional<_ForwardIterator>
+// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Comp&& __comp) const noexcept;
+
template <class _Backend, class _ExecutionPolicy>
struct __is_sorted;
// template <class _Policy, class _ForwardIterator, class _Comp>
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index be90715af13b5..c25a8fc2aa9b0 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -14,6 +14,7 @@
#include <__algorithm/fill_n.h>
#include <__algorithm/for_each_n.h>
#include <__algorithm/is_sorted.h>
+#include <__algorithm/is_sorted_until.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/not_fn.h>
@@ -23,6 +24,7 @@
#include <__iterator/next.h>
#include <__pstl/backend_fwd.h>
#include <__pstl/dispatch.h>
+#include <__pstl/index_iterator.h>
#include <__utility/empty.h>
#include <__utility/forward.h>
#include <__utility/move.h>
@@ -57,6 +59,7 @@ namespace __pstl {
// - all_of
// - none_of
// - is_partitioned
+// - is_sorted_until
//
// for_each family
// ---------------
@@ -181,6 +184,35 @@ struct __is_partitioned<__default_backend_tag, _ExecutionPolicy> {
}
};
+template <class _ExecutionPolicy>
+struct __is_sorted_until<__default_backend_tag, _ExecutionPolicy> {
+ template <class _Policy, class _ForwardIterator, class _Comp>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+ operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Comp&& __comp) const noexcept {
+ if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+ using _DifferenceType = typename std::iterator_traits<_ForwardIterator>::difference_type;
+ using _IndexIteratorType = __index_iterator<_DifferenceType>;
+
+ _DifferenceType __n = __last - __first;
+ if (__n <= 1)
+ return __last; // Sorted by definition
+
+ _IndexIteratorType __index_first{_DifferenceType{}};
+ _IndexIteratorType __index_last{__n - 1};
+
+ using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>;
+ auto __res = _FindIf()(__policy, __index_first, __index_last, [&](_DifferenceType __index) -> bool {
+ return __comp(*(__first + __index + 1), *(__first + __index));
+ });
+ if (!__res)
+ return nullopt;
+ return __first + *(*__res) + 1;
+ } else {
+ return std::is_sorted_until(std::move(__first), std::move(__last), std::forward<_Comp>(__comp));
+ }
+ }
+};
+
//////////////////////////////////////////////////////////////
// for_each family
//////////////////////////////////////////////////////////////
diff --git a/libcxx/include/__pstl/index_iterator.h b/libcxx/include/__pstl/index_iterator.h
new file mode 100644
index 0000000000000..e9e9af635e3bb
--- /dev/null
+++ b/libcxx/include/__pstl/index_iterator.h
@@ -0,0 +1,135 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_INDEX_ITERATOR_H
+#define _LIBCPP___PSTL_INDEX_ITERATOR_H
+
+#include <__config>
+#include <__iterator/iterator_traits.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
+namespace __pstl {
+
+// This iterator type is a stopgap solution to use the existing backend algorithms in PSTL and be able to implement
+// position-sensitive algorithms on top. While providing an iterator interface, this type is essentially a wrapper over
+// an index type.
+// Once the backends start providing a less restrictive interface, e.g. working with chunks of iterator
+// ranges, and supporting forward iterators, any algorithms that were implemented using this index wrapper should be
+// reimplemented using iterators as-is.
+
+template <typename _Index>
+class __index_iterator {
+public:
+ using value_type = _Index;
+ using difference_type = _Index;
+ using iterator_category = std::random_access_iterator_tag;
+ using reference = _Index;
+ using pointer = void;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __index_iterator() noexcept = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __index_iterator(_Index __index) noexcept : __index_(__index) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr _Index operator*() const noexcept { return __index_; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __index_iterator& operator++() noexcept {
+ ++__index_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __index_iterator operator++(int) noexcept {
+ auto __tmp = *this;
+ ++__index_;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __index_iterator& operator--() noexcept {
+ --__index_;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __index_iterator operator--(int) noexcept {
+ auto __tmp = *this;
+ --__index_;
+ return __tmp;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __index_iterator operator+(_Index __n) const noexcept {
+ return __index_iterator{__index_ + __n};
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr __index_iterator operator+(_Index __n, const __index_iterator& __x) noexcept {
+ return __x + __n;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __index_iterator& operator+=(_Index __n) noexcept {
+ __index_ += __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __index_iterator operator-(_Index __n) const noexcept {
+ return __index_iterator{__index_ - __n};
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr _Index
+ operator-(const __index_iterator& __lhs, const __index_iterator& __rhs) noexcept {
+ return __lhs.__index_ - __rhs.__index_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __index_iterator& operator-=(_Index __n) noexcept {
+ __index_ -= __n;
+ return *this;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr _Index operator[](_Index __n) const noexcept { return __index_ + __n; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const __index_iterator& __other) const noexcept {
+ return __index_ == __other.__index_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const __index_iterator& __other) const noexcept {
+ return !(*this == __other);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const __index_iterator& __other) const noexcept {
+ return __index_ < __other.__index_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const __index_iterator& __other) const noexcept {
+ return __index_ <= __other.__index_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const __index_iterator& __other) const noexcept {
+ return __index_ > __other.__index_;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const __index_iterator& __other) const noexcept {
+ return __index_ >= __other.__index_;
+ }
+
+private:
+ _Index __index_ = {};
+};
+
+} // namespace __pstl
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_INDEX_ITERATOR_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 58fc4941cb7d8..bfefa9c6ae174 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2356,6 +2356,7 @@ module std [system] {
}
module dispatch { header "__pstl/dispatch.h" }
module handle_exception { header "__pstl/handle_exception.h" }
+ module index_iterator { header "__pstl/index_iterator.h" }
}
// Miscellaneous modules for top-level headers
diff --git a/libcxx/test/libcxx/algorithms/pstl.index_iterator.pass.cpp b/libcxx/test/libcxx/algorithms/pstl.index_iterator.pass.cpp
new file mode 100644
index 0000000000000..650b7423d0839
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/pstl.index_iterator.pass.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// Checks the logic of the index wrapper iterator.
+
+#include <algorithm>
+#include <execution>
+#include <iterator>
+#include <type_traits>
+#include <cassert>
+#include <cstddef>
+
+int main(int, char**) {
+ using Index = std::ptrdiff_t;
+ using Iter = std::__pstl::__index_iterator<Index>;
+ static_assert(std::is_nothrow_default_constructible_v<Iter>);
+ static_assert(std::is_nothrow_constructible_v<Iter, Index>);
+ static_assert(std::is_trivially_copy_constructible_v<Iter>);
+ static_assert(std::is_trivially_move_constructible_v<Iter>);
+ static_assert(std::is_trivially_assignable_v<Iter, Iter>);
+ static_assert(std::is_trivially_copy_assignable_v<Iter>);
+ static_assert(std::is_trivially_move_assignable_v<Iter>);
+ static_assert(std::is_trivially_destructible_v<Iter>);
+
+ {
+ assert((*Iter{}) == Index{});
+ }
+ {
+ assert((*Iter{7}) == 7);
+ }
+ {
+ Iter it{5};
+ assert(&(++it) == &it);
+ assert((*it) == 6);
+ }
+ {
+ Iter it{5};
+ assert(*(it++) == 5);
+ assert((*it) == 6);
+ }
+ {
+ Iter it{5};
+ assert(&(--it) == &it);
+ assert((*it) == 4);
+ }
+ {
+ Iter it{5};
+ assert(*(it--) == 5);
+ assert((*it) == 4);
+ }
+ {
+ assert(*(Iter{4} + 3) == 7);
+ }
+ {
+ assert(*(4 + Iter{3}) == 7);
+ }
+ {
+ Iter it{5};
+ assert(&(it += 3) == &it);
+ assert((*it) == 8);
+ }
+ {
+ assert((Iter{4} - 3) == Iter{1});
+ }
+ {
+ assert((Iter{4} - Iter{3}) == 1);
+ }
+ {
+ Iter it{5};
+ assert(&(it -= 3) == &it);
+ assert((*it) == 2);
+ }
+ {
+ assert(Iter{5}[3] == 8);
+ }
+ {
+ assert(Iter{5} == Iter{5});
+ assert(!(Iter{5} == Iter{6}));
+ }
+ {
+ assert(Iter{5} != Iter{6});
+ assert(!(Iter{5} != Iter{5}));
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp
new file mode 100644
index 0000000000000..b6aea31dc5a74
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp
@@ -0,0 +1,188 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template<class ExecutionPolicy, class ForwardIterator>
+// ForwardIterator is_sorted_until(ExecutionPolicy&& exec,
+// ForwardIterator first, ForwardIterator last);
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class Iter>
+struct Test {
+ template <class ExecutionPolicy>
+ void operator()(ExecutionPolicy&& policy) {
+ {
+ int a[] = {0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a)) == Iter(a));
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+
+ {
+ int a[] = {0, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 2));
+ }
+ {
+ int a[] = {0, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {1, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 2));
+ }
+ {
+ int a[] = {1, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+
+ {
+ int a[] = {0, 0, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 0, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 0, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 3));
+ }
+ {
+ int a[] = {0, 0, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 1, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 2));
+ }
+ {
+ int a[] = {0, 1, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 2));
+ }
+ {
+ int a[] = {0, 1, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 3));
+ }
+ {
+ int a[] = {0, 1, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {1, 0, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 0, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 0, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 0, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 1, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 2));
+ }
+ {
+ int a[] = {1, 1, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 2));
+ }
+ {
+ int a[] = {1, 1, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 3));
+ }
+ {
+ int a[] = {1, 1, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::concatenate_t<types::forward_iterator_list<int*>,
+ types::bidirectional_iterator_list<int*>,
+ types::random_access_iterator_list<int*>>{},
+ TestIteratorWithPolicies<Test>{});
+
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp
new file mode 100644
index 0000000000000..74a073efd4451
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp
@@ -0,0 +1,187 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template<class ExecutionPolicy, class ForwardIterator, class Comp>
+// ForwardIterator is_sorted_until(ExecutionPolicy&& exec,
+// ForwardIterator first, ForwardIterator last,
+// Comp comp);
+
+#include <algorithm>
+#include <functional>
+#include <cassert>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <class Iter>
+struct Test {
+ template <class ExecutionPolicy>
+ void operator()(ExecutionPolicy&& policy) {
+ {
+ int a[] = {0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a), std::greater<int>()) == Iter(a));
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+
+ {
+ int a[] = {0, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 2));
+ }
+ {
+ int a[] = {0, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 1));
+ }
+ {
+ int a[] = {0, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {1, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 2));
+ }
+ {
+ int a[] = {1, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {1, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+
+ {
+ int a[] = {0, 0, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {0, 0, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 3));
+ }
+ {
+ int a[] = {0, 0, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 2));
+ }
+ {
+ int a[] = {0, 0, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 2));
+ }
+ {
+ int a[] = {0, 1, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 1));
+ }
+ {
+ int a[] = {0, 1, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 1));
+ }
+ {
+ int a[] = {0, 1, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 1));
+ }
+ {
+ int a[] = {0, 1, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 1));
+ }
+ {
+ int a[] = {1, 0, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {1, 0, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 3));
+ }
+ {
+ int a[] = {1, 0, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 2));
+ }
+ {
+ int a[] = {1, 0, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 2));
+ }
+ {
+ int a[] = {1, 1, 0, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {1, 1, 0, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 3));
+ }
+ {
+ int a[] = {1, 1, 1, 0};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {1, 1, 1, 1};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::concatenate_t<types::forward_iterator_list<int*>,
+ types::bidirectional_iterator_list<int*>,
+ types::random_access_iterator_list<int*>>{},
+ TestIteratorWithPolicies<Test>{});
+ return 0;
+}
>From 56b814a5af2744c7a81647c3329dc7995c87e995 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 29 Jan 2026 20:39:44 +0000
Subject: [PATCH 2/5] Rebased is_sorted on top of is_sorted_until, added more
tests
---
libcxx/include/__pstl/backend_fwd.h | 9 ++--
libcxx/include/__pstl/backends/default.h | 44 ++++++-------------
.../algorithms/pstl.nodiscard.verify.cpp | 4 ++
.../is.sorted/pstl.is_sorted_until.pass.cpp | 41 +++++++++++++++++
.../pstl.is_sorted_until_comp.pass.cpp | 41 +++++++++++++++++
.../pstl.exception_handling.pass.cpp | 8 ++++
6 files changed, 113 insertions(+), 34 deletions(-)
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index c6c00087105dd..6a17e2a109091 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -297,15 +297,16 @@ struct __reduce;
// operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last,
// _Tp __init, _BinaryOperation __op) const noexcept;
-struct __is_sorted_until;
+template <class _Backend, class _ExecutionPolicy>
+struct __is_sorted;
// template <class _Policy, class _ForwardIterator, class _Comp>
-// optional<_ForwardIterator>
+// optional<bool>
// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Comp&& __comp) const noexcept;
template <class _Backend, class _ExecutionPolicy>
-struct __is_sorted;
+struct __is_sorted_until;
// template <class _Policy, class _ForwardIterator, class _Comp>
-// optional<bool>
+// optional<_ForwardIterator>
// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Comp&& __comp) const noexcept;
} // namespace __pstl
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index c25a8fc2aa9b0..5e005a96429a8 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -59,6 +59,7 @@ namespace __pstl {
// - all_of
// - none_of
// - is_partitioned
+// - is_sorted
// - is_sorted_until
//
// for_each family
@@ -85,7 +86,6 @@ namespace __pstl {
// - count
// - equal(3 legs)
// - equal
-// - is_sorted
// - reduce
//
// transform and transform_binary family
@@ -213,6 +213,19 @@ struct __is_sorted_until<__default_backend_tag, _ExecutionPolicy> {
}
};
+template <class _ExecutionPolicy>
+struct __is_sorted<__default_backend_tag, _ExecutionPolicy> {
+ template <class _Policy, class _ForwardIterator, class _Comp>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
+ operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Comp&& __comp) const noexcept {
+ using _IsSortedUntil = __dispatch<__is_sorted_until, __current_configuration, _ExecutionPolicy>;
+ optional<_ForwardIterator> __res = _IsSortedUntil()(__policy, __first, __last, std::forward<_Comp>(__comp));
+ if (!__res)
+ return nullopt;
+ return *__res == __last;
+ }
+};
+
//////////////////////////////////////////////////////////////
// for_each family
//////////////////////////////////////////////////////////////
@@ -423,35 +436,6 @@ struct __reduce<__default_backend_tag, _ExecutionPolicy> {
}
};
-template <class _ExecutionPolicy>
-struct __is_sorted<__default_backend_tag, _ExecutionPolicy> {
- template <class _Policy, class _ForwardIterator, class _Comp>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
- operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Comp&& __comp) const noexcept {
- if constexpr (__has_bidirectional_iterator_category<_ForwardIterator>::value) {
- if (__first == __last)
- return true; // Empty, sorted by definition
- _ForwardIterator __first2 = std::next(__first);
- if (__first2 == __last)
- return true; // Only one element, sorted by definition
- --__last; // Make two iterator ranges: [__first, __first + n - 1) and [__first + 1, __first + n)
- using _TransformReduce = __dispatch<__transform_reduce_binary, __current_configuration, _ExecutionPolicy>;
- using _Ref = __iterator_reference<_ForwardIterator>;
- return _TransformReduce()(
- __policy,
- std::move(__first),
- std::move(__last),
- std::move(__first2),
- true,
- std::logical_and{},
- [&](_Ref __left, _Ref __right) -> bool { return !__comp(__right, __left); });
- } else {
- // Currently anything outside bidirectional iterators has to be processed serially
- return std::is_sorted(std::move(__first), std::move(__last), std::forward<_Comp>(__comp));
- }
- }
-};
-
//////////////////////////////////////////////////////////////
// transform family
//////////////////////////////////////////////////////////////
diff --git a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
index b6554cef6f32a..fa6bf65aab5ff 100644
--- a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
@@ -52,4 +52,8 @@ void test() {
std::is_sorted(std::execution::par, std::begin(a), std::end(a));
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::is_sorted(std::execution::par, std::begin(a), std::end(a), pred2);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::is_sorted_until(std::execution::par, std::begin(a), std::end(a));
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::is_sorted_until(std::execution::par, std::begin(a), std::end(a), pred2);
}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp
index b6aea31dc5a74..98cfceea59deb 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp
@@ -17,6 +17,7 @@
#include <algorithm>
#include <cassert>
#include <functional>
+#include <limits>
#include <numeric>
#include "test_execution_policies.h"
@@ -175,6 +176,46 @@ struct Test {
unsigned sa = sizeof(a) / sizeof(a[0]);
assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
}
+ {
+ int a[] = {std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::max()};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::max()};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 2));
+ }
+ {
+ int a[] = {
+ std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::min() / 2,
+ -1,
+ 0,
+ 1,
+ std::numeric_limits<int>::max() / 2,
+ std::numeric_limits<int>::max()};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + sa));
+ }
+ {
+ int a[] = {
+ std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::min() / 2,
+ 1,
+ 0,
+ -1,
+ std::numeric_limits<int>::max() / 2,
+ std::numeric_limits<int>::max()};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa)) == Iter(a + 3));
+ }
}
};
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp
index 74a073efd4451..e9bcdca288094 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp
@@ -17,6 +17,7 @@
#include <algorithm>
#include <functional>
+#include <limits>
#include <cassert>
#include "test_execution_policies.h"
@@ -175,6 +176,46 @@ struct Test {
unsigned sa = sizeof(a) / sizeof(a[0]);
assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
}
+ {
+ int a[] = {std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::min()};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::max()};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 1));
+ }
+ {
+ int a[] = {
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::max() / 2,
+ 1,
+ 0,
+ -1,
+ std::numeric_limits<int>::min() / 2,
+ std::numeric_limits<int>::min()};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + sa));
+ }
+ {
+ int a[] = {
+ std::numeric_limits<int>::max(),
+ std::numeric_limits<int>::max() / 2,
+ -1,
+ 0,
+ 1,
+ std::numeric_limits<int>::min() / 2,
+ std::numeric_limits<int>::min()};
+ unsigned sa = sizeof(a) / sizeof(a[0]);
+ assert(std::is_sorted_until(policy, Iter(a), Iter(a + sa), std::greater<int>()) == Iter(a + 3));
+ }
}
};
diff --git a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
index a3db159289393..bbb2d4e9e40d4 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -290,6 +290,14 @@ int main(int, char**) {
assert_non_throwing([=, &policy] {
(void)std::is_sorted(policy, std::move(first1), std::move(last1), compare);
});
+
+ // is_sorted_until(first, last)
+ assert_non_throwing([=, &policy] { (void)std::is_sorted_until(policy, std::move(first1), std::move(last1)); });
+
+ // is_sorted_until(first, last, comp)
+ assert_non_throwing([=, &policy] {
+ (void)std::is_sorted_until(policy, std::move(first1), std::move(last1), compare);
+ });
}
{
>From b427a33a8a272240f12e89d1719a27d53a473f2a Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Thu, 29 Jan 2026 22:17:27 +0000
Subject: [PATCH 3/5] Include the internal header directly in the test so that
the modules build can pass
---
libcxx/test/libcxx/algorithms/pstl.index_iterator.pass.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/libcxx/test/libcxx/algorithms/pstl.index_iterator.pass.cpp b/libcxx/test/libcxx/algorithms/pstl.index_iterator.pass.cpp
index 650b7423d0839..bcdf009b2912d 100644
--- a/libcxx/test/libcxx/algorithms/pstl.index_iterator.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.index_iterator.pass.cpp
@@ -12,8 +12,7 @@
// Checks the logic of the index wrapper iterator.
-#include <algorithm>
-#include <execution>
+#include <__pstl/index_iterator.h>
#include <iterator>
#include <type_traits>
#include <cassert>
>From d3684c7fd741063c0268c79597c7e997ba38d053 Mon Sep 17 00:00:00 2001
From: "Michael G. Kazakov" <mike.kazakov at gmail.com>
Date: Fri, 30 Jan 2026 10:24:05 +0000
Subject: [PATCH 4/5] Apply suggestion from @Zingam
Co-authored-by: Hristo Hristov <zingam at outlook.com>
---
.../alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp
index 98cfceea59deb..acf20bdccaa73 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: std-at-least-c++17
// UNSUPPORTED: libcpp-has-no-incomplete-pstl
>From 74ce3a63c72eb6e27854d75674032bd7a93b0875 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Fri, 30 Jan 2026 10:27:26 +0000
Subject: [PATCH 5/5] Use REQUIRES: std-at-least-c++17 in the test
---
.../alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp
index e9bcdca288094..fb438663f7cd4 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/is.sorted/pstl.is_sorted_until_comp.pass.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: std-at-least-c++17
// UNSUPPORTED: libcpp-has-no-incomplete-pstl
More information about the libcxx-commits
mailing list