1 | //===----------------------------------------------------------------------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // <algorithm> |
10 | |
11 | // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 |
12 | |
13 | // template<input_iterator I1, sentinel_for<I1> S1, input_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 bool ranges::ends_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, |
17 | // Proj1 proj1 = {}, Proj2 proj2 = {}); |
18 | // template<input_range R1, input_range R2, class Pred = ranges::equal_to, class Proj1 = identity, |
19 | // class Proj2 = identity> |
20 | // requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> |
21 | // constexpr bool ranges::ends_with(R1&& r1, R2&& r2, Pred pred = {}, |
22 | // Proj1 proj1 = {}, Proj2 proj2 = {}); |
23 | |
24 | #include <algorithm> |
25 | #include <array> |
26 | #include <chrono> |
27 | #include <ranges> |
28 | #include "almost_satisfies_types.h" |
29 | #include "test_iterators.h" |
30 | |
31 | using namespace std::chrono; |
32 | |
33 | template <class Iter1, class Sent1 = Iter1, class Iter2 = int*, class Sent2 = Iter2> |
34 | concept HasEndsWithIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { |
35 | std::ranges::ends_with(first1, last1, first2, last2); |
36 | }; |
37 | |
38 | static_assert(HasEndsWithIt<int*>); |
39 | static_assert(!HasEndsWithIt<ForwardIteratorNotDerivedFrom>); |
40 | static_assert(!HasEndsWithIt<ForwardIteratorNotIncrementable>); |
41 | static_assert(HasEndsWithIt<int*, int*>); |
42 | static_assert(!HasEndsWithIt<int*, SentinelForNotSemiregular>); |
43 | static_assert(!HasEndsWithIt<int*, int*, int**>); // not indirectly comparable |
44 | static_assert(!HasEndsWithIt<int*, SentinelForNotWeaklyEqualityComparableWith>); |
45 | static_assert(!HasEndsWithIt<int*, int*, ForwardIteratorNotDerivedFrom>); |
46 | static_assert(!HasEndsWithIt<int*, int*, ForwardIteratorNotIncrementable>); |
47 | static_assert(!HasEndsWithIt<int*, int*, int*, SentinelForNotSemiregular>); |
48 | static_assert(!HasEndsWithIt<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith>); |
49 | |
50 | template <class Range1, class Range2 = UncheckedRange<int*>> |
51 | concept HasEndsWithR = requires(Range1&& range1, Range2&& range2) { |
52 | std::ranges::ends_with(std::forward<Range1>(range1), std::forward<Range2>(range2)); |
53 | }; |
54 | |
55 | static_assert(HasEndsWithR<UncheckedRange<int*>>); |
56 | static_assert(!HasEndsWithR<ForwardRangeNotDerivedFrom>); |
57 | static_assert(!HasEndsWithR<ForwardIteratorNotIncrementable>); |
58 | static_assert(!HasEndsWithR<ForwardRangeNotSentinelSemiregular>); |
59 | static_assert(!HasEndsWithR<ForwardRangeNotSentinelEqualityComparableWith>); |
60 | static_assert(HasEndsWithR<UncheckedRange<int*>, UncheckedRange<int*>>); |
61 | static_assert(!HasEndsWithR<UncheckedRange<int*>, UncheckedRange<int**>>); // not indirectly comparable |
62 | static_assert(!HasEndsWithR<UncheckedRange<int*>, ForwardRangeNotDerivedFrom>); |
63 | static_assert(!HasEndsWithR<UncheckedRange<int*>, ForwardRangeNotSentinelSemiregular>); |
64 | |
65 | template <class Iter1, class Sent1 = Iter1, class Iter2, class Sent2 = Iter2> |
66 | constexpr void test_iterators() { |
67 | { // simple tests |
68 | int a[] = {1, 2, 3, 4, 5, 6}; |
69 | int p[] = {4, 5, 6}; |
70 | { |
71 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
72 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); |
73 | [[maybe_unused]] std::same_as<bool> decltype(auto) ret = |
74 | std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
75 | assert(ret); |
76 | } |
77 | { |
78 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
79 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); |
80 | [[maybe_unused]] std::same_as<bool> decltype(auto) ret = std::ranges::ends_with(whole, suffix); |
81 | assert(ret); |
82 | } |
83 | } |
84 | |
85 | { // suffix doesn't match |
86 | int a[] = {1, 2, 3, 4, 5, 6}; |
87 | int p[] = {1, 2, 3}; |
88 | { |
89 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
90 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); |
91 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
92 | assert(!ret); |
93 | } |
94 | { |
95 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
96 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); |
97 | bool ret = std::ranges::ends_with(whole, suffix); |
98 | assert(!ret); |
99 | } |
100 | } |
101 | |
102 | { // range consists of just one element |
103 | int a[] = {1}; |
104 | int p[] = {1}; |
105 | { |
106 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); |
107 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); |
108 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
109 | assert(ret); |
110 | } |
111 | { |
112 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); |
113 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); |
114 | bool ret = std::ranges::ends_with(whole, suffix); |
115 | assert(ret); |
116 | } |
117 | } |
118 | |
119 | { // suffix consists of just one element |
120 | int a[] = {5, 1, 2, 4, 3}; |
121 | int p[] = {3}; |
122 | { |
123 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); |
124 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); |
125 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
126 | assert(ret); |
127 | } |
128 | { |
129 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); |
130 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); |
131 | bool ret = std::ranges::ends_with(whole, suffix); |
132 | assert(ret); |
133 | } |
134 | } |
135 | |
136 | { // range and suffix are identical |
137 | int a[] = {1, 2, 3, 4, 5, 6}; |
138 | int p[] = {1, 2, 3, 4, 5, 6}; |
139 | { |
140 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
141 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6))); |
142 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
143 | assert(ret); |
144 | } |
145 | { |
146 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
147 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6))); |
148 | bool ret = std::ranges::ends_with(whole, suffix); |
149 | assert(ret); |
150 | } |
151 | } |
152 | |
153 | { // suffix is longer than range |
154 | int a[] = {3, 4, 5, 6, 7, 8}; |
155 | int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; |
156 | { |
157 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
158 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); |
159 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
160 | assert(!ret); |
161 | } |
162 | { |
163 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
164 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); |
165 | bool ret = std::ranges::ends_with(whole, suffix); |
166 | assert(!ret); |
167 | } |
168 | } |
169 | |
170 | { // suffix has zero length |
171 | int a[] = {1, 2, 3, 4, 5, 6}; |
172 | std::array<int, 0> p = {}; |
173 | { |
174 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
175 | auto suffix = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data()))); |
176 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
177 | assert(ret); |
178 | } |
179 | { |
180 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
181 | auto suffix = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data()))); |
182 | bool ret = std::ranges::ends_with(whole, suffix); |
183 | assert(ret); |
184 | } |
185 | } |
186 | |
187 | { // range has zero length |
188 | std::array<int, 0> a = {}; |
189 | int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; |
190 | { |
191 | auto whole = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); |
192 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); |
193 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
194 | assert(!ret); |
195 | } |
196 | { |
197 | auto whole = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); |
198 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); |
199 | bool ret = std::ranges::ends_with(whole, suffix); |
200 | assert(!ret); |
201 | } |
202 | } |
203 | |
204 | { // subarray |
205 | int a[] = {0, 3, 5, 10, 7, 3, 5, 89, 3, 5, 2, 1, 8, 6}; |
206 | int p[] = {3, 5}; |
207 | { |
208 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 13))); |
209 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); |
210 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
211 | assert(!ret); |
212 | } |
213 | { |
214 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 13))); |
215 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); |
216 | bool ret = std::ranges::ends_with(whole, suffix); |
217 | assert(!ret); |
218 | } |
219 | } |
220 | |
221 | { // repeated suffix |
222 | int a[] = {8, 6, 3, 5, 1, 2}; |
223 | int p[] = {1, 2, 1, 2}; |
224 | { |
225 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
226 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 4))); |
227 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); |
228 | assert(!ret); |
229 | } |
230 | { |
231 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
232 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 4))); |
233 | bool ret = std::ranges::ends_with(whole, suffix); |
234 | assert(!ret); |
235 | } |
236 | } |
237 | |
238 | { // check that the predicate is used |
239 | int a[] = {5, 1, 3, 2, 7}; |
240 | int p[] = {-2, -7}; |
241 | auto pred = [](int l, int r) { return l * -1 == r; }; |
242 | { |
243 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); |
244 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); |
245 | bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end(), pred); |
246 | assert(ret); |
247 | } |
248 | { |
249 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); |
250 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); |
251 | bool ret = std::ranges::ends_with(whole, suffix, pred); |
252 | assert(ret); |
253 | } |
254 | } |
255 | |
256 | { // check that the projections are used |
257 | int a[] = {1, 3, 15, 1, 2, 1}; |
258 | int p[] = {2, 1, 2}; |
259 | { |
260 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
261 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); |
262 | bool ret = std::ranges::ends_with( |
263 | whole.begin(), |
264 | whole.end(), |
265 | suffix.begin(), |
266 | suffix.end(), |
267 | {}, |
268 | [](int i) { return i - 3; }, |
269 | [](int i) { return i * -1; }); |
270 | assert(ret); |
271 | } |
272 | { |
273 | auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); |
274 | auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); |
275 | bool ret = std::ranges::ends_with(whole, suffix, {}, [](int i) { return i - 3; }, [](int i) { return i * -1; }); |
276 | assert(ret); |
277 | } |
278 | } |
279 | } |
280 | |
281 | constexpr bool test() { |
282 | // This is to test (forward_iterator<_Iter1> || sized_sentinel_for<_Sent1, _Iter1>) condition. |
283 | types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iter2>() { |
284 | types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iter1>() { |
285 | if constexpr (std::forward_iterator<Iter1> && std::forward_iterator<Iter2>) |
286 | test_iterators<Iter1, Iter1, Iter2, Iter2>(); |
287 | if constexpr (std::forward_iterator<Iter2>) |
288 | test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, Iter2>(); |
289 | if constexpr (std::forward_iterator<Iter1>) |
290 | test_iterators<Iter1, Iter1, Iter2, sized_sentinel<Iter2>>(); |
291 | test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, sized_sentinel<Iter2>>(); |
292 | }); |
293 | }); |
294 | |
295 | return true; |
296 | } |
297 | |
298 | int main(int, char**) { |
299 | test(); |
300 | static_assert(test()); |
301 | |
302 | return 0; |
303 | } |
304 | |