[libcxx-commits] [libcxx] 9853cb5 - [libc++][pstl] Implementation of parallel std::min_element() based on parallel reduce (#219876)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Sep 4 07:51:38 PDT 2026
Author: Michael G. Kazakov
Date: 2026-09-04T15:51:33+01:00
New Revision: 9853cb54d9d2684b27f0d0db89c00c2da7e31b88
URL: https://github.com/llvm/llvm-project/commit/9853cb54d9d2684b27f0d0db89c00c2da7e31b88
DIFF: https://github.com/llvm/llvm-project/commit/9853cb54d9d2684b27f0d0db89c00c2da7e31b88.diff
LOG: [libc++][pstl] Implementation of parallel std::min_element() based on parallel reduce (#219876)
This PR adds an implementation of parallel `std::min_element()` based on
parallel reduce.
`std::max_element()` is also added, implemented as a "one-liner" over
`min_element`.
The implementation formulates `min_element` as a reduction of iterators
over the input range.
The reduction is provided in two forms: 2-element reduction that picks
the iterator pointing to a smaller value, and a range-based reduction
with init value. The latter delegates the heavy-lifting to the serial
implementation of `std::min_element()`.
Part of #99938.
Added:
libcxx/include/__pstl/cpu_algos/min_element.h
libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.max_element.pass.cpp
libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.max_element_comp.pass.cpp
libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element.pass.cpp
libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element_comp.pass.cpp
Modified:
libcxx/include/CMakeLists.txt
libcxx/include/__algorithm/pstl.h
libcxx/include/__pstl/backend_fwd.h
libcxx/include/__pstl/backends/default.h
libcxx/include/__pstl/backends/libdispatch.h
libcxx/include/__pstl/backends/serial.h
libcxx/include/__pstl/backends/std_thread.h
libcxx/include/module.modulemap.in
libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 16b0ee0cd952b..d8fbc3462b02b 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -702,6 +702,7 @@ set(files
__pstl/cpu_algos/for_each.h
__pstl/cpu_algos/is_heap_until.h
__pstl/cpu_algos/merge.h
+ __pstl/cpu_algos/min_element.h
__pstl/cpu_algos/mismatch.h
__pstl/cpu_algos/reverse.h
__pstl/cpu_algos/search.h
diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index dc8b35a1d5a75..14b81ed0ade4f 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -139,6 +139,56 @@ count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __
std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), __value);
}
+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
+max_element(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "max_element requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__max_element, __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 _Compare,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+max_element(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "max_element requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__max_element, __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>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+min_element(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "min_element requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__min_element, __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 _Compare,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+min_element(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "min_element requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__min_element, __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 _ForwardIterator1,
class _ForwardIterator2,
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index 75179087c2e09..bec595449b40c 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -201,6 +201,18 @@ struct __merge;
// _ForwardIterator2 __first2, _ForwardIterator2 __last2,
// _ForwardOutIterator __result, _Comp __comp) const noexcept;
+template <class _Backend, class _ExecutionPolicy>
+struct __max_element;
+// template <class _Policy, class _ForwardIterator, class _Compare>
+// optional<_ForwardIterator>
+// operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept;
+
+template <class _Backend, class _ExecutionPolicy>
+struct __min_element;
+// template <class _Policy, class _ForwardIterator, class _Compare>
+// optional<_ForwardIterator>
+// operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept;
+
template <class _Backend, class _ExecutionPolicy>
struct __search_n;
// template <class _Policy, class _ForwardIterator, class _Size, class _T, class _Predicate>
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index f9cbe615ce8c6..e63c3802538de 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -78,6 +78,10 @@ namespace __pstl {
// - is_partitioned
// - find_first_of
//
+// min_element family
+// ---------------
+// - max_element
+//
// mismatch family
// ---------------
// - adjacent_find
@@ -254,6 +258,26 @@ struct __find_first_of<__default_backend_tag, _ExecutionPolicy> {
}
};
+//////////////////////////////////////////////////////////////
+// min_element family
+//////////////////////////////////////////////////////////////
+
+template <class _ExecutionPolicy>
+struct __max_element<__default_backend_tag, _ExecutionPolicy> {
+ template <class _Policy, class _ForwardIterator, class _Compare>
+ optional<_ForwardIterator>
+ operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
+ using _MinElement = __dispatch<__min_element, __current_configuration, _ExecutionPolicy>;
+ using _Ref = __iterator_reference<_ForwardIterator>;
+ // Express max_element via min_element by replacing the comparison
+ // "lhs OP rhs" with "rhs OP lhs".
+ return _MinElement()(
+ __policy, std::move(__first), std::move(__last), [__comp = std::move(__comp)](_Ref __lhs, _Ref __rhs) {
+ return __comp(__rhs, __lhs);
+ });
+ }
+};
+
//////////////////////////////////////////////////////////////
// mismatch family
//////////////////////////////////////////////////////////////
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 2ea980300646c..5d3fef8a4a176 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -42,6 +42,7 @@
#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/min_element.h>
#include <__pstl/cpu_algos/mismatch.h>
#include <__pstl/cpu_algos/reverse.h>
#include <__pstl/cpu_algos/search.h>
@@ -384,6 +385,10 @@ template <class _ExecutionPolicy>
struct __merge<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_merge<__libdispatch_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __min_element<__libdispatch_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_min_element<__libdispatch_backend_tag, _ExecutionPolicy> {};
+
template <class _ExecutionPolicy>
struct __mismatch<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_mismatch<__libdispatch_backend_tag, _ExecutionPolicy> {};
diff --git a/libcxx/include/__pstl/backends/serial.h b/libcxx/include/__pstl/backends/serial.h
index 2ab2675c55a89..ae4a21315ea31 100644
--- a/libcxx/include/__pstl/backends/serial.h
+++ b/libcxx/include/__pstl/backends/serial.h
@@ -15,6 +15,7 @@
#include <__algorithm/for_each.h>
#include <__algorithm/is_heap_until.h>
#include <__algorithm/merge.h>
+#include <__algorithm/min_element.h>
#include <__algorithm/mismatch.h>
#include <__algorithm/reverse.h>
#include <__algorithm/search.h>
@@ -135,6 +136,15 @@ struct __merge<__serial_backend_tag, _ExecutionPolicy> {
}
};
+template <class _ExecutionPolicy>
+struct __min_element<__serial_backend_tag, _ExecutionPolicy> {
+ template <class _Policy, class _ForwardIterator, class _Compare>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+ operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
+ return std::min_element(std::move(__first), std::move(__last), std::move(__comp));
+ }
+};
+
template <class _ExecutionPolicy>
struct __reverse<__serial_backend_tag, _ExecutionPolicy> {
template <class _Policy, class _BidirectionalIterator>
diff --git a/libcxx/include/__pstl/backends/std_thread.h b/libcxx/include/__pstl/backends/std_thread.h
index 22d11406f459c..25742c01eb298 100644
--- a/libcxx/include/__pstl/backends/std_thread.h
+++ b/libcxx/include/__pstl/backends/std_thread.h
@@ -21,6 +21,7 @@
#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/min_element.h>
#include <__pstl/cpu_algos/mismatch.h>
#include <__pstl/cpu_algos/reverse.h>
#include <__pstl/cpu_algos/search.h>
@@ -115,6 +116,10 @@ template <class _ExecutionPolicy>
struct __merge<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_merge<__std_thread_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __min_element<__std_thread_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_min_element<__std_thread_backend_tag, _ExecutionPolicy> {};
+
template <class _ExecutionPolicy>
struct __mismatch<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_mismatch<__std_thread_backend_tag, _ExecutionPolicy> {};
diff --git a/libcxx/include/__pstl/cpu_algos/min_element.h b/libcxx/include/__pstl/cpu_algos/min_element.h
new file mode 100644
index 0000000000000..3f61d8c2b4b42
--- /dev/null
+++ b/libcxx/include/__pstl/cpu_algos/min_element.h
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___PSTL_CPU_ALGOS_MIN_ELEMENT_H
+#define _LIBCPP___PSTL_CPU_ALGOS_MIN_ELEMENT_H
+
+#include <__algorithm/min_element.h>
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__optional/optional.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/cpu_algos/cpu_traits.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_min_element {
+ template <class _Policy, class _ForwardIterator, class _Compare>
+ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
+ operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Compare __comp) const noexcept {
+ if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
+ if (__first == __last) {
+ return __last; // nothing to do
+ }
+
+ _ForwardIterator __init = __first;
+ ++__first;
+ if (__first == __last) {
+ return __init; // the only element is the minimum
+ }
+
+ // A reduction that returns an iterator pointing to the lowest element, left bias in case of a tie
+ auto __iter_reduce = [&__comp](_ForwardIterator __lhs, _ForwardIterator __rhs) {
+ return __comp(*__rhs, *__lhs) ? __rhs : __lhs;
+ };
+
+ // Perform a parallel reduction of iterators [first+1, last) with 'first' as init.
+ return __cpu_traits<_Backend>::__transform_reduce(
+ std::move(__first),
+ std::move(__last),
+ __identity{}, // No transformations
+ std::move(__init), // Use the first iterator as the init element
+ __iter_reduce, // Reduction of 2 elements
+ [&__iter_reduce, &__comp](auto __brick_first, auto __brick_last, auto __brick_init) {
+ // Reduction of an iterage range + init element: use the serial version to find the minimum among
+ // the iterators and then reduce with the init element.
+ // Atm __transform_reduce can give empty bricks in edge cases, handle them explicitly until the contract is
+ // tightened.
+ return __brick_first == __brick_last
+ ? __brick_init
+ : __iter_reduce(__brick_init, std::min_element(__brick_first, __brick_last, __comp));
+ });
+ } else {
+ // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+ return std::min_element(std::move(__first), std::move(__last), std::move(__comp));
+ }
+ }
+};
+
+} // namespace __pstl
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_CPU_ALGOS_MIN_ELEMENT_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 4c5e63721610a..45f98a7b6b9e5 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2446,6 +2446,9 @@ module std {
module merge {
header "__pstl/cpu_algos/merge.h"
}
+ module min_element {
+ header "__pstl/cpu_algos/min_element.h"
+ }
module mismatch {
header "__pstl/cpu_algos/mismatch.h"
}
diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index c1275baa8bbbd..d67770cedc944 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -186,6 +186,13 @@ void f(non_forward_iterator non_fwd,
(void)std::merge(pol, it, it, it, it, non_output, pred); // expected-error@*:* {{static assertion failed: merge}}
}
+ {
+ (void)std::max_element(pol, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: max_element}}
+ (void)std::max_element(pol, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: max_element}}
+ (void)std::min_element(pol, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: min_element}}
+ (void)std::min_element(pol, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: min_element}}
+ }
+
{
(void)std::mismatch(pol, non_fwd, non_fwd, it); // expected-error@*:* {{static assertion failed: mismatch}}
(void)std::mismatch(pol, it, it, non_fwd); // expected-error@*:* {{static assertion failed: mismatch}}
diff --git a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
index f72696f5a26b1..1dbb100792d4e 100644
--- a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
@@ -76,6 +76,14 @@ void test() {
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::adjacent_
diff erence(std::execution::par, std::begin(a), std::end(a), std::begin(b), pred2);
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::max_element(std::execution::par, std::begin(a), std::end(a));
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::max_element(std::execution::par, std::begin(a), std::end(a), pred2);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::min_element(std::execution::par, std::begin(a), std::end(a));
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::min_element(std::execution::par, std::begin(a), std::end(a), pred2);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::mismatch(std::execution::par, std::begin(a), std::end(a), std::begin(b));
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::mismatch(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b));
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.max_element.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.max_element.pass.cpp
new file mode 100644
index 0000000000000..188f5d9e5f6b4
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.max_element.pass.cpp
@@ -0,0 +1,146 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 ForwardIterator>
+// ForwardIterator
+// max_element(ExecutionPolicy&& exec,
+// ForwardIterator first, ForwardIterator last);
+
+#include <cstddef>
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <numeric>
+#include <random>
+#include <vector>
+
+#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(max_element);
+
+static_assert(sfinae_test_max_element<int, int*, int*>);
+static_assert(!sfinae_test_max_element<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::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)));
+ static_assert(std::is_same_v<decltype(res), Iter>);
+ }
+ { // Empty
+ int a[] = {0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::begin(a))) == Iter(std::begin(a)));
+ }
+ { // Single
+ int a[] = {0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Two elements, second max
+ int a[] = {0, 1};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Two elements, first max
+ int a[] = {1, 0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Three elements, first max
+ int a[] = {2, 1, 0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Three elements, middle max
+ int a[] = {0, 2, 1};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Three elements, last max
+ int a[] = {1, 0, 2};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+ }
+ { // Four elements, first max
+ int a[] = {3, 0, 2, 1};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Four elements, all equal
+ int a[] = {1, 1, 1, 1};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Four elements, middle max
+ int a[] = {0, 3, 2, 1};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Four elements, middle max
+ int a[] = {0, 2, 3, 1};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+ }
+ { // Four elements, middle max and equal to consequent elements
+ int a[] = {0, 3, 3, 3};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Four elements, last max
+ int a[] = {0, 1, 2, 3};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 3));
+ }
+ { // Check for maximum among iotaed and shuffled elements
+ std::mt19937 randomness;
+ auto verify_max = [&](Iter first, Iter last) {
+ Iter i = std::max_element(policy, first, last);
+ if (first != last) {
+ for (Iter j = first; j != last; ++j)
+ assert(!(*j > *i));
+ } else {
+ assert(i == last);
+ }
+ };
+ auto test_n_elem = [&](int N) {
+ std::vector<int> a(N);
+ std::iota(a.begin(), a.end(), 0);
+ std::shuffle(a.begin(), a.end(), randomness);
+ verify_max(Iter(a.data()), Iter(a.data() + N));
+ };
+ test_n_elem(3);
+ test_n_elem(4);
+ test_n_elem(5);
+ test_n_elem(10);
+ test_n_elem(100);
+ test_n_elem(1000);
+ }
+ { // Check that the first one among equals is returned
+ int a[1073];
+ // Fill with 0 0 0 0 .... 2 1 2 1 ...
+ for (std::size_t i = 0; i < std::size(a); ++i)
+ a[i] = (i < 473) ? 0 : (i % 2 ? 2 : 1);
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 473));
+ }
+ { // Check that the maximum at sampled locations is found
+ int a[1073];
+ std::fill(std::begin(a), std::end(a), 0);
+ runway_sample(std::size(a), [&](size_t i) {
+ a[i] = 1;
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + i));
+ a[i] = 0;
+ });
+ }
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<const int*>{}, TestIteratorWithPolicies<Test>{});
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.max_element_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.max_element_comp.pass.cpp
new file mode 100644
index 0000000000000..4f0e0b475e4bf
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.max_element_comp.pass.cpp
@@ -0,0 +1,149 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 ForwardIterator, class Compare>
+// ForwardIterator
+// max_element(ExecutionPolicy&& exec,
+// ForwardIterator first, ForwardIterator last,
+// Compare comp);
+
+#include <cstddef>
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <numeric>
+#include <random>
+#include <vector>
+
+#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(max_element);
+
+static_assert(sfinae_test_max_element<int, int*, int*, bool (*)(int, int)>);
+static_assert(!sfinae_test_max_element<std::execution::parallel_policy, int*, int*, bool (*)(int, int)>);
+
+template <class Iter>
+struct Test {
+ template <class ExecutionPolicy>
+ void operator()(ExecutionPolicy&& policy) {
+ std::greater<int> comp;
+ { // Check the return type
+ int a[] = {0};
+ auto res = std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp);
+ static_assert(std::is_same_v<decltype(res), Iter>);
+ }
+ { // Empty
+ int a[] = {0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::begin(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Single
+ int a[] = {0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Two elements, first max
+ int a[] = {0, 1};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Two elements, second max
+ int a[] = {1, 0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 1));
+ }
+ { // Three elements, first max
+ int a[] = {0, 1, 2};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Three elements, middle max
+ int a[] = {1, 0, 2};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 1));
+ }
+ { // Three elements, middle max and equal to last element
+ int a[] = {1, 0, 0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 1));
+ }
+ { // Three elements, last max
+ int a[] = {2, 1, 0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 2));
+ }
+ { // Four elements, first max
+ int a[] = {0, 1, 2, 3};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Four elements, all equal
+ int a[] = {1, 1, 1, 1};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Four elements, middle max
+ int a[] = {3, 0, 2, 1};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 1));
+ }
+ { // Four elements, middle max and equal to consequent elements
+ int a[] = {3, 0, 0, 0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 1));
+ }
+ { // Four elements, last max
+ int a[] = {3, 2, 1, 0};
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 3));
+ }
+ { // Check for maximum among iotaed and shuffled elements
+ std::mt19937 randomness;
+ auto verify_max = [&](Iter first, Iter last) {
+ Iter i = std::max_element(policy, first, last, comp);
+ if (first != last) {
+ for (Iter j = first; j != last; ++j)
+ assert(!(*j < *i));
+ } else {
+ assert(i == last);
+ }
+ };
+ auto test_n_elem = [&](int N) {
+ std::vector<int> a(N);
+ std::iota(a.begin(), a.end(), 0);
+ std::shuffle(a.begin(), a.end(), randomness);
+ verify_max(Iter(a.data()), Iter(a.data() + N));
+ };
+ test_n_elem(3);
+ test_n_elem(4);
+ test_n_elem(5);
+ test_n_elem(10);
+ test_n_elem(100);
+ test_n_elem(1000);
+ }
+ { // Check that the first one among equals is returned
+ int a[1073];
+ // Fill with 2 2 2 2 .... 0 1 0 1 ...
+ for (std::size_t i = 0; i < std::size(a); ++i)
+ a[i] = (i < 473) ? 2 : (i % 2 ? 0 : 1);
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 473));
+ }
+ { // Check that the maximum at sampled locations is found
+ int a[1073];
+ std::fill(std::begin(a), std::end(a), 1);
+ runway_sample(std::size(a), [&](size_t i) {
+ a[i] = 0;
+ assert(std::max_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + i));
+ a[i] = 1;
+ });
+ }
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<const int*>{}, TestIteratorWithPolicies<Test>{});
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element.pass.cpp
new file mode 100644
index 0000000000000..59587f65a1efd
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element.pass.cpp
@@ -0,0 +1,146 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 ForwardIterator>
+// ForwardIterator
+// min_element(ExecutionPolicy&& exec,
+// ForwardIterator first, ForwardIterator last);
+
+#include <cstddef>
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <numeric>
+#include <random>
+#include <vector>
+
+#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(min_element);
+
+static_assert(sfinae_test_min_element<int, int*, int*>);
+static_assert(!sfinae_test_min_element<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::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)));
+ static_assert(std::is_same_v<decltype(res), Iter>);
+ }
+ { // Empty
+ int a[] = {0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::begin(a))) == Iter(std::begin(a)));
+ }
+ { // Single
+ int a[] = {0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Two elements, first min
+ int a[] = {0, 1};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Two elements, second min
+ int a[] = {1, 0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Three elements, first min
+ int a[] = {0, 1, 2};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Three elements, middle min
+ int a[] = {1, 0, 2};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Three elements, middle min and equal to last element
+ int a[] = {1, 0, 0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Three elements, last min
+ int a[] = {2, 1, 0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+ }
+ { // Four elements, first min
+ int a[] = {0, 1, 2, 3};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Four elements, all equal
+ int a[] = {1, 1, 1, 1};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+ }
+ { // Four elements, middle min
+ int a[] = {3, 0, 2, 1};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Four elements, middle min and equal to consequent elements
+ int a[] = {3, 0, 0, 0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+ }
+ { // Four elements, last min
+ int a[] = {3, 2, 1, 0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 3));
+ }
+ { // Check for minimum among iotaed and shuffled elements
+ std::mt19937 randomness;
+ auto verify_min = [&](Iter first, Iter last) {
+ Iter i = std::min_element(policy, first, last);
+ if (first != last) {
+ for (Iter j = first; j != last; ++j)
+ assert(!(*j < *i));
+ } else {
+ assert(i == last);
+ }
+ };
+ auto test_n_elem = [&](int N) {
+ std::vector<int> a(N);
+ std::iota(a.begin(), a.end(), 0);
+ std::shuffle(a.begin(), a.end(), randomness);
+ verify_min(Iter(a.data()), Iter(a.data() + N));
+ };
+ test_n_elem(3);
+ test_n_elem(4);
+ test_n_elem(5);
+ test_n_elem(10);
+ test_n_elem(100);
+ test_n_elem(1000);
+ }
+ { // Check that the first one among equals is returned
+ int a[1073];
+ // Fill with 2 2 2 2 .... 0 1 0 1 ...
+ for (std::size_t i = 0; i < std::size(a); ++i)
+ a[i] = (i < 473) ? 2 : (i % 2 ? 0 : 1);
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 473));
+ }
+ { // Check that the minimum at sampled locations is found
+ int a[1073];
+ std::fill(std::begin(a), std::end(a), 1);
+ runway_sample(std::size(a), [&](size_t i) {
+ a[i] = 0;
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + i));
+ a[i] = 1;
+ });
+ }
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<const int*>{}, TestIteratorWithPolicies<Test>{});
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element_comp.pass.cpp
new file mode 100644
index 0000000000000..f24a37e08e0ad
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.min.max/pstl.min_element_comp.pass.cpp
@@ -0,0 +1,149 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 ForwardIterator, class Compare>
+// ForwardIterator
+// min_element(ExecutionPolicy&& exec,
+// ForwardIterator first, ForwardIterator last,
+// Compare comp);
+
+#include <cstddef>
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <numeric>
+#include <random>
+#include <vector>
+
+#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(min_element);
+
+static_assert(sfinae_test_min_element<int, int*, int*, bool (*)(int, int)>);
+static_assert(!sfinae_test_min_element<std::execution::parallel_policy, int*, int*, bool (*)(int, int)>);
+
+template <class Iter>
+struct Test {
+ template <class ExecutionPolicy>
+ void operator()(ExecutionPolicy&& policy) {
+ std::greater<int> comp;
+ { // Check the return type
+ int a[] = {0};
+ auto res = std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp);
+ static_assert(std::is_same_v<decltype(res), Iter>);
+ }
+ { // Empty
+ int a[] = {0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::begin(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Single
+ int a[] = {0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Two elements, second min
+ int a[] = {0, 1};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 1));
+ }
+ { // Two elements, first min
+ int a[] = {1, 0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Three elements, first min
+ int a[] = {2, 1, 0};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Three elements, middle min
+ int a[] = {0, 2, 1};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 1));
+ }
+ { // Three elements, last min
+ int a[] = {1, 0, 2};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 2));
+ }
+ { // Four elements, first min
+ int a[] = {3, 0, 2, 1};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Four elements, all equal
+ int a[] = {1, 1, 1, 1};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a)));
+ }
+ { // Four elements, middle min
+ int a[] = {0, 3, 2, 1};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 1));
+ }
+ { // Four elements, middle min
+ int a[] = {0, 2, 3, 1};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 2));
+ }
+ { // Four elements, middle min and equal to consequent elements
+ int a[] = {0, 3, 3, 3};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 1));
+ }
+ { // Four elements, last min
+ int a[] = {0, 1, 2, 3};
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 3));
+ }
+ { // Check for minimum among iotaed and shuffled elements
+ std::mt19937 randomness;
+ auto verify_min = [&](Iter first, Iter last) {
+ Iter i = std::min_element(policy, first, last, comp);
+ if (first != last) {
+ for (Iter j = first; j != last; ++j)
+ assert(!(*j > *i));
+ } else {
+ assert(i == last);
+ }
+ };
+ auto test_n_elem = [&](int N) {
+ std::vector<int> a(N);
+ std::iota(a.begin(), a.end(), 0);
+ std::shuffle(a.begin(), a.end(), randomness);
+ verify_min(Iter(a.data()), Iter(a.data() + N));
+ };
+ test_n_elem(3);
+ test_n_elem(4);
+ test_n_elem(5);
+ test_n_elem(10);
+ test_n_elem(100);
+ test_n_elem(1000);
+ }
+ { // Check that the first one among equals is returned
+ int a[1073];
+ // Fill with 0 0 0 0 .... 2 1 2 1 ...
+ for (std::size_t i = 0; i < std::size(a); ++i)
+ a[i] = (i < 473) ? 0 : (i % 2 ? 2 : 1);
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + 473));
+ }
+ { // Check that the minimum at sampled locations is found
+ int a[1073];
+ std::fill(std::begin(a), std::end(a), 0);
+ runway_sample(std::size(a), [&](size_t i) {
+ a[i] = 1;
+ assert(std::min_element(policy, Iter(std::begin(a)), Iter(std::end(a)), comp) == Iter(std::begin(a) + i));
+ a[i] = 0;
+ });
+ }
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<const int*>{}, TestIteratorWithPolicies<Test>{});
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
index f7e096948e51c..6c652c8918f63 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -282,6 +282,26 @@ int main(int, char**) {
});
}
+ {
+ auto compare = maybe_throw(tokens[5], [](int x, int y) -> bool { return x < y; });
+
+ // max_element(first, last)
+ assert_non_throwing([=, &policy] { (void)std::max_element(policy, std::move(first1), std::move(last1)); });
+
+ // max_element(first, last, comp)
+ assert_non_throwing([=, &policy] {
+ (void)std::max_element(policy, std::move(first1), std::move(last1), compare);
+ });
+
+ // min_element(first, last)
+ assert_non_throwing([=, &policy] { (void)std::min_element(policy, std::move(first1), std::move(last1)); });
+
+ // min_element(first, last, comp)
+ assert_non_throwing([=, &policy] {
+ (void)std::min_element(policy, std::move(first1), std::move(last1), compare);
+ });
+ }
+
{
auto compare = maybe_throw(tokens[5], [](int x, int y) -> bool { return x < y; });
More information about the libcxx-commits
mailing list