blob: 83f4b0f16d6c1d62d278876b8bea2262eb16c386 [file] [edit]
//===----------------------------------------------------------------------===//
//
// 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;
}