[libcxx-commits] [libcxx] 150f33c - [libc++][pstl] Implementation of a parallel std::mismatch() based on __pstl::__parallel_find() (#209291)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Jul 26 07:51:44 PDT 2026
Author: Michael G. Kazakov
Date: 2026-07-26T22:51:39+08:00
New Revision: 150f33ce28956d80fc7617e477bb805ab062a28a
URL: https://github.com/llvm/llvm-project/commit/150f33ce28956d80fc7617e477bb805ab062a28a
DIFF: https://github.com/llvm/llvm-project/commit/150f33ce28956d80fc7617e477bb805ab062a28a.diff
LOG: [libc++][pstl] Implementation of a parallel std::mismatch() based on __pstl::__parallel_find() (#209291)
This PR adds a parallel version of `std::mismatch` as one of the backend
operations.
It also provides an implementation based on `__pstl::__parallel_find()`
which does the heavy lifting.
`libdispatch` and `std_thread` backends expose this implementation under
their backend tags, while the `serial` backend redirects the calls to
the serial `std::mismatch`.
4 flavours of the function are exposed: 3-legged, 3-legged with
predicate, 4-legged, 4-legged with predicate.
3-legged flavours are implemented in the `default` (`composition`)
backend by redirecting the call to the 4-legged flavours.
Included tests check that:
- Semantics of the iterator-only functions is correct.
- Semantics of the predicated functions is correct.
- Custom types are supported by the implementation.
- 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.
Added:
libcxx/include/__pstl/cpu_algos/mismatch.h
libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.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 fcea3b7601182..149b7fe0d9c61 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -680,6 +680,7 @@ set(files
__pstl/cpu_algos/find_if.h
__pstl/cpu_algos/for_each.h
__pstl/cpu_algos/merge.h
+ __pstl/cpu_algos/mismatch.h
__pstl/cpu_algos/stable_sort.h
__pstl/cpu_algos/transform.h
__pstl/cpu_algos/transform_reduce.h
diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index 2bf9b4276baab..bc48fd9f48d7f 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -31,6 +31,7 @@ _LIBCPP_PUSH_MACROS
# include <__type_traits/remove_cvref.h>
# include <__utility/forward.h>
# include <__utility/move.h>
+# include <__utility/pair.h>
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -138,6 +139,95 @@ count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __
std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), __value);
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _BinaryPredicate,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<_ForwardIterator1, _ForwardIterator2>
+mismatch(_ExecutionPolicy&& __policy,
+ _ForwardIterator1 __first1,
+ _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2,
+ _ForwardIterator2 __last2,
+ _BinaryPredicate __pred) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "mismatch requires ForwardIterators");
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "mismatch requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__mismatch, __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(__pred));
+}
+
+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 pair<_ForwardIterator1, _ForwardIterator2>
+mismatch(_ExecutionPolicy&& __policy,
+ _ForwardIterator1 __first1,
+ _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2,
+ _ForwardIterator2 __last2) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "mismatch requires ForwardIterators");
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "mismatch requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__mismatch, __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),
+ equal_to{});
+}
+
+template <class _ExecutionPolicy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _BinaryPredicate,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<_ForwardIterator1, _ForwardIterator2>
+mismatch(_ExecutionPolicy&& __policy,
+ _ForwardIterator1 __first1,
+ _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2,
+ _BinaryPredicate __pred) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "mismatch requires ForwardIterators");
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "mismatch requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__mismatch_3leg, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy),
+ std::move(__first1),
+ std::move(__last1),
+ std::move(__first2),
+ std::move(__pred));
+}
+
+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 pair<_ForwardIterator1, _ForwardIterator2> mismatch(
+ _ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) {
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "mismatch requires ForwardIterators");
+ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "mismatch requires ForwardIterators");
+ using _Implementation = __pstl::__dispatch<__pstl::__mismatch_3leg, __pstl::__current_configuration, _RawPolicy>;
+ return __pstl::__handle_exception<_Implementation>(
+ std::forward<_ExecutionPolicy>(__policy),
+ std::move(__first1),
+ std::move(__last1),
+ std::move(__first2),
+ equal_to{});
+}
+
template <class _ExecutionPolicy,
class _ForwardIterator1,
class _ForwardIterator2,
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index 2ba5b4434fc33..ecd1f0b9b4049 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -324,6 +324,21 @@ struct __adjacent_
diff erence;
// operator()(_Policy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
// _ForwardIterator2 __first2, _BinaryOperation &&__op) const noexcept;
+template <class _Backend, class _ExecutionPolicy>
+struct __mismatch;
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
+// optional<pair<_ForwardIterator1, _ForwardIterator2>>
+// operator()(_Policy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
+// _ForwardIterator2 __first2, _ForwardIterator2 __last2,
+// _Comp __comp) const noexcept;
+
+template <class _Backend, class _ExecutionPolicy>
+struct __mismatch_3leg;
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
+// optional<pair<_ForwardIterator1, _ForwardIterator2>>
+// operator()(_Policy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
+// _ForwardIterator2 __first2, _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 28bc75be147aa..776c76f3fdfbd 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -16,6 +16,7 @@
#include <__algorithm/find_if.h>
#include <__algorithm/for_each_n.h>
#include <__algorithm/is_sorted.h>
+#include <__algorithm/mismatch.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/not_fn.h>
@@ -63,6 +64,10 @@ namespace __pstl {
// - is_partitioned
// - find_first_of
//
+// mismatch family
+// ---------------
+// - mismatch_3leg
+//
// for_each family
// ---------------
// - for_each_n
@@ -212,6 +217,38 @@ struct __find_first_of<__default_backend_tag, _ExecutionPolicy> {
}
};
+//////////////////////////////////////////////////////////////
+// mismatch family
+//////////////////////////////////////////////////////////////
+
+template <class _ExecutionPolicy>
+struct __mismatch_3leg<__default_backend_tag, _ExecutionPolicy> {
+ template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
+ optional<pair<_ForwardIterator1, _ForwardIterator2>>
+ operator()(_Policy&& __policy,
+ _ForwardIterator1 __first1,
+ _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2,
+ _Comp __comp) const noexcept {
+ if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+ // Forward to the 4-legged version of mismatch.
+ using _Mismatch = __dispatch<__mismatch, __current_configuration, _ExecutionPolicy>;
+ _ForwardIterator2 __last2 = __first2 + (__last1 - __first1);
+ return _Mismatch()(
+ __policy,
+ std::move(__first1),
+ std::move(__last1),
+ std::move(__first2),
+ std::move(__last2),
+ std::move(__comp));
+ } else {
+ // Currently only random access iterators are supported for parallel mismatch_3leg.
+ return std::mismatch(std::move(__first1), std::move(__last1), std::move(__first2), std::move(__comp));
+ }
+ }
+};
+
//////////////////////////////////////////////////////////////
// for_each family
//////////////////////////////////////////////////////////////
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index f7141d24df090..5e89c6fe31cd8 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -37,6 +37,7 @@
#include <__pstl/cpu_algos/find_if.h>
#include <__pstl/cpu_algos/for_each.h>
#include <__pstl/cpu_algos/merge.h>
+#include <__pstl/cpu_algos/mismatch.h>
#include <__pstl/cpu_algos/stable_sort.h>
#include <__pstl/cpu_algos/transform.h>
#include <__pstl/cpu_algos/transform_reduce.h>
@@ -241,7 +242,7 @@ struct __cpu_traits<__libdispatch_backend_tag> {
auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
auto __index = __chunk == 0 ? 0
: (__chunk * __partitions.__chunk_size_) +
- (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+ (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
if (__this_chunk_size != 1) {
std::__construct_at(
__values.get() + __chunk,
@@ -368,6 +369,10 @@ template <class _ExecutionPolicy>
struct __merge<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_merge<__libdispatch_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __mismatch<__libdispatch_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_mismatch<__libdispatch_backend_tag, _ExecutionPolicy> {};
+
template <class _ExecutionPolicy>
struct __stable_sort<__libdispatch_backend_tag, _ExecutionPolicy>
: __cpu_parallel_stable_sort<__libdispatch_backend_tag, _ExecutionPolicy> {};
diff --git a/libcxx/include/__pstl/backends/serial.h b/libcxx/include/__pstl/backends/serial.h
index f4142016ccc79..d90022ee37145 100644
--- a/libcxx/include/__pstl/backends/serial.h
+++ b/libcxx/include/__pstl/backends/serial.h
@@ -13,6 +13,7 @@
#include <__algorithm/find_if.h>
#include <__algorithm/for_each.h>
#include <__algorithm/merge.h>
+#include <__algorithm/mismatch.h>
#include <__algorithm/stable_sort.h>
#include <__algorithm/transform.h>
#include <__config>
@@ -55,6 +56,25 @@ struct __find_if<__serial_backend_tag, _ExecutionPolicy> {
}
};
+template <class _ExecutionPolicy>
+struct __mismatch<__serial_backend_tag, _ExecutionPolicy> {
+ template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
+ _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator1, _ForwardIterator2>>
+ operator()(_Policy&&,
+ _ForwardIterator1 __first1,
+ _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2,
+ _ForwardIterator2 __last2,
+ _Predicate&& __pred) const noexcept {
+ return std::mismatch(
+ std::move(__first1),
+ std::move(__last1),
+ std::move(__first2),
+ std::move(__last2),
+ std::forward<_Predicate>(__pred));
+ }
+};
+
template <class _ExecutionPolicy>
struct __for_each<__serial_backend_tag, _ExecutionPolicy> {
template <class _Policy, class _ForwardIterator, class _Function>
diff --git a/libcxx/include/__pstl/backends/std_thread.h b/libcxx/include/__pstl/backends/std_thread.h
index dd2c3f15403e3..93935d22b9442 100644
--- a/libcxx/include/__pstl/backends/std_thread.h
+++ b/libcxx/include/__pstl/backends/std_thread.h
@@ -17,6 +17,7 @@
#include <__pstl/cpu_algos/find_if.h>
#include <__pstl/cpu_algos/for_each.h>
#include <__pstl/cpu_algos/merge.h>
+#include <__pstl/cpu_algos/mismatch.h>
#include <__pstl/cpu_algos/stable_sort.h>
#include <__pstl/cpu_algos/transform.h>
#include <__pstl/cpu_algos/transform_reduce.h>
@@ -100,6 +101,10 @@ template <class _ExecutionPolicy>
struct __merge<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_merge<__std_thread_backend_tag, _ExecutionPolicy> {};
+template <class _ExecutionPolicy>
+struct __mismatch<__std_thread_backend_tag, _ExecutionPolicy>
+ : __cpu_parallel_mismatch<__std_thread_backend_tag, _ExecutionPolicy> {};
+
template <class _ExecutionPolicy>
struct __stable_sort<__std_thread_backend_tag, _ExecutionPolicy>
: __cpu_parallel_stable_sort<__std_thread_backend_tag, _ExecutionPolicy> {};
diff --git a/libcxx/include/__pstl/cpu_algos/mismatch.h b/libcxx/include/__pstl/cpu_algos/mismatch.h
new file mode 100644
index 0000000000000..3d702b03d3afe
--- /dev/null
+++ b/libcxx/include/__pstl/cpu_algos/mismatch.h
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_MISMATCH_H
+#define _LIBCPP___PSTL_CPU_ALGOS_MISMATCH_H
+
+#include <__algorithm/min.h>
+#include <__algorithm/mismatch.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.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>
+#include <__utility/pair.h>
+#include <optional>
+
+#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_mismatch {
+ template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
+ _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator1, _ForwardIterator2>>
+ operator()(_Policy&&,
+ _ForwardIterator1 __first1,
+ _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2,
+ _ForwardIterator2 __last2,
+ _Predicate __pred) const noexcept {
+ if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+ __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+ // Look for a mismatch only in the prefix of the two ranges.
+ auto __n = std::min(__last1 - __first1, __last2 - __first2);
+ // Find a position in the first range where the predicate is false against the corresponding position in the
+ // second range.
+ auto __res = __pstl::__parallel_find<_Backend>(
+ __first1,
+ __first1 + __n,
+ [&__pred, __first1, __first2](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1) {
+ // Run the sequential mismatch algorithm on these ranges:
+ // [__brick_first1, __brick_last1) and
+ // [__first2 + (__brick_first1 - __first1), __first2 + (__brick_last1 - __first1))
+ auto __brick_first2 = __first2 + (__brick_first1 - __first1);
+ return std::mismatch(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2), __pred)
+ .first;
+ },
+ less<>{}, // `less` here means the lowest index among the mismatches
+ true // `true` here means we want the first mismatch, not the last
+ );
+ if (!__res) {
+ return std::nullopt; // Failed to run the algorithm, propagate the error.
+ }
+ auto __idx = *__res - __first1;
+ return pair<_ForwardIterator1, _ForwardIterator2>{std::move(*__res), __first2 + __idx};
+ } else {
+ // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+ // Unsequenced execution is also implicitly covered by the sequential implementation.
+ return std::mismatch(
+ std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+ }
+ }
+};
+
+} // namespace __pstl
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_CPU_ALGOS_MISMATCH_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index e3b9e5ac09cb3..3272f9a0aaac5 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2388,6 +2388,9 @@ module std {
module merge {
header "__pstl/cpu_algos/merge.h"
}
+ module mismatch {
+ header "__pstl/cpu_algos/mismatch.h"
+ }
module stable_sort {
header "__pstl/cpu_algos/stable_sort.h"
export std_core.utility_core.empty
diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index 402d8fbf9131a..df11341008bc5 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -135,6 +135,22 @@ 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::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}}
+
+ (void)std::mismatch(pol, non_fwd, non_fwd, it, it); // expected-error@*:* {{static assertion failed: mismatch}}
+ (void)std::mismatch(pol, it, it, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: mismatch}}
+
+ (void)std::mismatch(pol, non_fwd, non_fwd, it, pred); // expected-error@*:* {{static assertion failed: mismatch}}
+ (void)std::mismatch(pol, it, it, non_fwd, pred); // expected-error@*:* {{static assertion failed: mismatch}}
+
+ (void)std::mismatch(
+ pol, non_fwd, non_fwd, it, it, pred); // expected-error@*:* {{static assertion failed: mismatch}}
+ (void)std::mismatch(
+ pol, it, it, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: mismatch}}
+ }
+
{
(void)std::move(pol, non_fwd, non_fwd, out); // expected-error@*:* {{static assertion failed: move}}
(void)std::move(pol, it, it, non_fwd); // expected-error@*:* {{static assertion failed: move}}
diff --git a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
index f4fffd456a331..f5eaf1642b687 100644
--- a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
@@ -63,4 +63,12 @@ void test() {
std::adjacent_
diff erence(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::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::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));
+ // 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), 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), std::end(b), pred2);
}
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
new file mode 100644
index 0000000000000..83f4b0f16d6c1
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
@@ -0,0 +1,226 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+// pair<ForwardIterator1, ForwardIterator2> mismatch(ExecutionPolicy&& exec,
+// ForwardIterator1 first1,
+// ForwardIterator1 last1,
+// ForwardIterator2 first2);
+//
+// template <class ExecutionPolicy,
+// class ForwardIterator1,
+// class ForwardIterator2>
+// pair<ForwardIterator1, ForwardIterator2> mismatch(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(mismatch);
+
+static_assert(sfinae_test_mismatch<int, int*, int*, int*>);
+static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*>);
+static_assert(sfinae_test_mismatch<int, int*, int*, int*, int*>);
+static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*, int*>);
+
+// The types X and Y are provided to test that the mismatch algorithm 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(); }
+
+template <class Iter1, class Iter2>
+struct Test {
+ template <class ExecutionPolicy>
+ void operator()(ExecutionPolicy&& policy) {
+ {
+ // check the return types
+ int lhs[1] = {0};
+ int rhs[1] = {0};
+ auto res_3legged = std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)));
+ auto res_4legged = std::mismatch(
+ 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_3legged), std::pair<Iter1, Iter2>>);
+ static_assert(std::is_same_v<decltype(res_4legged), std::pair<Iter1, Iter2>>);
+ }
+ {
+ // empty ranges
+ int lhs[1] = {0};
+ int rhs[1] = {0};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs)), Iter2(std::begin(rhs))));
+ assert(
+ std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Iter2(std::begin(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs)), Iter2(std::begin(rhs))));
+ }
+ {
+ // single element only
+ int lhs[1] = {0};
+ int rhs[1] = {0};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ assert(std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ }
+ { // same range without mismatch
+ int lhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+ int rhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ assert(std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ }
+ { // same range with mismatch
+ int lhs[8] = {0, 1, 2, 2, 0, 1, 2, 3};
+ int rhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs) + 3), Iter2(std::begin(rhs) + 3)));
+ assert(std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs) + 3), Iter2(std::begin(rhs) + 3)));
+ }
+ { // second range is smaller
+ int lhs[8] = {0, 1, 2, 2, 0, 1, 2, 3};
+ int rhs[2] = {0, 1};
+ assert(std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+ }
+ { // first range is smaller
+ int lhs[2] = {0, 1};
+ int rhs[8] = {0, 1, 2, 2, 0, 1, 2, 3};
+ assert(std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+ }
+ { // same size, mismatching 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::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+ assert(
+ std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+ lhs[i] = i;
+ });
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ assert(std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ }
+ { // same values,
diff erent lengths
+ int lhs[739];
+ int rhs[739];
+ std::fill(std::begin(lhs), std::end(lhs), 42);
+ std::fill(std::begin(rhs), std::end(rhs), 42);
+ runway_sample(std::size(lhs), [&](size_t i) {
+ // lhs is shorter
+ assert(std::mismatch(
+ policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::begin(lhs) + i),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs))) == std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+ // rhs is shorter
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::begin(rhs) + i)) ==
+ std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+ });
+ }
+ }
+};
+
+template <class Iter1, class Iter2>
+struct TestXY {
+ template <class ExecutionPolicy>
+ void operator()(ExecutionPolicy&& policy) {
+ { // same ranges
+ X lhs[3] = {X(1), X(5), X(7)};
+ Y rhs[3] = {Y(1), Y(5), Y(7)};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ assert(std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ }
+ { // one element mismatch
+ X lhs[3] = {X(1), X(5), X(7)};
+ Y rhs[3] = {Y(1), Y(5), Y(8)};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+ assert(std::mismatch(
+ policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+ std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+ }
+ }
+};
+
+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.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
new file mode 100644
index 0000000000000..89cf899a47b4c
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
@@ -0,0 +1,267 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 BinaryPredicate>
+// pair<ForwardIterator1, ForwardIterator2> mismatch(ExecutionPolicy&& exec,
+// ForwardIterator1 first1,
+// ForwardIterator1 last1,
+// ForwardIterator2 first2,
+// BinaryPredicate pred);
+//
+// template <class ExecutionPolicy,
+// class ForwardIterator1,
+// class ForwardIterator2,
+// class BinaryPredicate>
+// pair<ForwardIterator1, ForwardIterator2> mismatch(ExecutionPolicy&& exec,
+// ForwardIterator1 first1,
+// ForwardIterator1 last1,
+// ForwardIterator2 first2,
+// ForwardIterator2 last2,
+// BinaryPredicate pred);
+
+#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(mismatch);
+
+static_assert(sfinae_test_mismatch<int, int*, int*, int*, bool (*)(int, int)>);
+static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*, bool (*)(int, int)>);
+static_assert(sfinae_test_mismatch<int, int*, int*, int*, int*, bool (*)(int, int)>);
+static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*, int*, bool (*)(int, int)>);
+
+// The types X and Y are provided to test that the mismatch algorithm 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 Pred {
+ bool operator()(int lhs, int rhs) const { return lhs * 2 == rhs; }
+ bool operator()(const X& lhs, const Y& rhs) const { return lhs.value() * 2 == rhs.value(); }
+};
+
+template <class Iter1, class Iter2>
+struct Test {
+ template <class ExecutionPolicy>
+ void operator()(ExecutionPolicy&& policy) {
+ {
+ // check the return types
+ int lhs[1] = {0};
+ int rhs[1] = {0};
+ auto res_3legged =
+ std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Pred{});
+ auto res_4legged = std::mismatch(
+ policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::begin(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::begin(rhs)),
+ Pred{});
+ static_assert(std::is_same_v<decltype(res_3legged), std::pair<Iter1, Iter2>>);
+ static_assert(std::is_same_v<decltype(res_4legged), std::pair<Iter1, Iter2>>);
+ }
+ {
+ // empty ranges
+ int lhs[1] = {0};
+ int rhs[1] = {0};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+ std::make_pair(Iter1(std::begin(lhs)), Iter2(std::begin(rhs))));
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::begin(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::begin(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::begin(lhs)), Iter2(std::begin(rhs))));
+ }
+ {
+ // single element only
+ int lhs[1] = {1};
+ int rhs[1] = {2};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ }
+ { // same range without mismatch
+ int lhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+ int rhs[8] = {0, 2, 4, 6, 0, 2, 4, 6};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ }
+ { // same range with mismatch
+ int lhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+ int rhs[8] = {0, 2, 4, 7, 0, 2, 4, 6};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+ std::make_pair(Iter1(std::begin(lhs) + 3), Iter2(std::begin(rhs) + 3)));
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::begin(lhs) + 3), Iter2(std::begin(rhs) + 3)));
+ }
+ { // second range is smaller
+ int lhs[8] = {0, 1, 2, 2, 0, 1, 2, 3};
+ int rhs[2] = {0, 2};
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+ }
+ { // first range is smaller
+ int lhs[2] = {0, 1};
+ int rhs[8] = {0, 2, 2, 2, 0, 1, 2, 3};
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+ }
+ { // same size, mismatching at various positions
+ int lhs[1073];
+ int rhs[1073];
+ std::iota(std::begin(lhs), std::end(lhs), 0);
+ std::transform(std::begin(lhs), std::end(lhs), std::begin(rhs), [](int x) { return x * 2; });
+ runway_sample(std::size(lhs), [&](size_t i) {
+ lhs[i] = -1;
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+ std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+ lhs[i] = i;
+ });
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ }
+ { // same values,
diff erent lengths
+ int lhs[739];
+ int rhs[739];
+ std::fill(std::begin(lhs), std::end(lhs), 42);
+ std::fill(std::begin(rhs), std::end(rhs), 84);
+ runway_sample(std::size(lhs), [&](size_t i) {
+ // lhs is shorter
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::begin(lhs) + i),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+ // rhs is shorter
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::begin(rhs) + i),
+ Pred{}) == std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+ });
+ }
+ }
+};
+
+template <class Iter1, class Iter2>
+struct TestXY {
+ template <class ExecutionPolicy>
+ void operator()(ExecutionPolicy&& policy) {
+ { // same ranges
+ X lhs[3] = {X(1), X(5), X(7)};
+ Y rhs[3] = {Y(2), Y(10), Y(14)};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+ std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+ }
+ { // one element mismatch
+ X lhs[3] = {X(1), X(5), X(7)};
+ Y rhs[3] = {Y(2), Y(10), Y(13)};
+ assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+ std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+ assert(std::mismatch(policy,
+ Iter1(std::begin(lhs)),
+ Iter1(std::end(lhs)),
+ Iter2(std::begin(rhs)),
+ Iter2(std::end(rhs)),
+ Pred{}) == std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+ }
+ }
+};
+
+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 e00046fdb1dd6..cbdb4663f168c 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -248,6 +248,31 @@ int main(int, char**) {
});
}
+ {
+ auto compare = maybe_throw(tokens[5], [](int x, int y) -> bool { return x < y; });
+
+ // mismatch(first1, last1, first2)
+ assert_non_throwing([=, &policy] {
+ (void)std::mismatch(policy, std::move(first1), std::move(last1), std::move(first2));
+ });
+
+ // mismatch(first1, last1, first2, last2)
+ assert_non_throwing([=, &policy] {
+ (void)std::mismatch(policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2));
+ });
+
+ // mismatch(first1, last1, first2, pred)
+ assert_non_throwing([=, &policy] {
+ (void)std::mismatch(policy, std::move(first1), std::move(last1), std::move(first2), compare);
+ });
+
+ // mismatch(first1, last1, first2, last2, pred)
+ assert_non_throwing([=, &policy] {
+ (void)std::mismatch(
+ policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2), compare);
+ });
+ }
+
{
// move(first, last, dest)
assert_non_throwing([=, &policy] {
More information about the libcxx-commits
mailing list