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// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10
11// <ranges>
12
13// std::views::chunk_by
14
15#include <ranges>
16
17#include <algorithm>
18#include <cassert>
19#include <concepts>
20#include <initializer_list>
21#include <type_traits>
22#include <utility>
23
24#include "test_iterators.h"
25#include "test_range.h"
26
27struct Pred {
28 constexpr bool operator()(int x, int y) const { return x != -y; }
29};
30
31struct NonCopyablePredicate : Pred {
32 NonCopyablePredicate(NonCopyablePredicate const&) = delete;
33};
34
35struct Range : std::ranges::view_base {
36 using Iterator = forward_iterator<int*>;
37 using Sentinel = sentinel_wrapper<Iterator>;
38 constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) {}
39 constexpr Iterator begin() const { return Iterator(begin_); }
40 constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }
41
42private:
43 int* begin_;
44 int* end_;
45};
46
47template <typename View>
48constexpr void compareViews(View v, std::initializer_list<std::initializer_list<int>> list) {
49 auto b1 = v.begin();
50 auto e1 = v.end();
51 auto b2 = list.begin();
52 auto e2 = list.end();
53 for (; b1 != e1 && b2 != e2; ++b1, ++b2) {
54 bool eq = std::ranges::equal(*b1, *b2, [](int x, int y) {
55 assert(x == y);
56 return true;
57 });
58 assert(eq);
59 }
60 assert(b1 == e1);
61 assert(b2 == e2);
62}
63
64constexpr int absoluteValue(int x) { return x < 0 ? -x : x; }
65
66template <class T>
67constexpr const T&& asConstRvalue(T&& t) {
68 return static_cast<T const&&>(t);
69}
70
71constexpr bool test() {
72 int buff[] = {-4, -3, -2, -1, 1, 2, 3, 4};
73
74 // Test range adaptor object
75 {
76 using RangeAdaptorObject = decltype(std::views::chunk_by);
77 static_assert(std::is_const_v<RangeAdaptorObject>);
78
79 // The type of a customization point object, ignoring cv-qualifiers, shall model semiregular
80 static_assert(std::semiregular<std::remove_const<RangeAdaptorObject>>);
81 }
82
83 // Test `views::chunk_by(pred)(v)`
84 {
85 using Result = std::ranges::chunk_by_view<Range, Pred>;
86 Range const range(buff, buff + 8);
87 Pred pred;
88
89 {
90 // 'views::chunk_by(pred)' - &&
91 std::same_as<Result> decltype(auto) result = std::views::chunk_by(pred)(range);
92 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
93 }
94 {
95 // 'views::chunk_by(pred)' - const&&
96 std::same_as<Result> decltype(auto) result = asConstRvalue(std::views::chunk_by(pred))(range);
97 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
98 }
99 {
100 // 'views::chunk_by(pred)' - &
101 auto partial = std::views::chunk_by(pred);
102 std::same_as<Result> decltype(auto) result = partial(range);
103 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
104 }
105 {
106 // 'views::chunk_by(pred)' - const&
107 auto const partial = std::views::chunk_by(pred);
108 std::same_as<Result> decltype(auto) result = partial(range);
109 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
110 }
111 }
112
113 // Test `v | views::chunk_by(pred)`
114 {
115 using Result = std::ranges::chunk_by_view<Range, Pred>;
116 Range const range(buff, buff + 8);
117 Pred pred;
118
119 {
120 // 'views::chunk_by(pred)' - &&
121 std::same_as<Result> decltype(auto) result = range | std::views::chunk_by(pred);
122 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
123 }
124 {
125 // 'views::chunk_by(pred)' - const&&
126 std::same_as<Result> decltype(auto) result = range | asConstRvalue(std::views::chunk_by(pred));
127 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
128 }
129 {
130 // 'views::chunk_by(pred)' - &
131 auto partial = std::views::chunk_by(pred);
132 std::same_as<Result> decltype(auto) result = range | partial;
133 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
134 }
135 {
136 // 'views::chunk_by(pred)' - const&
137 auto const partial = std::views::chunk_by(pred);
138 std::same_as<Result> decltype(auto) result = range | partial;
139 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
140 }
141 }
142
143 // Test `views::chunk_by(v, pred)` range adaptor object
144 {
145 using Result = std::ranges::chunk_by_view<Range, Pred>;
146 Range const range(buff, buff + 8);
147 Pred pred;
148
149 {
150 // 'views::chunk_by' - &&
151 auto range_adaptor = std::views::chunk_by;
152 std::same_as<Result> decltype(auto) result = std::move(range_adaptor)(range, pred);
153 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
154 }
155 {
156 // 'views::chunk_by' - const&&
157 auto const range_adaptor = std::views::chunk_by;
158 std::same_as<Result> decltype(auto) result = std::move(range_adaptor)(range, pred);
159 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
160 }
161 {
162 // 'views::chunk_by' - &
163 auto range_adaptor = std::views::chunk_by;
164 std::same_as<Result> decltype(auto) result = range_adaptor(range, pred);
165 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
166 }
167 {
168 // 'views::chunk_by' - const&
169 auto const range_adaptor = std::views::chunk_by;
170 std::same_as<Result> decltype(auto) result = range_adaptor(range, pred);
171 compareViews(result, {{-4, -3, -2, -1}, {1, 2, 3, 4}});
172 }
173 }
174
175 // Test that one can call std::views::chunk_by with arbitrary stuff, as long as we
176 // don't try to actually complete the call by passing it a range.
177 //
178 // That makes no sense and we can't do anything with the result, but it's valid.
179 {
180 int array[3] = {1, 2, 3};
181 [[maybe_unused]] auto partial = std::views::chunk_by(std::move(array));
182 }
183
184 // Test `adaptor | views::chunk_by(pred)`
185 {
186 Range const range(buff, buff + 8);
187
188 {
189 auto pred1 = [](int i) { return absoluteValue(x: i) < 3; };
190 Pred pred2;
191 using Result = std::ranges::chunk_by_view<std::ranges::filter_view<Range, decltype(pred1)>, Pred>;
192 std::same_as<Result> decltype(auto) result = range | std::views::filter(pred1) | std::views::chunk_by(pred2);
193 compareViews(result, {{-2, -1}, {1, 2}});
194 }
195 {
196 auto pred1 = [](int i) { return absoluteValue(x: i) < 3; };
197 Pred pred2;
198 using Result = std::ranges::chunk_by_view<std::ranges::filter_view<Range, decltype(pred1)>, Pred>;
199 auto const partial = std::views::filter(pred1) | std::views::chunk_by(pred2);
200 std::same_as<Result> decltype(auto) result = range | partial;
201 compareViews(result, {{-2, -1}, {1, 2}});
202 }
203 }
204
205 // Test SFINAE friendliness
206 {
207 struct NotAView {};
208 struct NotInvocable {};
209
210 static_assert(!CanBePiped<Range, decltype(std::views::chunk_by)>);
211 static_assert(CanBePiped<Range, decltype(std::views::chunk_by(Pred{}))>);
212 static_assert(!CanBePiped<NotAView, decltype(std::views::chunk_by(Pred{}))>);
213 static_assert(!CanBePiped<std::initializer_list<int>, decltype(std::views::chunk_by(Pred{}))>);
214 static_assert(!CanBePiped<Range, decltype(std::views::chunk_by(NotInvocable{}))>);
215
216 static_assert(!std::is_invocable_v<decltype(std::views::chunk_by)>);
217 static_assert(!std::is_invocable_v<decltype(std::views::chunk_by), Pred, Range>);
218 static_assert(std::is_invocable_v<decltype(std::views::chunk_by), Range, Pred>);
219 static_assert(!std::is_invocable_v<decltype(std::views::chunk_by), Range, Pred, Pred>);
220 static_assert(!std::is_invocable_v<decltype(std::views::chunk_by), NonCopyablePredicate>);
221 }
222
223 { static_assert(std::is_same_v<decltype(std::ranges::views::chunk_by), decltype(std::views::chunk_by)>); }
224
225 return true;
226}
227
228int main(int, char**) {
229 test();
230 static_assert(test());
231
232 return 0;
233}
234

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of libcxx/test/std/ranges/range.adaptors/range.chunk.by/adaptor.pass.cpp