//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// // // UNSUPPORTED: c++03, c++11, c++14, c++17 // template S1, forward_iterator I2, sentinel_for S2, // class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> // requires indirectly_comparable // constexpr I1 ranges::find_first_of(I1 first1, S1 last1, I2 first2, S2 last2, // Pred pred = {}, // Proj1 proj1 = {}, Proj2 proj2 = {}); // template // requires indirectly_comparable, iterator_t, Pred, Proj1, Proj2> // constexpr borrowed_iterator_t // ranges::find_first_of(R1&& r1, R2&& r2, // Pred pred = {}, // Proj1 proj1 = {}, Proj2 proj2 = {}); #include #include #include #include #include "almost_satisfies_types.h" #include "test_iterators.h" template concept HasFindFirstOfIt = requires(Iter1 iter1, Sent1 sent1, Iter2 iter2, Sent2 sent2) { std::ranges::find_first_of(iter1, sent1, iter2, sent2); }; static_assert(HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); static_assert(!HasFindFirstOfIt); // not indirectly_comparable template > concept HasFindFirstOfR = requires(Range1 range1, Range2 range2) { std::ranges::find_first_of(range1, range2); }; static_assert(HasFindFirstOfR>); static_assert(!HasFindFirstOfR); static_assert(!HasFindFirstOfR); static_assert(!HasFindFirstOfR); static_assert(!HasFindFirstOfR, ForwardRangeNotDerivedFrom>); static_assert(!HasFindFirstOfR, ForwardRangeNotIncrementable>); static_assert(!HasFindFirstOfR, InputRangeNotSentinelSemiregular>); static_assert(!HasFindFirstOfR, InputRangeNotSentinelEqualityComparableWith>); static_assert(!HasFindFirstOfR, ForwardRangeNotSentinelSemiregular>); static_assert(!HasFindFirstOfR, ForwardRangeNotSentinelEqualityComparableWith>); static_assert(!HasFindFirstOfR, UncheckedRange>); // not indirectly_comparable template struct Data { std::array input1; std::array input2; std::ptrdiff_t expected; }; template constexpr void test(Data d) { { std::same_as decltype(auto) ret = std::ranges::find_first_of(Iter1(d.input1.data()), Sent1(Iter1(d.input1.data() + d.input1.size())), Iter2(d.input2.data()), Sent2(Iter2(d.input2.data() + d.input2.size()))); assert(base(ret) == d.input1.data() + d.expected); } { auto range1 = std::ranges::subrange(Iter1(d.input1.data()), Sent1(Iter1(d.input1.data() + d.input1.size()))); auto range2 = std::ranges::subrange(Iter2(d.input2.data()), Sent2(Iter2(d.input2.data() + d.input2.size()))); std::same_as decltype(auto) ret = std::ranges::find_first_of(range1, range2); assert(base(ret) == d.input1.data() + d.expected); } } template constexpr void test_iterators() { // simple test test({.input1 = {1, 2, 3, 4}, .input2 = {2, 3}, .expected = 1}); // other elements from input2 are checked test({.input1 = {1, 2, 3, 4}, .input2 = {3, 2}, .expected = 1}); // an empty second range returns last test({.input1 = {1, 2, 3, 4}, .input2 = {}, .expected = 4}); // check that an empty first range works test({.input1 = {}, .input2 = {1}, .expected = 0}); // check both ranges empty works test({.input1 = {}, .input2 = {}, .expected = 0}); // the first element is checked properly test({.input1 = {5, 4, 3, 2, 1}, .input2 = {1, 5}, .expected = 0}); // the last element is checked properly test({.input1 = {5, 4, 3, 2, 1}, .input2 = {1, 6}, .expected = 4}); // no match, one-past-the-end iterator should be returned test({.input1 = {1, 3, 5, 7}, .input2 = {0, 2, 4, 6}, .expected = 4}); // input2 contains a single element test({.input1 = {1, 3, 5, 7}, .input2 = {1}, .expected = 0}); } template constexpr void test_iterators1() { test_iterators, sentinel_wrapper>>(); test_iterators>(); test_iterators>(); test_iterators>(); test_iterators>(); test_iterators(); } constexpr bool test() { test_iterators1, sentinel_wrapper>>(); test_iterators1, sentinel_wrapper>>(); test_iterators1>(); test_iterators1>(); test_iterators1>(); test_iterators1>(); test_iterators1(); { // check that std::ranges::dangling is returned [[maybe_unused]] std::same_as decltype(auto) ret = std::ranges::find_first_of(std::array {1}, std::array {1}); } { // check that the predicate is used int a[] = {1, 2, 3, 4}; int b[] = {2}; { auto ret = std::ranges::find_first_of(std::begin(a), std::end(a), std::begin(b), std::end(b), std::ranges::greater{}); assert(ret == a + 2); } { auto ret = std::ranges::find_first_of(a, b, std::ranges::greater{}); assert(ret == a + 2); } } { // check that the projections are used int a[] = {1, 2, 3, 4}; int b[] = {4}; { auto ret = std::ranges::find_first_of(std::begin(a), std::end(a), std::begin(b), std::end(b), {}, [](int i) { return i / 2; }, [](int i) { return i - 3; }); assert(ret == a + 1); } { auto ret = std::ranges::find_first_of(a, b, {}, [](int i) { return i / 2; }, [](int i) { return i - 3; }); assert(ret == a + 1); } } { // check that std::invoke is used struct S1 { constexpr S1(int i_) : i(i_) {} constexpr bool compare(int j) const { return j == i; } constexpr const S1& identity() const { return *this; } int i; }; struct S2 { constexpr S2(int i_) : i(i_) {} int i; }; { S1 a[] = {1, 2, 3, 4}; S2 b[] = {2, 3}; auto ret = std::ranges::find_first_of(std::begin(a), std::end(a), std::begin(b), std::end(b), &S1::compare, &S1::identity, &S2::i); assert(ret == a + 1); } { S1 a[] = {1, 2, 3, 4}; S2 b[] = {2, 3}; auto ret = std::ranges::find_first_of(a, b, &S1::compare, &S1::identity, &S2::i); assert(ret == a + 1); } } { // check that the complexity requirements are met int a[] = {1, 2, 3, 4}; int b[] = {2, 3}; { int predCount = 0; auto predCounter = [&](int, int) { ++predCount; return false; }; int proj1Count = 0; auto proj1Counter = [&](int i) { ++proj1Count; return i; }; int proj2Count = 0; auto proj2Counter = [&](int i) { ++proj2Count; return i; }; auto ret = std::ranges::find_first_of(std::begin(a), std::end(a), std::begin(b), std::end(b), predCounter, proj1Counter, proj2Counter); assert(ret == a + 4); assert(predCount <= 8); assert(proj1Count <= 8); assert(proj2Count <= 8); } { int predCount = 0; auto predCounter = [&](int, int) { ++predCount; return false; }; int proj1Count = 0; auto proj1Counter = [&](int i) { ++proj1Count; return i; }; int proj2Count = 0; auto proj2Counter = [&](int i) { ++proj2Count; return i; }; auto ret = std::ranges::find_first_of(a, b, predCounter, proj1Counter, proj2Counter); assert(ret == a + 4); assert(predCount == 8); assert(proj1Count == 8); assert(proj2Count == 8); } } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }