From 8614ef51c82c3ae8540765282e5f670017382c72 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 25 Apr 2025 22:40:36 +0300 Subject: [PATCH 1/4] Test coverage for `search_n` with forward iterators --- .../test.cpp | 76 +++++++++++++++---- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp index 04b3907b83c..00985a926dd 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp @@ -14,6 +14,42 @@ using namespace std; +template +struct forward_iter_adaptor { + using iterator_category = forward_iterator_tag; + using reference = typename UnderlyingIt::reference; + using value_type = typename UnderlyingIt::value_type; + using pointer = typename UnderlyingIt::pointer; + using difference_type = ptrdiff_t; + + constexpr forward_iter_adaptor() : ptr{} {} + constexpr explicit forward_iter_adaptor(const UnderlyingIt ptr_) : ptr(ptr_) {} + + constexpr reference operator*() const { + return *ptr; + } + constexpr pointer operator->() const { + return ptr; + } + constexpr forward_iter_adaptor& operator++() { + ++ptr; + return *this; + } + forward_iter_adaptor operator++(int) { + forward_iter_adaptor old; + ++ptr; + return old; + } + constexpr bool operator==(const forward_iter_adaptor& o) const { + return ptr == o.ptr; + } + constexpr bool operator!=(const forward_iter_adaptor& o) const { + return ptr != o.ptr; + } + + UnderlyingIt ptr; +}; + template auto last_known_good_search_n(FwdIt first, const FwdIt last, const size_t count, const T val) { // Deliberately using simple approach, not smart bidi/random iterators "check from the other end" stuff @@ -40,24 +76,30 @@ auto last_known_good_search_n(FwdIt first, const FwdIt last, const size_t count, return last; } -template -void test_case_search_n(const Container& c, size_t count, T val) { - auto expected = last_known_good_search_n(c.begin(), c.end(), count, val); - auto actual = search_n(c.begin(), c.end(), count, val); - assert(expected == actual); +template +void test_case_search_n(const It first, const It last, const size_t count, const T val) { +#pragma warning(suppress : 4984) // 'if constexpr' is a C++17 language extension + if constexpr (forward_only_iterators) { + using iter_type = forward_iter_adaptor; + test_case_search_n(iter_type(first), iter_type(last), count, val); + } else { + const auto expected = last_known_good_search_n(first, last, count, val); + const auto actual = search_n(first, last, count, val); + assert(expected == actual); #if _HAS_CXX20 - auto ranges_actual = ranges::search_n(c, static_cast(count), val); - assert(expected == begin(ranges_actual)); - if (expected == c.end()) { - assert(end(ranges_actual) == c.end()); - } else { - assert(distance(expected, end(ranges_actual)) == static_cast(count)); - } + const auto ranges_actual = ranges::search_n(first, last, static_cast(count), val); + assert(expected == begin(ranges_actual)); + if (expected == last) { + assert(end(ranges_actual) == last); + } else { + assert(distance(expected, end(ranges_actual)) == static_cast(count)); + } #endif // _HAS_CXX20 + } } -template +template void test_search_n(mt19937_64& gen) { constexpr size_t lengthCount = 70; constexpr size_t patternCount = 5; @@ -74,7 +116,7 @@ void test_search_n(mt19937_64& gen) { const T val = static_cast(dis(gen)); - test_case_search_n(input, count, val); + test_case_search_n(input.begin(), input.end(), count, val); if (input.empty()) { continue; @@ -90,7 +132,7 @@ void test_search_n(mt19937_64& gen) { if (pattern_length + pattern_pos <= input.size()) { fill_n(input.begin() + static_cast(pattern_pos), pattern_length, val); - test_case_search_n(input, count, val); + test_case_search_n(input.begin(), input.end(), count, val); } } } @@ -113,6 +155,10 @@ void test_vector_algorithms(mt19937_64& gen) { test_search_n(gen); test_search_n(gen); test_search_n(gen); + + // Test only one case with forward iteators. It is different complex enough code path, hence worth testing, + // but it is not vectorized, so no point in trying different types. + test_search_n(gen); } int main() { From d6c8197aa27531c2e36eed985bddc99c0029f753 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 25 Apr 2025 23:19:16 +0300 Subject: [PATCH 2/4] clang suppression --- .../tests/VSO_0000000_vector_algorithms_search_n/test.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp index 00985a926dd..2b04b15db7c 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp @@ -12,6 +12,11 @@ #include "test_vector_algorithms_support.hpp" +#pragma warning(disable : 4984) // if constexpr is a C++17 language extension +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wc++17-extensions" +#endif // __clang__ + using namespace std; template @@ -78,7 +83,6 @@ auto last_known_good_search_n(FwdIt first, const FwdIt last, const size_t count, template void test_case_search_n(const It first, const It last, const size_t count, const T val) { -#pragma warning(suppress : 4984) // 'if constexpr' is a C++17 language extension if constexpr (forward_only_iterators) { using iter_type = forward_iter_adaptor; test_case_search_n(iter_type(first), iter_type(last), count, val); From ba8174ee1d86ed83aa224fc8b203f223a1d1021b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 2 May 2025 18:19:19 -0700 Subject: [PATCH 3/4] Fix comment typo, improve grammar. --- .../std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp index 2b04b15db7c..960926782a4 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp @@ -160,8 +160,8 @@ void test_vector_algorithms(mt19937_64& gen) { test_search_n(gen); test_search_n(gen); - // Test only one case with forward iteators. It is different complex enough code path, hence worth testing, - // but it is not vectorized, so no point in trying different types. + // Test only one case with forward iterators. It is a different and complex code path, hence it's worth testing, + // but it is not vectorized, so there's no point in trying different types. test_search_n(gen); } From a3c22a9d70c326cf9b35caeae25afcdcf0c94e36 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 2 May 2025 18:20:58 -0700 Subject: [PATCH 4/4] Add constexpr to postincrement. --- tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp index 960926782a4..08b825855f2 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp @@ -40,7 +40,7 @@ struct forward_iter_adaptor { ++ptr; return *this; } - forward_iter_adaptor operator++(int) { + constexpr forward_iter_adaptor operator++(int) { forward_iter_adaptor old; ++ptr; return old;