//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// // // template // requires HasEqualTo // constexpr pair // constexpr after c++17 // mismatch(Iter1 first1, Iter1 last1, Iter2 first2); // // template // constexpr pair // constexpr after c++17 // mismatch(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2); // C++14 // // template Pred> // requires CopyConstructible // constexpr pair // constexpr after c++17 // mismatch(Iter1 first1, Iter1 last1, Iter2 first2, Pred pred); // // template // constexpr pair // constexpr after c++17 // mismatch(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2, Pred pred); // C++14 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=50000000 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=100000000 #include #include #include #include #include #include #include #include "test_macros.h" #include "test_iterators.h" #include "type_algorithms.h" template TEST_CONSTEXPR_CXX20 void check(Container1 lhs, Container2 rhs, size_t offset) { if (lhs.size() == rhs.size()) { assert(std::mismatch(Iter(lhs.data()), Iter(lhs.data() + lhs.size()), Iter(rhs.data())) == std::make_pair(Iter(lhs.data() + offset), Iter(rhs.data() + offset))); assert(std::mismatch(Iter(lhs.data()), Iter(lhs.data() + lhs.size()), Iter(rhs.data()), std::equal_to()) == std::make_pair(Iter(lhs.data() + offset), Iter(rhs.data() + offset))); } #if TEST_STD_VER >= 14 assert( std::mismatch(Iter(lhs.data()), Iter(lhs.data() + lhs.size()), Iter(rhs.data()), Iter(rhs.data() + rhs.size())) == std::make_pair(Iter(lhs.data() + offset), Iter(rhs.data() + offset))); assert(std::mismatch(Iter(lhs.data()), Iter(lhs.data() + lhs.size()), Iter(rhs.data()), Iter(rhs.data() + rhs.size()), std::equal_to()) == std::make_pair(Iter(lhs.data() + offset), Iter(rhs.data() + offset))); #endif } // Compares modulo 4 to make sure we only forward to the vectorized version if we are trivially equality comparable struct NonTrivialMod4Comp { int i_; TEST_CONSTEXPR_CXX20 NonTrivialMod4Comp(int i) : i_(i) {} TEST_CONSTEXPR_CXX20 NonTrivialMod4Comp(NonTrivialMod4Comp&& other) : i_(other.i_) { other.i_ = 0; } TEST_CONSTEXPR_CXX20 friend bool operator==(const NonTrivialMod4Comp& lhs, const NonTrivialMod4Comp& rhs) { return lhs.i_ % 4 == rhs.i_ % 4; } }; #if TEST_STD_VER >= 20 struct TriviallyEqualityComparable { int i_; TEST_CONSTEXPR_CXX20 TriviallyEqualityComparable(int i) : i_(i) {} TEST_CONSTEXPR_CXX20 friend bool operator==(TriviallyEqualityComparable, TriviallyEqualityComparable) = default; }; #endif // TEST_STD_VER >= 20 struct ModTwoComp { TEST_CONSTEXPR_CXX20 bool operator()(int lhs, int rhs) { return lhs % 2 == rhs % 2; } }; template TEST_CONSTEXPR_CXX20 bool test() { { // empty ranges std::array lhs = {}; std::array rhs = {}; check(lhs, rhs, 0); } { // same range without mismatch std::array lhs = {0, 1, 2, 3, 0, 1, 2, 3}; std::array rhs = {0, 1, 2, 3, 0, 1, 2, 3}; check(lhs, rhs, 8); } { // same range with mismatch std::array lhs = {0, 1, 2, 2, 0, 1, 2, 3}; std::array rhs = {0, 1, 2, 3, 0, 1, 2, 3}; check(lhs, rhs, 3); } { // second range is smaller std::array lhs = {0, 1, 2, 2, 0, 1, 2, 3}; std::array rhs = {0, 1}; check(lhs, rhs, 2); } { // first range is smaller std::array lhs = {0, 1}; std::array rhs = {0, 1, 2, 2, 0, 1, 2, 3}; check(lhs, rhs, 2); } { // use a custom comparator std::array lhs = {0, 2, 3, 4}; std::array rhs = {0, 0, 4, 4}; assert(std::mismatch(lhs.data(), lhs.data() + lhs.size(), rhs.data(), ModTwoComp()) == std::make_pair(lhs.data() + 2, rhs.data() + 2)); #if TEST_STD_VER >= 14 assert(std::mismatch(lhs.data(), lhs.data() + lhs.size(), rhs.data(), rhs.data() + rhs.size(), ModTwoComp()) == std::make_pair(lhs.data() + 2, rhs.data() + 2)); #endif } return true; } struct Test { template TEST_CONSTEXPR_CXX20 void operator()() { test(); } }; TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::cpp17_input_iterator_list(), Test()); { // use a non-integer type to also test the general case - all elements match std::array lhs = {1, 2, 3, 4, 5, 6, 7, 8}; std::array rhs = {1, 2, 3, 4, 1, 6, 7, 8}; check(std::move(lhs), std::move(rhs), 8); } { // use a non-integer type to also test the general case - not all elements match std::array lhs = {1, 2, 3, 4, 7, 6, 7, 8}; std::array rhs = {1, 2, 3, 4, 5, 6, 7, 8}; check(std::move(lhs), std::move(rhs), 4); } #if TEST_STD_VER >= 20 { // trivially equality comparable class type to test forwarding to the vectorized version - all elements match std::array lhs = {1, 2, 3, 4, 5, 6, 7, 8}; std::array rhs = {1, 2, 3, 4, 5, 6, 7, 8}; check(std::move(lhs), std::move(rhs), 8); } { // trivially equality comparable class type to test forwarding to the vectorized version - not all elements match std::array lhs = {1, 2, 3, 4, 7, 6, 7, 8}; std::array rhs = {1, 2, 3, 4, 5, 6, 7, 8}; check(std::move(lhs), std::move(rhs), 4); } #endif // TEST_STD_VER >= 20 return true; } int main(int, char**) { test(); #if TEST_STD_VER >= 20 static_assert(test()); #endif { // check with a lot of elements to test the vectorization optimization { std::vector lhs(256); std::vector rhs(256); for (size_t i = 0; i != lhs.size(); ++i) { lhs[i] = 1; check(lhs, rhs, i); lhs[i] = 0; rhs[i] = 1; check(lhs, rhs, i); rhs[i] = 0; } } { std::vector lhs(256); std::vector rhs(256); for (size_t i = 0; i != lhs.size(); ++i) { lhs[i] = 1; check(lhs, rhs, i); lhs[i] = 0; rhs[i] = 1; check(lhs, rhs, i); rhs[i] = 0; } } } { // check the tail of the vectorized loop for (size_t vec_size = 1; vec_size != 256; ++vec_size) { { std::vector lhs(vec_size); std::vector rhs(vec_size); check(lhs, rhs, lhs.size()); lhs.back() = 1; check(lhs, rhs, lhs.size() - 1); lhs.back() = 0; rhs.back() = 1; check(lhs, rhs, lhs.size() - 1); rhs.back() = 0; } { std::vector lhs(vec_size); std::vector rhs(vec_size); check(lhs, rhs, lhs.size()); lhs.back() = 1; check(lhs, rhs, lhs.size() - 1); lhs.back() = 0; rhs.back() = 1; check(lhs, rhs, lhs.size() - 1); rhs.back() = 0; } } } return 0; }