[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.
This commit is contained in:
parent
a81db64570
commit
150f33ce28
14 changed files with 809 additions and 1 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -324,6 +324,21 @@ struct __adjacent_difference;
|
|||
// 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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> {};
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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> {};
|
||||
|
|
|
|||
90
libcxx/include/__pstl/cpu_algos/mismatch.h
Normal file
90
libcxx/include/__pstl/cpu_algos/mismatch.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -63,4 +63,12 @@ void test() {
|
|||
std::adjacent_difference(std::execution::par, std::begin(a), std::end(a), std::begin(b));
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::adjacent_difference(std::execution::par, std::begin(a), std::end(a), std::begin(b), pred2);
|
||||
// expected-warning@+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@+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@+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@+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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, different 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;
|
||||
}
|
||||
|
|
@ -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, different 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;
|
||||
}
|
||||
|
|
@ -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] {
|
||||
|
|
|
|||
Loading…
Reference in a new issue