//===----------------------------------------------------------------------===// // // 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 // ADDITIONAL_COMPILE_FLAGS: -Wno-sign-compare // template S, class T, class Proj = identity> // requires indirect_binary_predicate, const T*> // constexpr I ranges::find(I first, S last, const T& value, Proj proj = {}); // template // requires indirect_binary_predicate, Proj>, const T*> // constexpr borrowed_iterator_t // ranges::find(R&& r, const T& value, Proj proj = {}); #include #include #include #include #include #include "almost_satisfies_types.h" #include "test_iterators.h" struct NotEqualityComparable {}; template concept HasFindIt = requires(It it, Sent sent) { std::ranges::find(it, sent, *it); }; static_assert(HasFindIt); static_assert(!HasFindIt); static_assert(!HasFindIt); static_assert(!HasFindIt); static_assert(!HasFindIt); static_assert(!HasFindIt, SentinelForNotSemiregular>); static_assert(!HasFindIt, InputRangeNotSentinelEqualityComparableWith>); static_assert(!HasFindIt); static_assert(!HasFindIt); template concept HasFindR = requires(Range r) { std::ranges::find(r, ValT{}); }; static_assert(HasFindR, int>); static_assert(!HasFindR); static_assert(!HasFindR, NotEqualityComparable>); static_assert(!HasFindR); static_assert(!HasFindR); static_assert(!HasFindR); static_assert(!HasFindR); static_assert(!HasFindR); static std::vector comparable_data; template constexpr void test_iterators() { using ValueT = std::iter_value_t; { // simple test { ValueT a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::find(It(a), Sent(It(a + 4)), 4); assert(base(ret) == a + 3); assert(*ret == 4); } { ValueT a[] = {1, 2, 3, 4}; auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as auto ret = std::ranges::find(range, 4); assert(base(ret) == a + 3); assert(*ret == 4); } } { // check that an empty range works { std::array a = {}; auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1); assert(base(ret) == a.data()); } { std::array a = {}; auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data()))); auto ret = std::ranges::find(range, 1); assert(base(ret) == a.data()); } } { // check that last is returned with no match { ValueT a[] = {1, 1, 1}; auto ret = std::ranges::find(a, a + 3, 0); assert(ret == a + 3); } { ValueT a[] = {1, 1, 1}; auto ret = std::ranges::find(a, 0); assert(ret == a + 3); } } if (!std::is_constant_evaluated()) comparable_data.clear(); } template class TriviallyComparable { ElementT el_; public: TEST_CONSTEXPR TriviallyComparable(ElementT el) : el_(el) {} bool operator==(const TriviallyComparable&) const = default; }; constexpr bool test() { types::for_each(types::type_list, TriviallyComparable>{}, [] { types::for_each(types::cpp20_input_iterator_list{}, [] { if constexpr (std::forward_iterator) test_iterators(); test_iterators>(); test_iterators>(); }); }); { // check that the first element is returned { struct S { int comp; int other; }; S a[] = { {0, 0}, {0, 2}, {0, 1} }; auto ret = std::ranges::find(a, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); assert(ret->other == 0); } { struct S { int comp; int other; }; S a[] = { {0, 0}, {0, 2}, {0, 1} }; auto ret = std::ranges::find(a, a + 3, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); assert(ret->other == 0); } } { // check that an iterator is returned with a borrowing range int a[] = {1, 2, 3, 4}; std::same_as auto ret = std::ranges::find(std::views::all(a), 1); assert(ret == a); assert(*ret == 1); } { // count invocations of the projection { int a[] = {1, 2, 3, 4}; int projection_count = 0; auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } { int a[] = {1, 2, 3, 4}; int projection_count = 0; auto ret = std::ranges::find(a, 2, [&](int i) { ++projection_count; return i; }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } } return true; } template class Comparable { IndexT index_; public: Comparable(IndexT i) : index_([&]() { IndexT size = static_cast(comparable_data.size()); comparable_data.push_back(i); return size; }()) {} bool operator==(const Comparable& other) const { return comparable_data[other.index_] == comparable_data[index_]; } friend bool operator==(const Comparable& lhs, long long rhs) { return comparable_data[lhs.index_] == rhs; } }; int main(int, char**) { test(); static_assert(test()); types::for_each(types::cpp20_input_iterator_list*>{}, [] { if constexpr (std::forward_iterator) test_iterators(); test_iterators>(); test_iterators>(); }); types::for_each(types::cpp20_input_iterator_list*>{}, [] { if constexpr (std::forward_iterator) test_iterators(); test_iterators>(); test_iterators>(); }); return 0; }