Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 65 additions & 15 deletions tests/std/tests/VSO_0000000_vector_algorithms_search_n/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,49 @@

#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 <class UnderlyingIt>
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;
}
constexpr 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 <class FwdIt, class T>
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
Expand All @@ -40,24 +81,29 @@ auto last_known_good_search_n(FwdIt first, const FwdIt last, const size_t count,
return last;
}

template <class Container, class T>
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 <bool forward_only_iterators, class It, class T>
void test_case_search_n(const It first, const It last, const size_t count, const T val) {
if constexpr (forward_only_iterators) {
using iter_type = forward_iter_adaptor<It>;
test_case_search_n<false>(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<ptrdiff_t>(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<ptrdiff_t>(count));
}
const auto ranges_actual = ranges::search_n(first, last, static_cast<ptrdiff_t>(count), val);
assert(expected == begin(ranges_actual));
if (expected == last) {
assert(end(ranges_actual) == last);
} else {
assert(distance(expected, end(ranges_actual)) == static_cast<ptrdiff_t>(count));
}
#endif // _HAS_CXX20
}
}

template <class T>
template <class T, bool forward_only_iterators = false>
void test_search_n(mt19937_64& gen) {
constexpr size_t lengthCount = 70;
constexpr size_t patternCount = 5;
Expand All @@ -74,7 +120,7 @@ void test_search_n(mt19937_64& gen) {

const T val = static_cast<T>(dis(gen));

test_case_search_n(input, count, val);
test_case_search_n<forward_only_iterators>(input.begin(), input.end(), count, val);

if (input.empty()) {
continue;
Expand All @@ -90,7 +136,7 @@ void test_search_n(mt19937_64& gen) {
if (pattern_length + pattern_pos <= input.size()) {
fill_n(input.begin() + static_cast<ptrdiff_t>(pattern_pos), pattern_length, val);

test_case_search_n(input, count, val);
test_case_search_n<forward_only_iterators>(input.begin(), input.end(), count, val);
}
}
}
Expand All @@ -113,6 +159,10 @@ void test_vector_algorithms(mt19937_64& gen) {
test_search_n<unsigned int>(gen);
test_search_n<long long>(gen);
test_search_n<unsigned long long>(gen);

// 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<short, true>(gen);
}

int main() {
Expand Down