From b4d2b2f9a31ba82b5bcbf9060748bde8beae814b Mon Sep 17 00:00:00 2001 From: "Michael G. Kazakov" Date: Fri, 31 Jul 2026 02:06:38 +0100 Subject: [PATCH] [libc++][pstl] Implementation of parallel std::lexicographical_compare() based on std::mismatch() (#212366) This PR adds an implementation of parallel `std::lexicographical_compare()` based on parallel `std::mismatch()`. The implementation is close to a one-liner: ```c++ auto __res = _Mismatch()(__policy, __first1, __last1, __first2, __last2, [&](_Ref1 __lhs, _Ref2 __rhs) { return !__comp(__lhs, __rhs) && !__comp(__rhs, __lhs); }); ``` Included tests check that: - Semantics of the iterator-only version is correct. - Semantics of the predicated version is correct. - The functions correctly SFINAE out when the first argument is not an execution policy. - The `noexcept` policy is followed. - The `nodiscard` policy is followed. - `static_assert` verifies iterators' categories. Part of #99938. --- libcxx/include/__algorithm/pstl.h | 50 ++++ libcxx/include/__pstl/backend_fwd.h | 7 + libcxx/include/__pstl/backends/default.h | 31 ++- .../pstl.iterator-requirements.verify.cpp | 11 + .../algorithms/pstl.nodiscard.verify.cpp | 4 + .../pstl.lexicographical_compare.pass.cpp | 178 +++++++++++++++ ...pstl.lexicographical_compare_comp.pass.cpp | 214 ++++++++++++++++++ .../pstl.exception_handling.pass.cpp | 16 ++ 8 files changed, 510 insertions(+), 1 deletion(-) create mode 100644 libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare.pass.cpp create mode 100644 libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare_comp.pass.cpp diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h index 0447691c3b86..bf6c2a030d34 100644 --- a/libcxx/include/__algorithm/pstl.h +++ b/libcxx/include/__algorithm/pstl.h @@ -253,6 +253,56 @@ template (__policy), std::move(__first), std::move(__last), std::move(__predicate)); } +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool lexicographical_compare( + _ExecutionPolicy&& __policy, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "lexicographical_compare requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "lexicographical_compare requires ForwardIterators"); + using _Implementation = + __pstl::__dispatch<__pstl::__lexicographical_compare, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + less<>{}); +} + +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool lexicographical_compare( + _ExecutionPolicy&& __policy, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _Comp __comp) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "lexicographical_compare requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "lexicographical_compare requires ForwardIterators"); + using _Implementation = + __pstl::__dispatch<__pstl::__lexicographical_compare, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__comp)); +} + template +struct __lexicographical_compare; +// template +// optional +// operator()(_Policy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, +// _ForwardIterator2 __first2, _ForwardIterator2 __last2, _Comp __comp) const noexcept; + } // namespace __pstl _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h index 05700daaf3e8..df287bdb67dc 100644 --- a/libcxx/include/__pstl/backends/default.h +++ b/libcxx/include/__pstl/backends/default.h @@ -69,6 +69,7 @@ namespace __pstl { // mismatch family // --------------- // - adjacent_find +// - lexicographical_compare // - mismatch_3leg // // for_each family @@ -224,6 +225,33 @@ struct __find_first_of<__default_backend_tag, _ExecutionPolicy> { // mismatch family ////////////////////////////////////////////////////////////// +template +struct __lexicographical_compare<__default_backend_tag, _ExecutionPolicy> { + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional + operator()(_Policy&& __policy, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _Comp __comp) const noexcept { + using _Mismatch = __dispatch<__mismatch, __current_configuration, _ExecutionPolicy>; + using _Ref1 = __iterator_reference<_ForwardIterator1>; + using _Ref2 = __iterator_reference<_ForwardIterator2>; + // find the first pair of elements that are not equal, or the end of one or both of the ranges + auto __res = _Mismatch()(__policy, __first1, __last1, __first2, __last2, [&](_Ref1 __lhs, _Ref2 __rhs) { + return !__comp(__lhs, __rhs) && !__comp(__rhs, __lhs); // derive equality from the less-than predicate + }); + if (!__res) // if the underlying mismatch operation failed, return nullopt + return nullopt; + if (__res->first == __last1) // the first range is exhausted, + return __res->second != __last2; // it is lexicographically less if the second range is not exhausted. + if (__res->second == __last2) // the second range is exhausted, + return false; // the first range is not exhausted, so it is not lexicographically less. + return __comp(*__res->first, *__res->second); // otherwise, compare the first pair of non-equal elements + } +}; + template struct __mismatch_3leg<__default_backend_tag, _ExecutionPolicy> { template @@ -674,7 +702,8 @@ struct __adjacent_difference<__default_backend_tag, _ExecutionPolicy> { ++__result; _ForwardIterator1 __first2 = std::next(__first1); if (__first2 == __last1) - return __result; // edge case: not enough elements to perform adjacent difference, just return the output iterator + return __result; // edge case: not enough elements to perform adjacent difference, just return the output + // iterator // Process as a binary transform of two iterator ranges: [__first1 + 1, __last1) and [__first1, __last1 - 1) return _TransformBinary()( __policy, diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp index 640109ac131f..636c4cf84ab2 100644 --- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp +++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp @@ -114,6 +114,17 @@ void f(non_forward_iterator non_fwd, (void)std::generate_n(pol, non_fwd, n, func); // expected-error@*:* {{static assertion failed: generate_n}} } + { + (void)std::lexicographical_compare( + pol, it, it, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: lexicographical_compare}} + (void)std::lexicographical_compare( + pol, it, it, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: lexicographical_compare}} + (void)std::lexicographical_compare( + pol, non_fwd, non_fwd, it, it); // expected-error@*:* {{static assertion failed: lexicographical_compare}} + (void)std::lexicographical_compare( + pol, non_fwd, non_fwd, it, it, pred); // expected-error@*:* {{static assertion failed: lexicographical_compare}} + } + { (void)std::reverse_copy( pol, non_bidir, non_bidir, it); // expected-error@*:* {{static assertion failed: reverse_copy}} diff --git a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp index 352f00f1c9ba..0efb6ffe6b0c 100644 --- a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp +++ b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp @@ -75,4 +75,8 @@ void test() { std::adjacent_find(std::execution::par, std::begin(a), std::end(a)); // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} std::adjacent_find(std::execution::par, std::begin(a), std::end(a), pred2); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::lexicographical_compare(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::lexicographical_compare(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b), pred2); } diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare.pass.cpp new file mode 100644 index 000000000000..85eaf5128afe --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare.pass.cpp @@ -0,0 +1,178 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// bool lexicographical_compare(ExecutionPolicy&& exec, +// ForwardIterator1 first1, +// ForwardIterator1 last1, +// ForwardIterator2 first2, +// ForwardIterator2 last2); + +#include +#include +#include +#include +#include +#include + +#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(lexicographical_compare); + +static_assert(sfinae_test_lexicographical_compare); +static_assert(!sfinae_test_lexicographical_compare); + +// The types X and Y are provided to test that lexicographical_compare can be used with heterogeneous custom types. + +struct X { + X() = delete; + X(int i) : i_(i) {} + X(const X&) = delete; + int value() const { return i_; } + +private: + int i_; +}; + +struct Y { + Y() = delete; + Y(int i) : i_(i) {} + Y(const Y&) = delete; + int value() const { return i_; } + +private: + int i_; +}; + +bool operator<(const X& lhs, const Y& rhs) { return lhs.value() < rhs.value(); } +bool operator<(const Y& lhs, const X& rhs) { return lhs.value() < rhs.value(); } + +template +struct Test { + template + void operator()(ExecutionPolicy&& policy) { + { // check the return types + int lhs[] = {0}; + int rhs[] = {0}; + auto res = std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Iter2(std::begin(rhs))); + static_assert(std::is_same_v); + } + { // 2 empty ranges + int lhs[] = {0}; + int rhs[] = {0}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Iter2(std::begin(rhs)))); + } + { // left empty, right non-empty + int lhs[] = {0}; + int rhs[] = {0}; + assert(std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + } + { // left non-empty, right empty + int lhs[] = {0}; + int rhs[] = {0}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::begin(rhs)))); + } + { // same size, same single element + int lhs[] = {0}; + int rhs[] = {0}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + } + { // left longer + int lhs[] = {1, 2, 3, 4, 5}; + int rhs[] = {1, 2, 3}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + } + { // right longer + int lhs[] = {1, 2, 3}; + int rhs[] = {1, 2, 3, 4, 5}; + assert(std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + } + { // same size, left is lexicographically less than right + int lhs[] = {1, 2, 2, 4, 5}; + int rhs[] = {1, 2, 3, 4, 5}; + assert(std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + } + { // same size, right is lexicographically less than left + int lhs[] = {1, 2, 3, 4, 5}; + int rhs[] = {1, 2, 2, 4, 5}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + } + { // same size, different at various positions + int lhs[1073]; + int rhs[1073]; + std::iota(std::begin(lhs), std::end(lhs), 0); + std::copy(std::begin(lhs), std::end(lhs), std::begin(rhs)); + runway_sample(std::size(lhs), [&](size_t i) { + lhs[i] = -1; + assert(std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + lhs[i] = static_cast(i); + rhs[i] = -1; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + rhs[i] = static_cast(i); + }); + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + } + } +}; + +template +struct TestXY { + template + void operator()(ExecutionPolicy&& policy) { + { // same ranges + X lhs[] = {X(1), X(5), X(7)}; + Y rhs[] = {Y(1), Y(5), Y(7)}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + } + { // one element difference + X lhs[] = {X(1), X(5), X(7)}; + Y rhs[] = {Y(1), Y(5), Y(8)}; + assert(std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)))); + } + } +}; + +int main(int, char**) { + types::for_each(types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { + using Iter = typename decltype(v)::type; + types::for_each( + types::forward_iterator_list{}, + TestIteratorWithPolicies::template apply>{}); + }}); + types::for_each(types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { + using Iter = typename decltype(v)::type; + types::for_each( + types::forward_iterator_list{}, + TestIteratorWithPolicies::template apply>{}); + }}); + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare_comp.pass.cpp new file mode 100644 index 000000000000..ba70ec24e2cd --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare_comp.pass.cpp @@ -0,0 +1,214 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// bool lexicographical_compare(ExecutionPolicy&& exec, +// ForwardIterator1 first1, +// ForwardIterator1 last1, +// ForwardIterator2 first2, +// ForwardIterator2 last2, +// Compare comp); + +#include +#include +#include +#include +#include +#include + +#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(lexicographical_compare); + +static_assert(sfinae_test_lexicographical_compare); +static_assert( + !sfinae_test_lexicographical_compare); + +// The types X and Y are provided to test that lexicographical_compare can be used with heterogeneous custom types. + +struct X { + X() = delete; + X(int i) : i_(i) {} + X(const X&) = delete; + int value() const { return i_; } + +private: + int i_; +}; + +struct Y { + Y() = delete; + Y(int i) : i_(i) {} + Y(const Y&) = delete; + int value() const { return i_; } + +private: + int i_; +}; + +struct Comp { + bool operator()(int lhs, int rhs) const { return lhs > rhs; } + bool operator()(const X& lhs, const Y& rhs) const { return lhs.value() > rhs.value(); } + bool operator()(const Y& lhs, const X& rhs) const { return lhs.value() > rhs.value(); } +}; + +template +struct Test { + template + void operator()(ExecutionPolicy&& policy) { + { // check the return types + int lhs[] = {0}; + int rhs[] = {0}; + auto res = std::lexicographical_compare( + policy, + Iter1(std::begin(lhs)), + Iter1(std::begin(lhs)), + Iter2(std::begin(rhs)), + Iter2(std::begin(rhs)), + Comp{}); + static_assert(std::is_same_v); + } + { // 2 empty ranges + int lhs[] = {0}; + int rhs[] = {0}; + assert(!std::lexicographical_compare( + policy, + Iter1(std::begin(lhs)), + Iter1(std::begin(lhs)), + Iter2(std::begin(rhs)), + Iter2(std::begin(rhs)), + Comp{})); + } + { // left empty, right non-empty + int lhs[] = {0}; + int rhs[] = {0}; + assert(std::lexicographical_compare( + policy, + Iter1(std::begin(lhs)), + Iter1(std::begin(lhs)), + Iter2(std::begin(rhs)), + Iter2(std::end(rhs)), + Comp{})); + } + { // left non-empty, right empty + int lhs[] = {0}; + int rhs[] = {0}; + assert(!std::lexicographical_compare( + policy, + Iter1(std::begin(lhs)), + Iter1(std::end(lhs)), + Iter2(std::begin(rhs)), + Iter2(std::begin(rhs)), + Comp{})); + } + { // same size, same single element + int lhs[] = {0}; + int rhs[] = {0}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{})); + } + { // left longer + int lhs[] = {1, 2, 3, 4, 5}; + int rhs[] = {1, 2, 3}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{})); + } + { // right longer + int lhs[] = {1, 2, 3}; + int rhs[] = {1, 2, 3, 4, 5}; + assert(std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{})); + } + { // same size, left is lexicographically less than right + int lhs[] = {1, 2, 4, 4, 5}; + int rhs[] = {1, 2, 3, 4, 5}; + assert(std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{})); + } + { // same size, right is lexicographically less than left + int lhs[] = {1, 2, 3, 4, 5}; + int rhs[] = {1, 2, 4, 4, 5}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{})); + } + { // same size, different at various positions + int lhs[1073]; + int rhs[1073]; + std::iota(std::begin(lhs), std::end(lhs), 0); + std::copy(std::begin(lhs), std::end(lhs), std::begin(rhs)); + runway_sample(std::size(lhs), [&](size_t i) { + lhs[i] = 10'000; + assert(std::lexicographical_compare( + policy, + Iter1(std::begin(lhs)), + Iter1(std::end(lhs)), + Iter2(std::begin(rhs)), + Iter2(std::end(rhs)), + Comp{})); + lhs[i] = static_cast(i); + rhs[i] = 10'000; + assert(!std::lexicographical_compare( + policy, + Iter1(std::begin(lhs)), + Iter1(std::end(lhs)), + Iter2(std::begin(rhs)), + Iter2(std::end(rhs)), + Comp{})); + rhs[i] = static_cast(i); + }); + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{})); + } + } +}; + +template +struct TestXY { + template + void operator()(ExecutionPolicy&& policy) { + { // same ranges + X lhs[] = {X(1), X(5), X(7)}; + Y rhs[] = {Y(1), Y(5), Y(7)}; + assert(!std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{})); + } + { // one element difference + X lhs[] = {X(1), X(5), X(8)}; + Y rhs[] = {Y(1), Y(5), Y(7)}; + assert(std::lexicographical_compare( + policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{})); + } + } +}; + +int main(int, char**) { + types::for_each(types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { + using Iter = typename decltype(v)::type; + types::for_each( + types::forward_iterator_list{}, + TestIteratorWithPolicies::template apply>{}); + }}); + types::for_each(types::forward_iterator_list{}, types::apply_type_identity{[](auto v) { + using Iter = typename decltype(v)::type; + types::for_each( + types::forward_iterator_list{}, + TestIteratorWithPolicies::template apply>{}); + }}); + 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 e3e76bc3692d..a505e1441d2a 100644 --- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp +++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp @@ -210,6 +210,22 @@ int main(int, char**) { assert_non_throwing([=, &policy] { (void)std::generate_n(policy, std::move(first1), n, gen); }); } + { + auto pred = maybe_throw(tokens[5], [](int, int) -> bool { return true; }); + + // lexicographical_compare(first1, last1, first2, last2) + assert_non_throwing([=, &policy] { + (void)std::lexicographical_compare( + policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2)); + }); + + // lexicographical_compare(first1, last1, first2, last2, pred) + assert_non_throwing([=, &policy] { + (void)std::lexicographical_compare( + policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2), pred); + }); + } + { // reverse_copy(first, last, dest) assert_non_throwing([=, &policy] {