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, c++20
12 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000
14 // template<forward_iterator I1, sentinel_for<I1> S1,
15 // forward_iterator I2, sentinel_for<I2> S2, class Proj = identity>
16 // requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
17 // constexpr bool ranges::contains_subrange(I1 first1, S1 last1, I2 first2, S2 last2,
18 // Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++23
20 // template<forward_range R1, forward_range R2,
21 // class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
22 // requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
23 // constexpr bool ranges::contains_subrange(R1&& r1, R2&& r2, Pred pred = {},
24 // Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++23
33 #include "almost_satisfies_types.h"
34 #include "test_iterators.h"
36 struct NotEqualityComparable
{};
38 template <class Iter1
, class Sent1
= Iter1
, class Iter2
= int*, class Sent2
= Iter2
>
39 concept HasContainsSubrangeIt
= requires(Iter1 first1
, Sent1 last1
, Iter2 first2
, Sent2 last2
) {
40 std::ranges::contains_subrange(first1
, last1
, first2
, last2
);
43 static_assert(HasContainsSubrangeIt
<int*>);
44 static_assert(!HasContainsSubrangeIt
<ForwardIteratorNotDerivedFrom
>);
45 static_assert(!HasContainsSubrangeIt
<ForwardIteratorNotIncrementable
>);
46 static_assert(!HasContainsSubrangeIt
<int*, SentinelForNotSemiregular
>);
47 static_assert(!HasContainsSubrangeIt
<int*, int*, int**>); // not indirectly comparable
48 static_assert(!HasContainsSubrangeIt
<int*, SentinelForNotWeaklyEqualityComparableWith
>);
49 static_assert(!HasContainsSubrangeIt
<int*, int*, ForwardIteratorNotDerivedFrom
>);
50 static_assert(!HasContainsSubrangeIt
<int*, int*, ForwardIteratorNotIncrementable
>);
51 static_assert(!HasContainsSubrangeIt
<int*, int*, int*, SentinelForNotSemiregular
>);
52 static_assert(!HasContainsSubrangeIt
<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith
>);
54 template <class Range1
, class Range2
= UncheckedRange
<int*>>
55 concept HasContainsSubrangeR
= requires(Range1
&& range1
, Range2
&& range2
) {
56 std::ranges::contains_subrange(std::forward
<Range1
>(range1
), std::forward
<Range2
>(range2
));
59 static_assert(HasContainsSubrangeR
<UncheckedRange
<int*>>);
60 static_assert(!HasContainsSubrangeR
<ForwardRangeNotDerivedFrom
>);
61 static_assert(!HasContainsSubrangeR
<ForwardIteratorNotIncrementable
>);
62 static_assert(!HasContainsSubrangeR
<ForwardRangeNotSentinelSemiregular
>);
63 static_assert(!HasContainsSubrangeR
<ForwardRangeNotSentinelEqualityComparableWith
>);
64 static_assert(!HasContainsSubrangeR
<UncheckedRange
<int*>, UncheckedRange
<int**>>); // not indirectly comparable
65 static_assert(!HasContainsSubrangeR
<UncheckedRange
<int*>, ForwardRangeNotDerivedFrom
>);
66 static_assert(!HasContainsSubrangeR
<UncheckedRange
<int*>, ForwardRangeNotIncrementable
>);
67 static_assert(!HasContainsSubrangeR
<UncheckedRange
<int*>, ForwardRangeNotSentinelSemiregular
>);
68 static_assert(!HasContainsSubrangeR
<UncheckedRange
<int*>, ForwardRangeNotSentinelEqualityComparableWith
>);
70 template <class Iter1
, class Sent1
= Iter1
, class Iter2
, class Sent2
= Iter2
>
71 constexpr void test_iterators() {
73 int a
[] = {1, 2, 3, 4, 5, 6};
75 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
76 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
78 std::same_as
<bool> decltype(auto) ret
=
79 std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
83 std::same_as
<bool> decltype(auto) ret
= std::ranges::contains_subrange(whole
, subrange
);
89 int a
[] = {1, 2, 3, 4, 5, 6};
91 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
92 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
94 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
98 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
103 { // range consists of just one element
106 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
107 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
109 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
113 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
118 { // subrange consists of just one element
119 int a
[] = {23, 1, 20, 3, 54, 2};
121 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
122 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
124 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
128 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
133 { // range has zero length
134 std::array
<int, 0> a
= {};
136 auto whole
= std::ranges::subrange(Iter1(a
.data()), Sent1(Iter1(a
.data())));
137 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
139 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
143 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
148 { // subrange has zero length
150 std::array
<int, 0> p
= {};
151 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
152 auto subrange
= std::ranges::subrange(Iter2(p
.data()), Sent2(Iter2(p
.data())));
154 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
158 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
163 { // range and subrange both have zero length
164 std::array
<int, 0> a
= {};
165 std::array
<int, 0> p
= {};
166 auto whole
= std::ranges::subrange(Iter1(a
.data()), Sent1(Iter1(a
.data())));
167 auto subrange
= std::ranges::subrange(Iter2(p
.data()), Sent2(Iter2(p
.data())));
169 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
173 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
178 { // range and subrange are identical
179 int a
[] = {3, 4, 11, 32, 54, 2};
180 int p
[] = {3, 4, 11, 32, 54, 2};
181 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
182 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
184 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
188 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
193 { // subrange is longer than range
195 int p
[] = {23, 3, 4, 2, 11, 32, 54, 2};
196 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
197 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
199 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
203 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
208 { // subrange is the prefix
209 int a
[] = {3, 43, 5, 100, 433, 278, 6457, 900};
210 int p
[] = {3, 43, 5};
211 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
212 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
214 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
218 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
223 { // subrange is the suffix
224 int a
[] = {3, 43, 5, 7, 68, 100, 433, 900};
225 int p
[] = {100, 433, 900};
226 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
227 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
229 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
233 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
238 { // subrange is a subsequence
239 int a
[] = {23, 1, 0, 54, 2};
241 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
242 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
244 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
248 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
253 { // repeated subrange
254 int a
[] = {23, 1, 0, 2, 54, 1, 0, 2, 23, 33};
256 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
257 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
259 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end());
263 bool ret
= std::ranges::contains_subrange(whole
, subrange
);
268 { // check that the predicate is used
269 int a
[] = {23, 81, 61, 0, 42, 25, 1, 2, 1, 29, 2};
270 int p
[] = {-1, -2, -1};
271 auto pred
= [](int l
, int r
) { return l
* -1 == r
; };
272 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
273 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
275 bool ret
= std::ranges::contains_subrange(whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end(), pred
);
279 bool ret
= std::ranges::contains_subrange(whole
, subrange
, pred
);
284 { // check that the projections are used
285 int a
[] = {1, 3, 15, 1, 2, 1, 8};
287 auto whole
= std::ranges::subrange(Iter1(a
), Sent1(Iter1(std::end(a
))));
288 auto subrange
= std::ranges::subrange(Iter2(p
), Sent2(Iter2(std::end(p
))));
289 auto proj1
= [](int i
) { return i
- 3; };
290 auto proj2
= [](int i
) { return i
* -1; };
292 bool ret
= std::ranges::contains_subrange(
293 whole
.begin(), whole
.end(), subrange
.begin(), subrange
.end(), {}, proj1
, proj2
);
297 bool ret
= std::ranges::contains_subrange(whole
, subrange
, {}, proj1
, proj2
);
303 constexpr bool test() {
304 types::for_each(types::forward_iterator_list
<int*>{}, []<class Iter1
> {
305 types::for_each(types::forward_iterator_list
<int*>{}, []<class Iter2
> {
306 test_iterators
<Iter1
, Iter1
, Iter2
, Iter2
>();
307 test_iterators
<Iter1
, Iter1
, Iter2
, sized_sentinel
<Iter2
>>();
308 test_iterators
<Iter1
, sized_sentinel
<Iter1
>, Iter2
, Iter2
>();
309 test_iterators
<Iter1
, sized_sentinel
<Iter1
>, Iter2
, sized_sentinel
<Iter2
>>();
313 assert(std::ranges::contains_subrange(
314 std::views::iota(0, 5), std::views::iota(0, 5) | std::views::filter([](int) { return true; })));
315 assert(!std::ranges::contains_subrange(std::views::iota(0ULL, 42ULL), std::views::iota(0ULL, 1ULL << 32)));
320 int main(int, char**) {
322 static_assert(test());