[libcxx-commits] [libcxx] [libc++][pstl] Implementation of parallel std::is_heap_until() based on __parallel_find() (PR #218603)
via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Aug 26 21:30:14 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Michael G. Kazakov (mikekazakov)
<details>
<summary>Changes</summary>
This PR adds an implementation of a parallel `std::is_heap_until()` based on `__parallel_find()`.
`std::is_heap()` will be implemented as a one-liner (`return std::is_heap_until(..) == last;`) in a following PR.
This function is implemented inside `cpu_algos` since it requires manipulations with iterators.
The implementation chops the input range `[first+1, last)` into partitions and processes them in parallel.
For each partition, it derives the first and the last parents of these children, and iterates over the parents checking their children for heap violations.
Basically, it's very close to the implementation of the serial version, but with a different prologue and epilogue.
Included tests check that:
- Semantics of the iterator-only function is correct.
- Semantics of the predicated function is correct.
- The functions correctly SFINAE out when the first argument is not an execution policy.
- The `nodiscard` policy is followed.
- The `noexcept` policy is followed.
- `static_assert` verifies iterators' categories.
Part of #<!-- -->99938.
---
Patch is 109.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/218603.diff
14 Files Affected:
- (modified) libcxx/include/CMakeLists.txt (+1)
- (modified) libcxx/include/__algorithm/pstl.h (+25)
- (modified) libcxx/include/__pstl/backend_fwd.h (+7)
- (modified) libcxx/include/__pstl/backends/default.h (+4)
- (modified) libcxx/include/__pstl/backends/libdispatch.h (+5)
- (modified) libcxx/include/__pstl/backends/serial.h (+10)
- (modified) libcxx/include/__pstl/backends/std_thread.h (+5)
- (added) libcxx/include/__pstl/cpu_algos/is_heap_until.h (+102)
- (modified) libcxx/include/module.modulemap.in (+3)
- (modified) libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp (+9)
- (modified) libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp (+4)
- (added) libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/is.heap/pstl.is_heap_until.pass.cpp (+1064)
- (added) libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/is.heap/pstl.is_heap_until_comp.pass.cpp (+1068)
- (modified) libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp (+12)
``````````diff
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index d717a7354c62b..b0c9181211f43 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -697,6 +697,7 @@ set(files
__pstl/cpu_algos/fill.h
__pstl/cpu_algos/find_if.h
__pstl/cpu_algos/for_each.h
+ __pstl/cpu_algos/is_heap_until.h
__pstl/cpu_algos/merge.h
__pstl/cpu_algos/mismatch.h
__pstl/cpu_algos/reverse.h
diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index a8ef6ddae9b63..79790ad429daa 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -988,6 +988,31 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
std::move(__op));
}
+template <class _ExecutionPolicy,
+ class _RandomAccessIterator,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _RandomAccessIterator
+is_heap_until(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last) {
+ _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(_RandomAccessIterator, "is_heap_until requires RandomAccessIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__is_heap_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 _RandomAccessIterator,
+ class _Comp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _RandomAccessIterator
+is_heap_until(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
+ _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(_RandomAccessIterator, "is_heap_until requires RandomAccessIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__is_heap_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 45e570c51aed9..3383ec0c0058a 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -331,6 +331,13 @@ struct __reduce;
// operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last,
// _Tp __init, _BinaryOperation __op) const noexcept;
+template <class _Backend, class _ExecutionPolicy>
+struct __is_heap_until;
+// template <class _Policy, class _RandomAccessIterator, class _Comp>
+// optional<bool>
+// operator()(_Policy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __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 ecf5b3bc3d9eb..a54ed27c1c58f 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -60,6 +60,10 @@ namespace __pstl {
//
// This backend implements all the PSTL algorithms based on the following basis operations:
//
+// is_heap_until family
+// --------------
+// No other algorithms based on is_heap_until
+//
// find_if family
// --------------
// - find
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index c5efbd46298fb..a93f5170e427f 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -39,6 +39,7 @@
#include <__pstl/cpu_algos/fill.h>
#include <__pstl/cpu_algos/find_if.h>
#include <__pstl/cpu_algos/for_each.h>
+#include <__pstl/cpu_algos/is_heap_until.h>
#include <__pstl/cpu_algos/merge.h>
#include <__pstl/cpu_algos/mismatch.h>
#include <__pstl/cpu_algos/reverse.h>
@@ -370,6 +371,10 @@ template <class _ExecutionPolicy>
struct __for_each<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_for_each<__libdispatch_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __is_heap_until<__libdispatch_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_is_heap_until<__libdispatch_backend_tag, _ExecutionPolicy> {};
+
template <class _ExecutionPolicy>
struct __merge<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_merge<__libdispatch_backend_tag, _ExecutionPolicy> {};
diff --git a/libcxx/include/__pstl/backends/serial.h b/libcxx/include/__pstl/backends/serial.h
index c67f0b3331ac2..085bc440b5e7b 100644
--- a/libcxx/include/__pstl/backends/serial.h
+++ b/libcxx/include/__pstl/backends/serial.h
@@ -12,6 +12,7 @@
#include <__algorithm/find_if.h>
#include <__algorithm/for_each.h>
+#include <__algorithm/is_heap_until.h>
#include <__algorithm/merge.h>
#include <__algorithm/mismatch.h>
#include <__algorithm/reverse.h>
@@ -88,6 +89,15 @@ struct __for_each<__serial_backend_tag, _ExecutionPolicy> {
}
};
+template <class _Backend, class _RawExecutionPolicy>
+struct __is_heap_until {
+ template <class _Policy, class _RandomAccessIterator, class _Comp>
+ _LIBCPP_HIDE_FROM_ABI optional<_RandomAccessIterator>
+ operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
+ return std::is_heap_until(std::move(__first), std::move(__last), std::move(__comp));
+ }
+};
+
template <class _ExecutionPolicy>
struct __merge<__serial_backend_tag, _ExecutionPolicy> {
template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _ForwardOutIterator, class _Comp>
diff --git a/libcxx/include/__pstl/backends/std_thread.h b/libcxx/include/__pstl/backends/std_thread.h
index 06beb04e4d885..aecc6b3af2a14 100644
--- a/libcxx/include/__pstl/backends/std_thread.h
+++ b/libcxx/include/__pstl/backends/std_thread.h
@@ -18,6 +18,7 @@
#include <__pstl/cpu_algos/fill.h>
#include <__pstl/cpu_algos/find_if.h>
#include <__pstl/cpu_algos/for_each.h>
+#include <__pstl/cpu_algos/is_heap_until.h>
#include <__pstl/cpu_algos/merge.h>
#include <__pstl/cpu_algos/mismatch.h>
#include <__pstl/cpu_algos/reverse.h>
@@ -101,6 +102,10 @@ template <class _ExecutionPolicy>
struct __for_each<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_for_each<__std_thread_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __is_heap_until<__std_thread_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_is_heap_until<__std_thread_backend_tag, _ExecutionPolicy> {};
+
template <class _ExecutionPolicy>
struct __merge<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_merge<__std_thread_backend_tag, _ExecutionPolicy> {};
diff --git a/libcxx/include/__pstl/cpu_algos/is_heap_until.h b/libcxx/include/__pstl/cpu_algos/is_heap_until.h
new file mode 100644
index 0000000000000..9d881ea14cf94
--- /dev/null
+++ b/libcxx/include/__pstl/cpu_algos/is_heap_until.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_CPU_ALGOS_IS_HEAP_UNTIL_H
+#define _LIBCPP___PSTL_CPU_ALGOS_IS_HEAP_UNTIL_H
+
+#include <__algorithm/is_heap_until.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/cpu_algos/cpu_traits.h>
+#include <__pstl/cpu_algos/find_if.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace __pstl {
+
+template <class _Backend, class _RawExecutionPolicy>
+struct __cpu_parallel_is_heap_until {
+ template <class _Policy, class _RandomAccessIterator, class _Comp>
+ _LIBCPP_HIDE_FROM_ABI optional<_RandomAccessIterator>
+ operator()(_Policy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) const noexcept {
+ if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy>) {
+ if (__last - __first < 2)
+ return __last; // Any sequence with less than 2 elements is a heap
+ // Run a parallel find in chunks over [first+1, last) to validate every element excepting the root.
+ return __pstl::__parallel_find<_Backend>(
+ __first + 1,
+ __last,
+ [__first, &__comp](_RandomAccessIterator __child_first, _RandomAccessIterator __child_last) {
+ // This algorithm assumes that __parallel_find() will never pass an empty brick,
+ // i.e. that __child_first != __child_last.
+ using _DifferenceType = typename std::iterator_traits<_RandomAccessIterator>::difference_type;
+
+ // Derive the indices of the children and the iterators of their parents
+ _DifferenceType __child_first_idx = __child_first - __first;
+ _DifferenceType __child_last_idx = __child_last - __first;
+ _RandomAccessIterator __parent = __first + (__child_first_idx - 1) / 2;
+ _RandomAccessIterator __parent_last = __first + (__child_last_idx - 1) / 2;
+
+ // If we're starting from a right child => process this element separately in a prologue
+ if (__child_first_idx % 2 == 0) {
+ if (__comp(*__parent, *__child_first)) // Check the right child
+ return __child_first;
+ ++__parent;
+ ++__child_first;
+ }
+
+ // Iterate over the parents and check their left and right children
+ for (; __parent != __parent_last; ++__parent) {
+ if (__comp(*__parent, *__child_first)) // Check the left child
+ return __child_first;
+ ++__child_first;
+
+ if (__comp(*__parent, *__child_first)) // Check the right child
+ return __child_first;
+ ++__child_first;
+ }
+
+ // If we're ending with a right child => __parent_last also includes the left child.
+ // Process this accessible element separately in an epilogue.
+ if (__child_last_idx % 2 == 0) {
+ if (__comp(*__parent, *__child_first)) // Check the left child
+ return __child_first;
+ }
+
+ return __child_last; // No violations found in this brick
+ },
+ less<>{}, // `less` here means the lowest index among the matches
+ true // `true` here means we want the first match, not the last
+ );
+ } else {
+ return std::is_heap_until(std::move(__first), std::move(__last), std::move(__comp));
+ }
+ }
+};
+
+} // namespace __pstl
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_CPU_ALGOS_IS_HEAP_UNTIL_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 78f4e08d9c282..463afd164cd2b 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2435,6 +2435,9 @@ module std {
header "__pstl/cpu_algos/for_each.h"
export std_core.utility_core.empty
}
+ module is_heap_until {
+ header "__pstl/cpu_algos/is_heap_until.h"
+ }
module merge {
header "__pstl/cpu_algos/merge.h"
}
diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index 7e9fa5cfacc30..f4bcb34030f23 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -34,6 +34,7 @@
using non_forward_iterator = cpp17_input_iterator<int*>;
using non_bidirectional_iterator = forward_iterator<int*>;
+using non_randomaccess_iterator = bidirectional_iterator<int*>;
struct non_output_iterator : forward_iterator<int*> {
constexpr int const& operator*() const; // prevent it from being an output iterator
};
@@ -41,6 +42,7 @@ struct non_output_iterator : forward_iterator<int*> {
void f(non_forward_iterator non_fwd,
non_output_iterator non_output,
non_bidirectional_iterator non_bidir,
+ non_randomaccess_iterator non_random,
std::execution::sequenced_policy pol) {
auto pred = [](auto&&...) -> bool { return true; };
auto func = [](auto&&...) -> int { return 1; };
@@ -146,6 +148,13 @@ void f(non_forward_iterator non_fwd,
pol, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: is_partitioned}}
}
+ {
+ (void)std::is_heap_until(
+ pol, non_random, non_random); // expected-error@*:* {{static assertion failed: is_heap_until}}
+ (void)std::is_heap_until(
+ pol, non_random, non_random, pred); // expected-error@*:* {{static assertion failed: is_heap_until}}
+ }
+
{
(void)std::is_sorted(pol, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: is_sorted}}
(void)std::is_sorted(pol, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: is_sorted}}
diff --git a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
index 61758770102f3..4dc4a221a2d10 100644
--- a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
@@ -52,6 +52,10 @@ void test() {
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::find_first_of(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b), pred2);
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::is_heap_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_heap_until(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_partitioned(std::execution::par, std::begin(a), std::end(a), pred);
// 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));
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/is.heap/pstl.is_heap_until.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/is.heap/pstl.is_heap_until.pass.cpp
new file mode 100644
index 0000000000000..880dcce3d95d5
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/is.heap/pstl.is_heap_until.pass.cpp
@@ -0,0 +1,1064 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <algorithm>
+
+// template<class ExecutionPolicy, class RandomAccessIterator>
+// RandomAccessIterator
+// is_heap_until(ExecutionPolicy&& exec,
+// RandomAccessIterator first, RandomAccessIterator last);
+
+#include <cstddef>
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "runway_sample.h"
+
+EXECUTION_POLICY_SFINAE_TEST(is_heap_until);
+
+static_assert(sfinae_test_is_heap_until<int, int*, int*>);
+static_assert(!sfinae_test_is_heap_until<std::execution::parallel_policy, int*, int*>);
+
+template <class Iter>
+struct Test {
+ template <class ExecutionPolicy>
+ void operator()(ExecutionPolicy&& policy) {
+ { // Check the return type
+ int a[] = {0};
+ auto res = std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a)));
+ static_assert(std::is_same_v<decltype(res), Iter>);
+ }
+ { // Empty
+ int a[] = {0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::begin(a))) == Iter(std::begin(a)));
+ }
+ { // Single
+ int a[] = {0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+ }
+ { // Size=2, heap
+ int a[] = {0, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+ }
+ { // Size=2, not heap
+ int a[] = {0, 1};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Size=2, heap
+ int a[] = {1, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+ }
+ { // Size=3, heap
+ int a[] = {0, 0, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+ }
+ { // Size=3, not heap
+ int a[] = {0, 0, 1};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+ }
+ { // Size=3, not heap
+ int a[] = {0, 1, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Size=3, not heap
+ int a[] = {0, 1, 1};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Size=3, heap
+ int a[] = {1, 0, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+ }
+ { // Size=3, heap
+ int a[] = {1, 0, 1};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+ }
+ { // Size=3, heap
+ int a[] = {1, 1, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+ }
+ { // Size=4, heap
+ int a[] = {0, 0, 0, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+ }
+ { // Size=4, not heap
+ int a[] = {0, 0, 0, 1};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 3));
+ }
+ { // Size=4, not heap
+ int a[] = {0, 0, 1, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+ }
+ { // Size=4, not heap
+ int a[] = {0, 0, 1, 1};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+ }
+ { // Size=4, not heap
+ int a[] = {0, 1, 0, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Size=4, not heap
+ int a[] = {0, 1, 0, 1};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Size=4, not heap
+ int a[] = {0, 1, 1, 0};
+ assert(std::is_heap_until(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Size=4, not heap
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/218603
More information about the libcxx-commits
mailing list