[libcxx-commits] [libcxx] b4d2b2f - [libc++][pstl] Implementation of parallel std::lexicographical_compare() based on std::mismatch() (#212366)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 30 18:06:43 PDT 2026


Author: Michael G. Kazakov
Date: 2026-07-31T09:06:38+08:00
New Revision: b4d2b2f9a31ba82b5bcbf9060748bde8beae814b

URL: https://github.com/llvm/llvm-project/commit/b4d2b2f9a31ba82b5bcbf9060748bde8beae814b
DIFF: https://github.com/llvm/llvm-project/commit/b4d2b2f9a31ba82b5bcbf9060748bde8beae814b.diff

LOG: [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.

Added: 
    libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare.pass.cpp
    libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/pstl.lexicographical_compare_comp.pass.cpp

Modified: 
    libcxx/include/__algorithm/pstl.h
    libcxx/include/__pstl/backend_fwd.h
    libcxx/include/__pstl/backends/default.h
    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/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index 0447691c3b86b..bf6c2a030d348 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -253,6 +253,56 @@ template <class _ExecutionPolicy,
       std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__predicate));
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator1,
+          class _ForwardIterator2,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
+          class _ForwardIterator1,
+          class _ForwardIterator2,
+          class _Comp,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
           class _ForwardIterator1,
           class _ForwardIterator2,

diff  --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index 3c835426ec377..eaa987a2a3c94 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -346,6 +346,13 @@ struct __adjacent_find;
 // operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last,
 //                                _BinaryPredicate __predicate) const noexcept;
 
+template <class _Backend, class _ExecutionPolicy>
+struct __lexicographical_compare;
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
+// optional<bool>
+// 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 05700daaf3e84..df287bdb67dc1 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 <class _ExecutionPolicy>
+struct __lexicographical_compare<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
+  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 <class _ExecutionPolicy>
 struct __mismatch_3leg<__default_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
@@ -674,7 +702,8 @@ struct __adjacent_
diff erence<__default_backend_tag, _ExecutionPolicy> {
     ++__result;
     _ForwardIterator1 __first2 = std::next(__first1);
     if (__first2 == __last1)
-      return __result; // edge case: not enough elements to perform adjacent 
diff erence, just return the output iterator
+      return __result; // edge case: not enough elements to perform adjacent 
diff erence, 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 640109ac131fb..636c4cf84ab2d 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 352f00f1c9baf..0efb6ffe6b0cd 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 at +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 at +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 at +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 0000000000000..85eaf5128afe8
--- /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 <class ExecutionPolicy,
+//           class ForwardIterator1,
+//           class ForwardIterator2>
+//   bool lexicographical_compare(ExecutionPolicy&& exec,
+//                                ForwardIterator1 first1,
+//                                ForwardIterator1 last1,
+//                                ForwardIterator2 first2,
+//                                ForwardIterator2 last2);
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <limits>
+#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(lexicographical_compare);
+
+static_assert(sfinae_test_lexicographical_compare<int, int*, int*, int*, int*>);
+static_assert(!sfinae_test_lexicographical_compare<std::execution::parallel_policy, int*, int*, int*, int*>);
+
+// 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 <class Iter1, class Iter2>
+struct Test {
+  template <class ExecutionPolicy>
+  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<decltype(res), bool>);
+    }
+    { // 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, 
diff erent 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<int>(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<int>(i);
+      });
+      assert(!std::lexicographical_compare(
+          policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))));
+    }
+  }
+};
+
+template <class Iter1, class Iter2>
+struct TestXY {
+  template <class ExecutionPolicy>
+  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 
diff erence
+      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<const int*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<const int*>{},
+                        TestIteratorWithPolicies<types::partial_instantiation<Test, Iter>::template apply>{});
+                  }});
+  types::for_each(types::forward_iterator_list<const X*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<const Y*>{},
+                        TestIteratorWithPolicies<types::partial_instantiation<TestXY, Iter>::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 0000000000000..ba70ec24e2cdf
--- /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 <class ExecutionPolicy,
+//           class ForwardIterator1,
+//           class ForwardIterator2,
+//           class Compare>
+//   bool lexicographical_compare(ExecutionPolicy&& exec,
+//                                ForwardIterator1 first1,
+//                                ForwardIterator1 last1,
+//                                ForwardIterator2 first2,
+//                                ForwardIterator2 last2,
+//                                Compare comp);
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <limits>
+#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(lexicographical_compare);
+
+static_assert(sfinae_test_lexicographical_compare<int, int*, int*, int*, int*, bool (*)(int, int)>);
+static_assert(
+    !sfinae_test_lexicographical_compare<std::execution::parallel_policy, int*, int*, int*, int*, bool (*)(int, int)>);
+
+// 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 <class Iter1, class Iter2>
+struct Test {
+  template <class ExecutionPolicy>
+  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<decltype(res), bool>);
+    }
+    { // 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, 
diff erent 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<int>(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<int>(i);
+      });
+      assert(!std::lexicographical_compare(
+          policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs)), Comp{}));
+    }
+  }
+};
+
+template <class Iter1, class Iter2>
+struct TestXY {
+  template <class ExecutionPolicy>
+  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 
diff erence
+      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<const int*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<const int*>{},
+                        TestIteratorWithPolicies<types::partial_instantiation<Test, Iter>::template apply>{});
+                  }});
+  types::for_each(types::forward_iterator_list<const X*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<const Y*>{},
+                        TestIteratorWithPolicies<types::partial_instantiation<TestXY, Iter>::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 e3e76bc3692d3..a505e1441d2a9 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] {


        


More information about the libcxx-commits mailing list