From 6bbd050263e7aeaed7925ae1627f5b3fd31b6f6f Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 15 Jun 2025 17:00:00 +0300 Subject: [PATCH 1/6] benchmark --- benchmarks/src/mismatch.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/benchmarks/src/mismatch.cpp b/benchmarks/src/mismatch.cpp index f604ceff4fb..9d4c79f5c7b 100644 --- a/benchmarks/src/mismatch.cpp +++ b/benchmarks/src/mismatch.cpp @@ -19,13 +19,24 @@ enum class op { lexi, }; -template +struct color { + uint16_t h; + uint16_t s; + uint16_t l; + + bool operator==(const color&) const = default; +}; + +constexpr color c1{30000, 40000, 20000}; +constexpr color c2{30000, 40000, 30000}; + +template void bm(benchmark::State& state) { - vector> a(static_cast(state.range(0)), T{'.'}); - vector> b(static_cast(state.range(0)), T{'.'}); + vector> a(static_cast(state.range(0)), MatchVal); + vector> b(static_cast(state.range(0)), MatchVal); if (state.range(1) != no_pos) { - b.at(static_cast(state.range(1))) = 'x'; + b.at(static_cast(state.range(1))) = MismatchVal; } for (auto _ : state) { @@ -45,6 +56,7 @@ BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); +BENCHMARK(bm)->Apply(common_args); BENCHMARK(bm)->Apply(common_args); // still optimized without vector algorithms using memcmp BENCHMARK(bm)->Apply(common_args); // optimized with vector algorithms only From c958d7cba87b0921ecc7bb4c3535b71597de7eec Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 15 Jun 2025 18:20:29 +0300 Subject: [PATCH 2/6] coverage --- .../test.cpp | 89 +++++++++++++++++-- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp index 458d4314076..7db87ab9a4d 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp @@ -64,20 +64,28 @@ auto last_known_good_lex_compare_3way(pair expected_mismatch, FwdI #endif // _HAS_CXX20 template -void test_case_mismatch_and_lex_compare_family(const vector& a, const vector& b) { +auto test_case_mismatch_only(const vector& a, const vector& b) { auto expected_mismatch = last_known_good_mismatch(a.begin(), a.end(), b.begin(), b.end()); auto actual_mismatch = mismatch(a.begin(), a.end(), b.begin(), b.end()); assert(expected_mismatch == actual_mismatch); - auto expected_lex = last_known_good_lex_compare(expected_mismatch, a.end(), b.end()); - auto actual_lex = lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); - assert(expected_lex == actual_lex); - #if _HAS_CXX20 auto ranges_actual_mismatch = ranges::mismatch(a, b); assert(get<0>(expected_mismatch) == ranges_actual_mismatch.in1); assert(get<1>(expected_mismatch) == ranges_actual_mismatch.in2); +#endif // _HAS_CXX20 + return expected_mismatch; +} + +template +void test_case_mismatch_and_lex_compare_family(const vector& a, const vector& b) { + auto expected_mismatch = test_case_mismatch_only(a, b); + + auto expected_lex = last_known_good_lex_compare(expected_mismatch, a.end(), b.end()); + auto actual_lex = lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + assert(expected_lex == actual_lex); +#if _HAS_CXX20 auto ranges_actual_lex = ranges::lexicographical_compare(a, b); assert(expected_lex == ranges_actual_lex); @@ -130,6 +138,65 @@ void test_mismatch_and_lex_compare_family(mt19937_64& gen) { } } +#if _HAS_CXX20 +template +struct triplet { + T x; + T y; + T z; + + bool operator==(const triplet&) const = default; +}; + +template +void test_mismatch_only_triplets(mt19937_64& gen) { + constexpr size_t shrinkCount = 4; + constexpr size_t mismatchCount = 10; + using TD = conditional_t; + uniform_int_distribution dis('a', 'z'); + vector> input_a; + vector> input_b; + input_a.reserve(dataCount); + input_b.reserve(dataCount); + + for (;;) { + // equal + test_case_mismatch_only(input_a, input_b); + + // different sizes + for (size_t i = 0; i != shrinkCount && !input_b.empty(); ++i) { + input_b.pop_back(); + test_case_mismatch_only(input_a, input_b); + test_case_mismatch_only(input_b, input_a); + } + + // actual mismatch (or maybe not, depending on random) + if (!input_b.empty()) { + uniform_int_distribution mismatch_dis(0, input_a.size() - 1); + + for (size_t attempts = 0; attempts < mismatchCount; ++attempts) { + const size_t possible_mismatch_pos = mismatch_dis(gen); + input_a[possible_mismatch_pos].x = static_cast(dis(gen)); + input_a[possible_mismatch_pos].y = static_cast(dis(gen)); + input_a[possible_mismatch_pos].z = static_cast(dis(gen)); + test_case_mismatch_only(input_a, input_b); + test_case_mismatch_only(input_b, input_a); + } + } + + if (input_a.size() == dataCount) { + break; + } + + input_a.emplace_back(); + input_a.back().x = static_cast(dis(gen)); + input_a.back().y = static_cast(dis(gen)); + input_a.back().z = static_cast(dis(gen)); + input_b = input_a; + } +} +#endif // _HAS_CXX20 + template void test_mismatch_and_lex_compare_family_containers() { C1 a{'m', 'e', 'o', 'w', ' ', 'C', 'A', 'T', 'S'}; @@ -245,6 +312,18 @@ void test_vector_algorithms(mt19937_64& gen) { test_mismatch_and_lex_compare_family(gen); test_mismatch_and_lex_compare_family(gen); +#if _HAS_CXX20 + test_mismatch_only_triplets(gen); + test_mismatch_only_triplets(gen); + test_mismatch_only_triplets(gen); + test_mismatch_only_triplets(gen); + test_mismatch_only_triplets(gen); + test_mismatch_only_triplets(gen); + test_mismatch_only_triplets(gen); + test_mismatch_only_triplets(gen); + test_mismatch_only_triplets(gen); +#endif // _HAS_CXX20 + test_mismatch_and_lex_compare_family_containers, vector>(); test_mismatch_and_lex_compare_family_containers, vector>(); test_mismatch_and_lex_compare_family_containers, vector>(); From 5126b1a0b3229504f9d64c976ffd72fb4bd4086d Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 15 Jun 2025 18:23:33 +0300 Subject: [PATCH 3/6] vectorization --- stl/inc/algorithm | 4 ++-- stl/inc/xutility | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index e8afb54e353..ffa5985bf80 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -883,7 +883,7 @@ _NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, const _InI const auto _ULast1 = _STD _Get_unwrapped(_Last1); auto _UFirst2 = _STD _Get_unwrapped_n(_First2, _STD _Idl_distance<_InIt1>(_UFirst1, _ULast1)); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (_Vector_alg_in_search_is_safe) { + if constexpr (_Equal_memcmp_is_safe) { if (!_STD _Is_constant_evaluated()) { constexpr size_t _Elem_size = sizeof(_Iter_value_t<_InIt1>); @@ -947,7 +947,7 @@ _NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch( const auto _Count = static_cast<_Iter_diff_t<_InIt1>>((_STD min)(_Count1, _Count2)); _ULast1 = _UFirst1 + _Count; #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (_Vector_alg_in_search_is_safe) { + if constexpr (_Equal_memcmp_is_safe) { if (!_STD _Is_constant_evaluated()) { constexpr size_t _Elem_size = sizeof(_Iter_value_t<_InIt1>); diff --git a/stl/inc/xutility b/stl/inc/xutility index dbfbad6ce35..8e1d99408ec 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -454,7 +454,15 @@ size_t _Mismatch_vectorized(const void* const _First1, const void* const _First2 } else if constexpr (_Element_size == 8) { return __std_mismatch_8(_First1, _First2, _Count); } else { - _STL_INTERNAL_STATIC_ASSERT(false); // unexpected size + if constexpr ((_Element_size % 8) == 0) { + return __std_mismatch_8(_First1, _First2, _Count * (_Element_size / 8)) / (_Element_size / 8); + } else if constexpr ((_Element_size % 4) == 0) { + return __std_mismatch_4(_First1, _First2, _Count * (_Element_size / 4)) / (_Element_size / 4); + } else if constexpr ((_Element_size % 2) == 0) { + return __std_mismatch_2(_First1, _First2, _Count * (_Element_size / 2)) / (_Element_size / 2); + } else { + return __std_mismatch_1(_First1, _First2, _Count * _Element_size) / _Element_size; + } } } _STD_END @@ -5720,7 +5728,7 @@ namespace ranges { _It1 _First1, _It2 _First2, iter_difference_t<_It1> _Count, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { _STL_INTERNAL_CHECK(_Count >= 0); #if _USE_STD_VECTOR_ALGORITHMS - if constexpr (_Vector_alg_in_search_is_safe<_It1, _It2, _Pr> && is_same_v<_Pj1, identity> + if constexpr (_Equal_memcmp_is_safe<_It1, _It2, _Pr> && is_same_v<_Pj1, identity> && is_same_v<_Pj2, identity>) { if (!_STD is_constant_evaluated()) { constexpr size_t _Elem_size = sizeof(iter_value_t<_It1>); From eb78ed4949628ffae83343c34a56a991545d2a87 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 3 Oct 2025 08:05:04 -0700 Subject: [PATCH 4/6] Drop unnecessary parens. --- stl/inc/xutility | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index f7318423f9a..039ae54c09c 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -456,11 +456,11 @@ size_t _Mismatch_vectorized(const void* const _First1, const void* const _First2 } else if constexpr (_Element_size == 8) { return __std_mismatch_8(_First1, _First2, _Count); } else { - if constexpr ((_Element_size % 8) == 0) { + if constexpr (_Element_size % 8 == 0) { return __std_mismatch_8(_First1, _First2, _Count * (_Element_size / 8)) / (_Element_size / 8); - } else if constexpr ((_Element_size % 4) == 0) { + } else if constexpr (_Element_size % 4 == 0) { return __std_mismatch_4(_First1, _First2, _Count * (_Element_size / 4)) / (_Element_size / 4); - } else if constexpr ((_Element_size % 2) == 0) { + } else if constexpr (_Element_size % 2 == 0) { return __std_mismatch_2(_First1, _First2, _Count * (_Element_size / 2)) / (_Element_size / 2); } else { return __std_mismatch_1(_First1, _First2, _Count * _Element_size) / _Element_size; From 157ee11858fd757e0af6d42eccad881928b7eb8a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 3 Oct 2025 08:13:48 -0700 Subject: [PATCH 5/6] MODULO RULES ALL --- stl/inc/xutility | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 039ae54c09c..fe79367452b 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -447,24 +447,14 @@ auto _Max_vectorized(_Ty* const _First, _Ty* const _Last) noexcept { template size_t _Mismatch_vectorized(const void* const _First1, const void* const _First2, const size_t _Count) noexcept { - if constexpr (_Element_size == 1) { - return __std_mismatch_1(_First1, _First2, _Count); - } else if constexpr (_Element_size == 2) { - return __std_mismatch_2(_First1, _First2, _Count); - } else if constexpr (_Element_size == 4) { - return __std_mismatch_4(_First1, _First2, _Count); - } else if constexpr (_Element_size == 8) { - return __std_mismatch_8(_First1, _First2, _Count); + if constexpr (_Element_size % 8 == 0) { + return __std_mismatch_8(_First1, _First2, _Count * (_Element_size / 8)) / (_Element_size / 8); + } else if constexpr (_Element_size % 4 == 0) { + return __std_mismatch_4(_First1, _First2, _Count * (_Element_size / 4)) / (_Element_size / 4); + } else if constexpr (_Element_size % 2 == 0) { + return __std_mismatch_2(_First1, _First2, _Count * (_Element_size / 2)) / (_Element_size / 2); } else { - if constexpr (_Element_size % 8 == 0) { - return __std_mismatch_8(_First1, _First2, _Count * (_Element_size / 8)) / (_Element_size / 8); - } else if constexpr (_Element_size % 4 == 0) { - return __std_mismatch_4(_First1, _First2, _Count * (_Element_size / 4)) / (_Element_size / 4); - } else if constexpr (_Element_size % 2 == 0) { - return __std_mismatch_2(_First1, _First2, _Count * (_Element_size / 2)) / (_Element_size / 2); - } else { - return __std_mismatch_1(_First1, _First2, _Count * _Element_size) / _Element_size; - } + return __std_mismatch_1(_First1, _First2, _Count * _Element_size) / _Element_size; } } _STD_END From 95ed203fee706392b8e22e348896f99b528ef857 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 3 Oct 2025 08:47:53 -0700 Subject: [PATCH 6/6] Use injected-class-name. --- .../test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp index 7db87ab9a4d..fd14a0b0968 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp @@ -145,7 +145,7 @@ struct triplet { T y; T z; - bool operator==(const triplet&) const = default; + bool operator==(const triplet&) const = default; }; template