1ee0f8c40SNikolas Klauser //===----------------------------------------------------------------------===//
2ee0f8c40SNikolas Klauser //
3ee0f8c40SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ee0f8c40SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
5ee0f8c40SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ee0f8c40SNikolas Klauser //
7ee0f8c40SNikolas Klauser //===----------------------------------------------------------------------===//
8ee0f8c40SNikolas Klauser
9ee0f8c40SNikolas Klauser // <algorithm>
10ee0f8c40SNikolas Klauser
11ee0f8c40SNikolas Klauser // UNSUPPORTED: c++03, c++11, c++14, c++17
12ee0f8c40SNikolas Klauser
1364addd65SStephan T. Lavavej // ADDITIONAL_COMPILE_FLAGS(gcc-style-warnings): -Wno-sign-compare
1464addd65SStephan T. Lavavej // MSVC warning C4242: 'argument': conversion from 'const _Ty' to 'ElementT', possible loss of data
1564addd65SStephan T. Lavavej // MSVC warning C4244: 'argument': conversion from 'const _Ty' to 'ElementT', possible loss of data
1664addd65SStephan T. Lavavej // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4242 /wd4244
171fd08eddSNikolas Klauser
18ee0f8c40SNikolas Klauser // template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
19ee0f8c40SNikolas Klauser // requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
20ee0f8c40SNikolas Klauser // constexpr I ranges::find(I first, S last, const T& value, Proj proj = {});
21ee0f8c40SNikolas Klauser // template<input_range R, class T, class Proj = identity>
22ee0f8c40SNikolas Klauser // requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
23ee0f8c40SNikolas Klauser // constexpr borrowed_iterator_t<R>
24ee0f8c40SNikolas Klauser // ranges::find(R&& r, const T& value, Proj proj = {});
25ee0f8c40SNikolas Klauser
26ee0f8c40SNikolas Klauser #include <algorithm>
27ee0f8c40SNikolas Klauser #include <array>
28ee0f8c40SNikolas Klauser #include <cassert>
29*f7407411SNikolas Klauser #include <deque>
30ee0f8c40SNikolas Klauser #include <ranges>
311fd08eddSNikolas Klauser #include <vector>
32ee0f8c40SNikolas Klauser
33ee0f8c40SNikolas Klauser #include "almost_satisfies_types.h"
34ee0f8c40SNikolas Klauser #include "test_iterators.h"
35ee0f8c40SNikolas Klauser
36ee0f8c40SNikolas Klauser struct NotEqualityComparable {};
37ee0f8c40SNikolas Klauser
38ee0f8c40SNikolas Klauser template <class It, class Sent = It>
39ee0f8c40SNikolas Klauser concept HasFindIt = requires(It it, Sent sent) { std::ranges::find(it, sent, *it); };
40ee0f8c40SNikolas Klauser static_assert(HasFindIt<int*>);
41ee0f8c40SNikolas Klauser static_assert(!HasFindIt<NotEqualityComparable*>);
42ee0f8c40SNikolas Klauser static_assert(!HasFindIt<InputIteratorNotDerivedFrom>);
43ee0f8c40SNikolas Klauser static_assert(!HasFindIt<InputIteratorNotIndirectlyReadable>);
44ee0f8c40SNikolas Klauser static_assert(!HasFindIt<InputIteratorNotInputOrOutputIterator>);
45ee0f8c40SNikolas Klauser static_assert(!HasFindIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);
46ee0f8c40SNikolas Klauser static_assert(!HasFindIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);
47ee0f8c40SNikolas Klauser
48ee0f8c40SNikolas Klauser static_assert(!HasFindIt<int*, int>);
49ee0f8c40SNikolas Klauser static_assert(!HasFindIt<int, int*>);
50ee0f8c40SNikolas Klauser
51ee0f8c40SNikolas Klauser template <class Range, class ValT>
52ee0f8c40SNikolas Klauser concept HasFindR = requires(Range r) { std::ranges::find(r, ValT{}); };
53ee0f8c40SNikolas Klauser static_assert(HasFindR<std::array<int, 1>, int>);
54ee0f8c40SNikolas Klauser static_assert(!HasFindR<int, int>);
55ee0f8c40SNikolas Klauser static_assert(!HasFindR<std::array<NotEqualityComparable, 1>, NotEqualityComparable>);
56ee0f8c40SNikolas Klauser static_assert(!HasFindR<InputRangeNotDerivedFrom, int>);
57ee0f8c40SNikolas Klauser static_assert(!HasFindR<InputRangeNotIndirectlyReadable, int>);
58ee0f8c40SNikolas Klauser static_assert(!HasFindR<InputRangeNotInputOrOutputIterator, int>);
59ee0f8c40SNikolas Klauser static_assert(!HasFindR<InputRangeNotSentinelSemiregular, int>);
60ee0f8c40SNikolas Klauser static_assert(!HasFindR<InputRangeNotSentinelEqualityComparableWith, int>);
61ee0f8c40SNikolas Klauser
621fd08eddSNikolas Klauser static std::vector<int> comparable_data;
631fd08eddSNikolas Klauser
64ee0f8c40SNikolas Klauser template <class It, class Sent = It>
test_iterators()65ee0f8c40SNikolas Klauser constexpr void test_iterators() {
661fd08eddSNikolas Klauser using ValueT = std::iter_value_t<It>;
671fd08eddSNikolas Klauser { // simple test
68ee0f8c40SNikolas Klauser {
691fd08eddSNikolas Klauser ValueT a[] = {1, 2, 3, 4};
70ee0f8c40SNikolas Klauser std::same_as<It> auto ret = std::ranges::find(It(a), Sent(It(a + 4)), 4);
71ee0f8c40SNikolas Klauser assert(base(ret) == a + 3);
72ee0f8c40SNikolas Klauser assert(*ret == 4);
73ee0f8c40SNikolas Klauser }
74ee0f8c40SNikolas Klauser {
751fd08eddSNikolas Klauser ValueT a[] = {1, 2, 3, 4};
76ee0f8c40SNikolas Klauser auto range = std::ranges::subrange(It(a), Sent(It(a + 4)));
77ee0f8c40SNikolas Klauser std::same_as<It> auto ret = std::ranges::find(range, 4);
78ee0f8c40SNikolas Klauser assert(base(ret) == a + 3);
79ee0f8c40SNikolas Klauser assert(*ret == 4);
80ee0f8c40SNikolas Klauser }
81ee0f8c40SNikolas Klauser }
82ee0f8c40SNikolas Klauser
831fd08eddSNikolas Klauser { // check that an empty range works
841fd08eddSNikolas Klauser {
851fd08eddSNikolas Klauser std::array<ValueT, 0> a = {};
861fd08eddSNikolas Klauser auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1);
871fd08eddSNikolas Klauser assert(base(ret) == a.data());
881fd08eddSNikolas Klauser }
891fd08eddSNikolas Klauser {
901fd08eddSNikolas Klauser std::array<ValueT, 0> a = {};
911fd08eddSNikolas Klauser auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data())));
921fd08eddSNikolas Klauser auto ret = std::ranges::find(range, 1);
931fd08eddSNikolas Klauser assert(base(ret) == a.data());
941fd08eddSNikolas Klauser }
951fd08eddSNikolas Klauser }
96ee0f8c40SNikolas Klauser
971fd08eddSNikolas Klauser { // check that last is returned with no match
98ee0f8c40SNikolas Klauser {
991fd08eddSNikolas Klauser ValueT a[] = {1, 1, 1};
1001fd08eddSNikolas Klauser auto ret = std::ranges::find(a, a + 3, 0);
101ee0f8c40SNikolas Klauser assert(ret == a + 3);
102ee0f8c40SNikolas Klauser }
103ee0f8c40SNikolas Klauser {
1041fd08eddSNikolas Klauser ValueT a[] = {1, 1, 1};
1051fd08eddSNikolas Klauser auto ret = std::ranges::find(a, 0);
106ee0f8c40SNikolas Klauser assert(ret == a + 3);
107ee0f8c40SNikolas Klauser }
108ee0f8c40SNikolas Klauser }
109ee0f8c40SNikolas Klauser
1101fd08eddSNikolas Klauser if (!std::is_constant_evaluated())
1111fd08eddSNikolas Klauser comparable_data.clear();
1121fd08eddSNikolas Klauser }
1131fd08eddSNikolas Klauser
1141fd08eddSNikolas Klauser template <class ElementT>
1151fd08eddSNikolas Klauser class TriviallyComparable {
1161fd08eddSNikolas Klauser ElementT el_;
1171fd08eddSNikolas Klauser
1181fd08eddSNikolas Klauser public:
TriviallyComparable(ElementT el)1191fd08eddSNikolas Klauser TEST_CONSTEXPR TriviallyComparable(ElementT el) : el_(el) {}
1201fd08eddSNikolas Klauser bool operator==(const TriviallyComparable&) const = default;
1211fd08eddSNikolas Klauser };
1221fd08eddSNikolas Klauser
test()1231fd08eddSNikolas Klauser constexpr bool test() {
1241fd08eddSNikolas Klauser types::for_each(types::type_list<char, wchar_t, int, long, TriviallyComparable<char>, TriviallyComparable<wchar_t>>{},
1251fd08eddSNikolas Klauser []<class T> {
1261fd08eddSNikolas Klauser types::for_each(types::cpp20_input_iterator_list<T*>{}, []<class Iter> {
1271fd08eddSNikolas Klauser if constexpr (std::forward_iterator<Iter>)
1281fd08eddSNikolas Klauser test_iterators<Iter>();
1291fd08eddSNikolas Klauser test_iterators<Iter, sentinel_wrapper<Iter>>();
1301fd08eddSNikolas Klauser test_iterators<Iter, sized_sentinel<Iter>>();
1311fd08eddSNikolas Klauser });
1321fd08eddSNikolas Klauser });
1331fd08eddSNikolas Klauser
134*f7407411SNikolas Klauser // TODO: Remove the `_LIBCPP_ENABLE_EXPERIMENTAL` check once we have the FTM guarded or views::join isn't
135*f7407411SNikolas Klauser // experimental anymore
136*f7407411SNikolas Klauser #if TEST_STD_VER >= 20 && (!defined(_LIBCPP_VERSION) || defined(_LIBCPP_ENABLE_EXPERIMENTAL))
137*f7407411SNikolas Klauser {
138*f7407411SNikolas Klauser std::vector<std::vector<int>> vec = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
139*f7407411SNikolas Klauser auto view = vec | std::views::join;
140*f7407411SNikolas Klauser assert(std::ranges::find(view.begin(), view.end(), 4) == std::next(view.begin(), 3));
141*f7407411SNikolas Klauser assert(std::ranges::find(view, 4) == std::next(view.begin(), 3));
142*f7407411SNikolas Klauser }
143*f7407411SNikolas Klauser #endif
144*f7407411SNikolas Klauser
145ee0f8c40SNikolas Klauser { // check that the first element is returned
146ee0f8c40SNikolas Klauser {
147ee0f8c40SNikolas Klauser struct S {
148ee0f8c40SNikolas Klauser int comp;
149ee0f8c40SNikolas Klauser int other;
150ee0f8c40SNikolas Klauser };
151ee0f8c40SNikolas Klauser S a[] = { {0, 0}, {0, 2}, {0, 1} };
152ee0f8c40SNikolas Klauser auto ret = std::ranges::find(a, 0, &S::comp);
153ee0f8c40SNikolas Klauser assert(ret == a);
154ee0f8c40SNikolas Klauser assert(ret->comp == 0);
155ee0f8c40SNikolas Klauser assert(ret->other == 0);
156ee0f8c40SNikolas Klauser }
157ee0f8c40SNikolas Klauser {
158ee0f8c40SNikolas Klauser struct S {
159ee0f8c40SNikolas Klauser int comp;
160ee0f8c40SNikolas Klauser int other;
161ee0f8c40SNikolas Klauser };
162ee0f8c40SNikolas Klauser S a[] = { {0, 0}, {0, 2}, {0, 1} };
163ee0f8c40SNikolas Klauser auto ret = std::ranges::find(a, a + 3, 0, &S::comp);
164ee0f8c40SNikolas Klauser assert(ret == a);
165ee0f8c40SNikolas Klauser assert(ret->comp == 0);
166ee0f8c40SNikolas Klauser assert(ret->other == 0);
167ee0f8c40SNikolas Klauser }
168ee0f8c40SNikolas Klauser }
169ee0f8c40SNikolas Klauser
170ee0f8c40SNikolas Klauser {
171ee0f8c40SNikolas Klauser // check that an iterator is returned with a borrowing range
172ee0f8c40SNikolas Klauser int a[] = {1, 2, 3, 4};
173ee0f8c40SNikolas Klauser std::same_as<int*> auto ret = std::ranges::find(std::views::all(a), 1);
174ee0f8c40SNikolas Klauser assert(ret == a);
175ee0f8c40SNikolas Klauser assert(*ret == 1);
176ee0f8c40SNikolas Klauser }
177ee0f8c40SNikolas Klauser
178ee0f8c40SNikolas Klauser {
179ee0f8c40SNikolas Klauser // count invocations of the projection
180ee0f8c40SNikolas Klauser {
181ee0f8c40SNikolas Klauser int a[] = {1, 2, 3, 4};
182ee0f8c40SNikolas Klauser int projection_count = 0;
183ee0f8c40SNikolas Klauser auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { ++projection_count; return i; });
184ee0f8c40SNikolas Klauser assert(ret == a + 1);
185ee0f8c40SNikolas Klauser assert(*ret == 2);
186ee0f8c40SNikolas Klauser assert(projection_count == 2);
187ee0f8c40SNikolas Klauser }
188ee0f8c40SNikolas Klauser {
189ee0f8c40SNikolas Klauser int a[] = {1, 2, 3, 4};
190ee0f8c40SNikolas Klauser int projection_count = 0;
191ee0f8c40SNikolas Klauser auto ret = std::ranges::find(a, 2, [&](int i) { ++projection_count; return i; });
192ee0f8c40SNikolas Klauser assert(ret == a + 1);
193ee0f8c40SNikolas Klauser assert(*ret == 2);
194ee0f8c40SNikolas Klauser assert(projection_count == 2);
195ee0f8c40SNikolas Klauser }
196ee0f8c40SNikolas Klauser }
197ee0f8c40SNikolas Klauser
198ee0f8c40SNikolas Klauser return true;
199ee0f8c40SNikolas Klauser }
200ee0f8c40SNikolas Klauser
2011fd08eddSNikolas Klauser template <class IndexT>
2021fd08eddSNikolas Klauser class Comparable {
2031fd08eddSNikolas Klauser IndexT index_;
2041fd08eddSNikolas Klauser
2051fd08eddSNikolas Klauser public:
Comparable(IndexT i)2061fd08eddSNikolas Klauser Comparable(IndexT i)
2071fd08eddSNikolas Klauser : index_([&]() {
2081fd08eddSNikolas Klauser IndexT size = static_cast<IndexT>(comparable_data.size());
2091fd08eddSNikolas Klauser comparable_data.push_back(i);
2101fd08eddSNikolas Klauser return size;
2111fd08eddSNikolas Klauser }()) {}
2121fd08eddSNikolas Klauser
operator ==(const Comparable & other) const2131fd08eddSNikolas Klauser bool operator==(const Comparable& other) const {
2141fd08eddSNikolas Klauser return comparable_data[other.index_] == comparable_data[index_];
2151fd08eddSNikolas Klauser }
2161fd08eddSNikolas Klauser
operator ==(const Comparable & lhs,long long rhs)2171fd08eddSNikolas Klauser friend bool operator==(const Comparable& lhs, long long rhs) { return comparable_data[lhs.index_] == rhs; }
2181fd08eddSNikolas Klauser };
2191fd08eddSNikolas Klauser
test_deque()220*f7407411SNikolas Klauser void test_deque() {
221*f7407411SNikolas Klauser { // empty deque
222*f7407411SNikolas Klauser std::deque<int> data;
223*f7407411SNikolas Klauser assert(std::ranges::find(data, 4) == data.end());
224*f7407411SNikolas Klauser assert(std::ranges::find(data.begin(), data.end(), 4) == data.end());
225*f7407411SNikolas Klauser }
226*f7407411SNikolas Klauser
227*f7407411SNikolas Klauser { // single element - match
228*f7407411SNikolas Klauser std::deque<int> data = {4};
229*f7407411SNikolas Klauser assert(std::ranges::find(data, 4) == data.begin());
230*f7407411SNikolas Klauser assert(std::ranges::find(data.begin(), data.end(), 4) == data.begin());
231*f7407411SNikolas Klauser }
232*f7407411SNikolas Klauser
233*f7407411SNikolas Klauser { // single element - no match
234*f7407411SNikolas Klauser std::deque<int> data = {3};
235*f7407411SNikolas Klauser assert(std::ranges::find(data, 4) == data.end());
236*f7407411SNikolas Klauser assert(std::ranges::find(data.begin(), data.end(), 4) == data.end());
237*f7407411SNikolas Klauser }
238*f7407411SNikolas Klauser
239*f7407411SNikolas Klauser // many elements
240*f7407411SNikolas Klauser for (auto size : {2, 3, 1023, 1024, 1025, 2047, 2048, 2049}) {
241*f7407411SNikolas Klauser { // last element match
242*f7407411SNikolas Klauser std::deque<int> data;
243*f7407411SNikolas Klauser data.resize(size);
244*f7407411SNikolas Klauser std::fill(data.begin(), data.end(), 3);
245*f7407411SNikolas Klauser data[size - 1] = 4;
246*f7407411SNikolas Klauser assert(std::ranges::find(data, 4) == data.end() - 1);
247*f7407411SNikolas Klauser assert(std::ranges::find(data.begin(), data.end(), 4) == data.end() - 1);
248*f7407411SNikolas Klauser }
249*f7407411SNikolas Klauser
250*f7407411SNikolas Klauser { // second-last element match
251*f7407411SNikolas Klauser std::deque<int> data;
252*f7407411SNikolas Klauser data.resize(size);
253*f7407411SNikolas Klauser std::fill(data.begin(), data.end(), 3);
254*f7407411SNikolas Klauser data[size - 2] = 4;
255*f7407411SNikolas Klauser assert(std::ranges::find(data, 4) == data.end() - 2);
256*f7407411SNikolas Klauser assert(std::ranges::find(data.begin(), data.end(), 4) == data.end() - 2);
257*f7407411SNikolas Klauser }
258*f7407411SNikolas Klauser
259*f7407411SNikolas Klauser { // no match
260*f7407411SNikolas Klauser std::deque<int> data;
261*f7407411SNikolas Klauser data.resize(size);
262*f7407411SNikolas Klauser std::fill(data.begin(), data.end(), 3);
263*f7407411SNikolas Klauser assert(std::ranges::find(data, 4) == data.end());
264*f7407411SNikolas Klauser assert(std::ranges::find(data.begin(), data.end(), 4) == data.end());
265*f7407411SNikolas Klauser }
266*f7407411SNikolas Klauser }
267*f7407411SNikolas Klauser }
268*f7407411SNikolas Klauser
main(int,char **)269ee0f8c40SNikolas Klauser int main(int, char**) {
270*f7407411SNikolas Klauser test_deque();
271ee0f8c40SNikolas Klauser test();
272ee0f8c40SNikolas Klauser static_assert(test());
273ee0f8c40SNikolas Klauser
2741fd08eddSNikolas Klauser types::for_each(types::cpp20_input_iterator_list<Comparable<char>*>{}, []<class Iter> {
2751fd08eddSNikolas Klauser if constexpr (std::forward_iterator<Iter>)
2761fd08eddSNikolas Klauser test_iterators<Iter>();
2771fd08eddSNikolas Klauser test_iterators<Iter, sentinel_wrapper<Iter>>();
2781fd08eddSNikolas Klauser test_iterators<Iter, sized_sentinel<Iter>>();
2791fd08eddSNikolas Klauser });
2801fd08eddSNikolas Klauser
2811fd08eddSNikolas Klauser types::for_each(types::cpp20_input_iterator_list<Comparable<wchar_t>*>{}, []<class Iter> {
2821fd08eddSNikolas Klauser if constexpr (std::forward_iterator<Iter>)
2831fd08eddSNikolas Klauser test_iterators<Iter>();
2841fd08eddSNikolas Klauser test_iterators<Iter, sentinel_wrapper<Iter>>();
2851fd08eddSNikolas Klauser test_iterators<Iter, sized_sentinel<Iter>>();
2861fd08eddSNikolas Klauser });
2871fd08eddSNikolas Klauser
288ee0f8c40SNikolas Klauser return 0;
289ee0f8c40SNikolas Klauser }
290