1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<input_iterator I1, sentinel_for<I1> S1, forward_iterator I2, sentinel_for<I2> S2,
14 // class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
15 // requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
16 // constexpr I1 ranges::find_first_of(I1 first1, S1 last1, I2 first2, S2 last2,
18 // Proj1 proj1 = {}, Proj2 proj2 = {});
19 // template<input_range R1, forward_range R2,
20 // class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
21 // requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
22 // constexpr borrowed_iterator_t<R1>
23 // ranges::find_first_of(R1&& r1, R2&& r2,
25 // Proj1 proj1 = {}, Proj2 proj2 = {});
32 #include "almost_satisfies_types.h"
33 #include "test_iterators.h"
35 template <class Iter1
, class Iter2
= int*, class Sent1
= Iter1
, class Sent2
= Iter2
>
36 concept HasFindFirstOfIt
= requires(Iter1 iter1
, Sent1 sent1
, Iter2 iter2
, Sent2 sent2
) {
37 std::ranges::find_first_of(iter1
, sent1
, iter2
, sent2
);
40 static_assert(HasFindFirstOfIt
<int*>);
41 static_assert(!HasFindFirstOfIt
<InputIteratorNotDerivedFrom
>);
42 static_assert(!HasFindFirstOfIt
<InputIteratorNotIndirectlyReadable
>);
43 static_assert(!HasFindFirstOfIt
<InputIteratorNotInputOrOutputIterator
>);
44 static_assert(!HasFindFirstOfIt
<int*, ForwardIteratorNotDerivedFrom
>);
45 static_assert(!HasFindFirstOfIt
<int*, ForwardIteratorNotIncrementable
>);
46 static_assert(!HasFindFirstOfIt
<int*, int*, SentinelForNotSemiregular
>);
47 static_assert(!HasFindFirstOfIt
<int*, int*, SentinelForNotWeaklyEqualityComparableWith
>);
48 static_assert(!HasFindFirstOfIt
<int*, int*, int*, SentinelForNotSemiregular
>);
49 static_assert(!HasFindFirstOfIt
<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith
>);
50 static_assert(!HasFindFirstOfIt
<int*, int**>); // not indirectly_comparable
52 template <class Range1
, class Range2
= UncheckedRange
<int*>>
53 concept HasFindFirstOfR
= requires(Range1 range1
, Range2 range2
) {
54 std::ranges::find_first_of(range1
, range2
);
57 static_assert(HasFindFirstOfR
<UncheckedRange
<int*>>);
58 static_assert(!HasFindFirstOfR
<InputRangeNotDerivedFrom
>);
59 static_assert(!HasFindFirstOfR
<InputRangeNotIndirectlyReadable
>);
60 static_assert(!HasFindFirstOfR
<InputRangeNotInputOrOutputIterator
>);
61 static_assert(!HasFindFirstOfR
<UncheckedRange
<int*>, ForwardRangeNotDerivedFrom
>);
62 static_assert(!HasFindFirstOfR
<UncheckedRange
<int*>, ForwardRangeNotIncrementable
>);
63 static_assert(!HasFindFirstOfR
<UncheckedRange
<int*>, InputRangeNotSentinelSemiregular
>);
64 static_assert(!HasFindFirstOfR
<UncheckedRange
<int*>, InputRangeNotSentinelEqualityComparableWith
>);
65 static_assert(!HasFindFirstOfR
<UncheckedRange
<int*>, ForwardRangeNotSentinelSemiregular
>);
66 static_assert(!HasFindFirstOfR
<UncheckedRange
<int*>, ForwardRangeNotSentinelEqualityComparableWith
>);
67 static_assert(!HasFindFirstOfR
<UncheckedRange
<int*>, UncheckedRange
<int**>>); // not indirectly_comparable
69 template <int N1
, int N2
>
71 std::array
<int, N1
> input1
;
72 std::array
<int, N2
> input2
;
73 std::ptrdiff_t expected
;
76 template <class Iter1
, class Sent1
, class Iter2
, class Sent2
, int N1
, int N2
>
77 constexpr void test(Data
<N1
, N2
> d
) {
79 std::same_as
<Iter1
> decltype(auto) ret
=
80 std::ranges::find_first_of(Iter1(d
.input1
.data()), Sent1(Iter1(d
.input1
.data() + d
.input1
.size())),
81 Iter2(d
.input2
.data()), Sent2(Iter2(d
.input2
.data() + d
.input2
.size())));
82 assert(base(ret
) == d
.input1
.data() + d
.expected
);
85 auto range1
= std::ranges::subrange(Iter1(d
.input1
.data()), Sent1(Iter1(d
.input1
.data() + d
.input1
.size())));
86 auto range2
= std::ranges::subrange(Iter2(d
.input2
.data()), Sent2(Iter2(d
.input2
.data() + d
.input2
.size())));
87 std::same_as
<Iter1
> decltype(auto) ret
= std::ranges::find_first_of(range1
, range2
);
88 assert(base(ret
) == d
.input1
.data() + d
.expected
);
92 template <class Iter1
, class Sent1
, class Iter2
, class Sent2
= Iter2
>
93 constexpr void test_iterators() {
95 test
<Iter1
, Sent1
, Iter2
, Sent2
, 4, 2>({.input1
= {1, 2, 3, 4}, .input2
= {2, 3}, .expected
= 1});
96 // other elements from input2 are checked
97 test
<Iter1
, Sent1
, Iter2
, Sent2
, 4, 2>({.input1
= {1, 2, 3, 4}, .input2
= {3, 2}, .expected
= 1});
98 // an empty second range returns last
99 test
<Iter1
, Sent1
, Iter2
, Sent2
, 4, 0>({.input1
= {1, 2, 3, 4}, .input2
= {}, .expected
= 4});
100 // check that an empty first range works
101 test
<Iter1
, Sent1
, Iter2
, Sent2
, 0, 1>({.input1
= {}, .input2
= {1}, .expected
= 0});
102 // check both ranges empty works
103 test
<Iter1
, Sent1
, Iter2
, Sent2
, 0, 0>({.input1
= {}, .input2
= {}, .expected
= 0});
104 // the first element is checked properly
105 test
<Iter1
, Sent1
, Iter2
, Sent2
, 5, 2>({.input1
= {5, 4, 3, 2, 1}, .input2
= {1, 5}, .expected
= 0});
106 // the last element is checked properly
107 test
<Iter1
, Sent1
, Iter2
, Sent2
, 5, 2>({.input1
= {5, 4, 3, 2, 1}, .input2
= {1, 6}, .expected
= 4});
108 // no match, one-past-the-end iterator should be returned
109 test
<Iter1
, Sent1
, Iter2
, Sent2
, 4, 4>({.input1
= {1, 3, 5, 7}, .input2
= {0, 2, 4, 6}, .expected
= 4});
110 // input2 contains a single element
111 test
<Iter1
, Sent1
, Iter2
, Sent2
, 4, 1>({.input1
= {1, 3, 5, 7}, .input2
= {1}, .expected
= 0});
114 template <class Iter1
, class Sent1
= Iter1
>
115 constexpr void test_iterators1() {
116 test_iterators
<Iter1
, Sent1
, forward_iterator
<int*>, sentinel_wrapper
<forward_iterator
<int*>>>();
117 test_iterators
<Iter1
, Sent1
, forward_iterator
<int*>>();
118 test_iterators
<Iter1
, Sent1
, bidirectional_iterator
<int*>>();
119 test_iterators
<Iter1
, Sent1
, random_access_iterator
<int*>>();
120 test_iterators
<Iter1
, Sent1
, contiguous_iterator
<int*>>();
121 test_iterators
<Iter1
, Sent1
, int*>();
124 constexpr bool test() {
125 test_iterators1
<cpp20_input_iterator
<int*>, sentinel_wrapper
<cpp20_input_iterator
<int*>>>();
126 test_iterators1
<cpp17_input_iterator
<int*>, sentinel_wrapper
<cpp17_input_iterator
<int*>>>();
127 test_iterators1
<forward_iterator
<int*>>();
128 test_iterators1
<bidirectional_iterator
<int*>>();
129 test_iterators1
<random_access_iterator
<int*>>();
130 test_iterators1
<contiguous_iterator
<int*>>();
131 test_iterators1
<int*>();
133 { // check that std::ranges::dangling is returned
134 [[maybe_unused
]] std::same_as
<std::ranges::dangling
> decltype(auto) ret
=
135 std::ranges::find_first_of(std::array
{1}, std::array
{1});
138 { // check that the predicate is used
139 int a
[] = {1, 2, 3, 4};
142 auto ret
= std::ranges::find_first_of(std::begin(a
), std::end(a
),
143 std::begin(b
), std::end(b
),
144 std::ranges::greater
{});
145 assert(ret
== a
+ 2);
148 auto ret
= std::ranges::find_first_of(a
, b
, std::ranges::greater
{});
149 assert(ret
== a
+ 2);
153 { // check that the projections are used
154 int a
[] = {1, 2, 3, 4};
157 auto ret
= std::ranges::find_first_of(std::begin(a
), std::end(a
),
158 std::begin(b
), std::end(b
), {},
159 [](int i
) { return i
/ 2; },
160 [](int i
) { return i
- 3; });
161 assert(ret
== a
+ 1);
164 auto ret
= std::ranges::find_first_of(a
, b
, {}, [](int i
) { return i
/ 2; }, [](int i
) { return i
- 3; });
165 assert(ret
== a
+ 1);
169 { // check that std::invoke is used
171 constexpr S1(int i_
) : i(i_
) {}
172 constexpr bool compare(int j
) const { return j
== i
; }
173 constexpr const S1
& identity() const { return *this; }
177 constexpr S2(int i_
) : i(i_
) {}
182 S1 a
[] = {1, 2, 3, 4};
184 auto ret
= std::ranges::find_first_of(std::begin(a
), std::end(a
),
185 std::begin(b
), std::end(b
), &S1::compare
, &S1::identity
, &S2::i
);
186 assert(ret
== a
+ 1);
189 S1 a
[] = {1, 2, 3, 4};
191 auto ret
= std::ranges::find_first_of(a
, b
, &S1::compare
, &S1::identity
, &S2::i
);
192 assert(ret
== a
+ 1);
196 { // check that the complexity requirements are met
197 int a
[] = {1, 2, 3, 4};
201 auto predCounter
= [&](int, int) { ++predCount
; return false; };
203 auto proj1Counter
= [&](int i
) { ++proj1Count
; return i
; };
205 auto proj2Counter
= [&](int i
) { ++proj2Count
; return i
; };
206 auto ret
= std::ranges::find_first_of(std::begin(a
), std::end(a
),
207 std::begin(b
), std::end(b
), predCounter
, proj1Counter
, proj2Counter
);
208 assert(ret
== a
+ 4);
209 assert(predCount
<= 8);
210 assert(proj1Count
<= 8);
211 assert(proj2Count
<= 8);
215 auto predCounter
= [&](int, int) { ++predCount
; return false; };
217 auto proj1Counter
= [&](int i
) { ++proj1Count
; return i
; };
219 auto proj2Counter
= [&](int i
) { ++proj2Count
; return i
; };
220 auto ret
= std::ranges::find_first_of(a
, b
, predCounter
, proj1Counter
, proj2Counter
);
221 assert(ret
== a
+ 4);
222 assert(predCount
== 8);
223 assert(proj1Count
== 8);
224 assert(proj2Count
== 8);
231 int main(int, char**) {
233 static_assert(test());