openMSX
ranges_test.cc
Go to the documentation of this file.
1#include "catch.hpp"
2#include "ranges.hh"
3#include "stl.hh"
4#include "view.hh"
5#include <array>
6#include <span>
7#include <string>
8#include <vector>
9
10TEST_CASE("ranges::copy")
11{
12 std::array a = {1, 2, 3, 4, 5};
13 std::vector v = {9, 9, 9, 9, 9, 9, 9, 9};
14
15 // this is the c++20 std::ranges::copy() version
16 SECTION("range to output-iterator") {
17 ranges::copy(a, subspan(v, 1).data());
18 CHECK(v == std::vector{9, 1, 2, 3, 4, 5, 9, 9});
19
20 ranges::copy(a, v.data());
21 CHECK(v == std::vector{1, 2, 3, 4, 5, 5, 9, 9});
22 }
23
24 // this is our own extension
25 SECTION("sized_range to sized_range") {
26 ranges::copy(a, subspan(v, 1));
27 CHECK(v == std::vector{9, 1, 2, 3, 4, 5, 9, 9});
28
29 ranges::copy(a, v);
30 CHECK(v == std::vector{1, 2, 3, 4, 5, 5, 9, 9});
31 }
32
33 // Unfortunately our extension is not 100% backwards compatible.
34 // This example breaks:
35 SECTION("bw-compat") {
36 std::array<int, 10> buffer = {};
37
38 // This now triggers a compilation error: ambiguous overload
39 // It compiled fine before our extension.
40 //ranges::copy(a, buffer);
41
42 // It worked because c-arrays can (implicitly) decay to pointers
43 // when passed to functions. We can do that explicitly to
44 // resolve the ambiguity.
45 ranges::copy(a, std::begin(buffer));
46 CHECK(to_vector(buffer) == std::vector{1, 2, 3, 4, 5, 0, 0, 0, 0, 0});
47
48 // But a better solution is to replace teh c-array with a
49 // std::array. (This has other benefits as well, though not
50 // relevant for this example).
51 std::array<int, 10> buffer2 = {};
52 ranges::copy(a, buffer2);
53 CHECK(to_vector(buffer2) == std::vector{1, 2, 3, 4, 5, 0, 0, 0, 0, 0});
54 }
55}
56
57TEST_CASE("ranges::equal")
58{
59 auto always_equal = [](const auto&, const auto&) { return true; };
60
61 SECTION("sized ranges") {
62 std::array a3 = {1, 2, 3};
63 std::vector v3 = {1, 2, 3};
64 std::array a4 = {2, 4, 6, 8};
65 std::vector v4 = {1, 2, 3, 4};
66
67 CHECK( ranges::equal(a3, a3));
68 CHECK( ranges::equal(a3, v3));
69 CHECK(!ranges::equal(a3, a4));
70 CHECK(!ranges::equal(a3, v4));
71
72 CHECK( ranges::equal(v3, v3));
73 CHECK( ranges::equal(v3, v3));
74 CHECK(!ranges::equal(v3, a4));
75 CHECK(!ranges::equal(v3, v4));
76
77 CHECK(!ranges::equal(a4, v3));
78 CHECK(!ranges::equal(a4, v3));
79 CHECK( ranges::equal(a4, a4));
80 CHECK(!ranges::equal(a4, v4));
81
82 CHECK(!ranges::equal(v4, v3));
83 CHECK(!ranges::equal(v4, v3));
84 CHECK(!ranges::equal(v4, a4));
86
87 CHECK( ranges::equal(a4, v4, always_equal));
88 CHECK(!ranges::equal(a3, a4, always_equal)); // size is different
89
90 auto mul2 = [](const auto& e) { return e * 2; };
91 auto div2 = [](const auto& e) { return e / 2; };
92 CHECK( ranges::equal(a4, v4, {}, div2));
93 CHECK( ranges::equal(a4, v4, {}, {}, mul2));
94 CHECK(!ranges::equal(a4, v4, {}, div2, mul2));
95 CHECK( ranges::equal(a4, v4, always_equal, div2, mul2));
96 CHECK(!ranges::equal(a4, v3, always_equal, div2, mul2)); // size is different
97 }
98 SECTION("non-sized ranges") {
99 std::array a2 = {2, 4};
100 std::array a3 = {1, 3, 5};
101 std::array a4 = {1, 3, 5, 7};
102 std::array a5 = {1, 2, 3, 4, 5};
103 auto is_even = [](const auto& e) { return (e & 1) == 0; };
104 auto is_odd = [](const auto& e) { return (e & 1) == 1; };
105 auto ve = view::filter(a5, is_even);
106 auto vo = view::filter(a5, is_odd);
107 // The size of a "view::filter" is only known after the filter
108 // has been applied. This makes "view::filter" a non-size range.
109
110 CHECK( ranges::equal(ve, a2));
111 CHECK(!ranges::equal(ve, a3));
112 CHECK(!ranges::equal(ve, a4));
113 CHECK(!ranges::equal(ve, vo));
114 CHECK( ranges::equal(ve, ve));
115
116 CHECK(!ranges::equal(vo, a2));
117 CHECK( ranges::equal(vo, a3));
118 CHECK(!ranges::equal(vo, a4)); // front matches, but a4 is longer
119 CHECK( ranges::equal(vo, vo));
120 CHECK(!ranges::equal(vo, ve));
121
122 std::array b3 = {9, 9, 9};
123 CHECK(!ranges::equal(ve, b3, always_equal)); // different size
124 CHECK( ranges::equal(vo, b3, always_equal));
125 CHECK(!ranges::equal(b3, ve, always_equal)); // different size
126 CHECK( ranges::equal(b3, vo, always_equal));
127
128 struct S {
129 int x, y;
130 };
131 std::array ss = {S{9, 1}, S{9, 3}, S{9, 5}};
132 CHECK(!ranges::equal(vo, ss, {}, {}, &S::x));
133 CHECK( ranges::equal(vo, ss, {}, {}, &S::y));
134 CHECK(!ranges::equal(ss, vo, {}, &S::x));
135 CHECK( ranges::equal(ss, vo, {}, &S::y));
136 }
137}
138
139TEST_CASE("ranges::all_equal")
140{
141 std::array<int, 0> a = {};
142 std::array b = {3};
143 std::array c = {3, 3};
144 std::array d = {3, 3, 3};
145 std::array e = {1, 3, 3};
146 std::array f = {3, 1, 3};
147 std::array g = {3, 3, 1};
155
156 struct S {
157 int x, y;
158 };
159 std::array s = {S{9, 1}, S{9, 3}, S{9, 5}, S{9, 7}};
160 CHECK( ranges::all_equal(s, &S::x));
161 CHECK(!ranges::all_equal(s, &S::y));
162}
163
164TEST_CASE("binary_find")
165{
166 SECTION("no projection") {
167 std::array a = {3, 5, 9, 13, 19, 22, 45, 87, 98};
168
169 SECTION("found") {
170 SECTION("first") {
171 auto f = binary_find(a, 3);
172 CHECK(*f == 3);
173 CHECK(f == &a[0]);
174 }
175 SECTION("middle") {
176 auto f = binary_find(a, 19);
177 CHECK(*f == 19);
178 CHECK(f == &a[4]);
179 }
180 SECTION("last") {
181 auto f = binary_find(a, 98);
182 CHECK(*f == 98);
183 CHECK(f == &a[8]);
184 }
185 }
186 SECTION("not found") {
187 SECTION("before") {
188 CHECK(binary_find(a, 2) == nullptr);
189 }
190 SECTION("middle") {
191 CHECK(binary_find(a, 28) == nullptr);
192 }
193 SECTION("after") {
194 CHECK(binary_find(a, 99) == nullptr);
195 }
196 }
197 }
198 SECTION("no projection, reverse sorted") {
199 std::vector v = {86, 54, 33, 29, 14, 3};
200 CHECK(binary_find(v, 33, std::greater{}) == &v[2]);
201 CHECK(binary_find(v, 14, std::greater{}) == &v[4]);
202 CHECK(binary_find(v, 48, std::greater{}) == nullptr);
203 CHECK(binary_find(v, 7, std::greater{}) == nullptr);
204 }
205 SECTION("projection") {
206 struct S {
207 int i;
208 std::string s;
209 };
210 std::vector v = {S{4, "four"}, S{6, "six"}, S{10, "ten"}, S{99, "a lot"}};
211
212 CHECK(binary_find(v, 4, {}, &S::i) == &v[0]);
213 CHECK(binary_find(v, 99, {}, &S::i) == &v[3]);
214 CHECK(binary_find(v, 6, {}, &S::i)->s == "six");
215 CHECK(binary_find(v, 10, {}, &S::i)->s == "ten");
216 CHECK(binary_find(v, 1, {}, &S::i) == nullptr);
217 CHECK(binary_find(v, 17, {}, &S::i) == nullptr);
218 CHECK(binary_find(v, 100, {}, &S::i) == nullptr);
219 }
220}
221
222TEST_CASE("subspan")
223{
224 SECTION("from vector") {
225 std::vector v = {2, 6, 7, 9, 1, 3, 4, 5, 6, 0, 1};
226 SECTION("dynamic size") {
227 SECTION("full") {
228 auto s = subspan(v, 0);
229 CHECK(s.data() == &v[0]);
230 CHECK(s.size() == 11);
231 CHECK(s.extent == std::dynamic_extent);
232 }
233 SECTION("till end") {
234 auto s = subspan(v, 6);
235 CHECK(s.data() == &v[6]);
236 CHECK(s.size() == 5);
237 CHECK(s.extent == std::dynamic_extent);
238 }
239 SECTION("till end, empty") {
240 auto s = subspan(v, 11);
241 CHECK(s.empty());
242 CHECK(s.extent == std::dynamic_extent);
243 }
244 SECTION("from start, with size") {
245 auto s = subspan(v, 0, 3);
246 CHECK(s.data() == &v[0]);
247 CHECK(s.size() == 3);
248 CHECK(s.extent == std::dynamic_extent);
249 }
250 SECTION("middle") {
251 auto s = subspan(v, 4, 5);
252 CHECK(s.data() == &v[4]);
253 CHECK(s.size() == 5);
254 CHECK(s.extent == std::dynamic_extent);
255 }
256 }
257 SECTION("fixed size") {
258 SECTION("full") {
259 auto s = subspan<11>(v);
260 CHECK(s.data() == &v[0]);
261 CHECK(s.size() == 11);
262 CHECK(s.extent == 11);
263 }
264 SECTION("from start") {
265 auto s = subspan<5>(v);
266 CHECK(s.data() == &v[0]);
267 CHECK(s.size() == 5);
268 CHECK(s.extent == 5);
269 }
270 SECTION("middle") {
271 auto s = subspan<7>(v, 2);
272 CHECK(s.data() == &v[2]);
273 CHECK(s.size() == 7);
274 CHECK(s.extent == 7);
275 }
276 SECTION("empty") {
277 auto s = subspan<0>(v, 2);
278 CHECK(s.empty());
279 CHECK(s.extent == 0);
280 }
281 }
282 }
283 SECTION("from array") {
284 std::array a = {3, 5, 1, 2, 3, 9, 1, 0};
285
286 auto s1 = subspan(a, 2, 3);
287 CHECK(s1.data() == &a[2]);
288 CHECK(s1.size() == 3);
289 CHECK(s1.extent == std::dynamic_extent);
290
291 auto s2 = subspan<4>(a, 1);
292 CHECK(s2.data() == &a[1]);
293 CHECK(s2.size() == 4);
294 CHECK(s2.extent == 4);
295 }
296 SECTION("from string") {
297 std::string s = "abcdefghijklmnopqrstuvwxyz";
298
299 auto s1 = subspan(s, 20);
300 CHECK(s1.data() == &s[20]);
301 CHECK(s1.size() == 6);
302 CHECK(s1.extent == std::dynamic_extent);
303
304 auto s2 = subspan<3>(s, 6);
305 CHECK(s2.data() == &s[6]);
306 CHECK(s2.size() == 3);
307 CHECK(s2.extent == 3);
308 }
309 SECTION("from another span") {
310 std::vector v = {2, 4, 6, 8, 4, 2};
311 std::span s = v;
312
313 auto s1 = subspan(s, 0, 3);
314 CHECK(s1.data() == &v[0]);
315 CHECK(s1.size() == 3);
316 CHECK(s1.extent == std::dynamic_extent);
317
318 auto s2 = subspan<4>(s, 2);
319 CHECK(s2.data() == &v[2]);
320 CHECK(s2.size() == 4);
321 CHECK(s2.extent == 4);
322 }
323 SECTION("from a class with begin/end methods") {
324 struct S {
325 const auto* begin() const { return a.begin(); }
326 const auto* end() const { return a.end(); }
327 std::array<int, 10> a;
328 } s;
329
330 auto s1 = subspan(s, 4, 5);
331 CHECK(s1.data() == &s.a[4]);
332 CHECK(s1.size() == 5);
333 CHECK(s1.extent == std::dynamic_extent);
334
335 auto s2 = subspan<7>(s, 1);
336 CHECK(s2.data() == &s.a[1]);
337 CHECK(s2.size() == 7);
338 CHECK(s2.extent == 7);
339 }
340}
int g
CHECK(m3==m3)
vec4 v4(2, 1, -4, -3)
bool all_equal(InputRange &&range, Proj proj={})
Definition ranges.hh:415
constexpr bool equal(InputRange1 &&range1, InputRange2 &&range2, Pred pred={}, Proj1 proj1={}, Proj2 proj2={})
Definition ranges.hh:378
constexpr auto copy(InputRange &&range, OutputIter out)
Definition ranges.hh:252
auto filter(ForwardRange &&range, Predicate pred)
Definition view.hh:538
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
Definition ranges.hh:481
auto * binary_find(ForwardRange &&range, const T &value, Compare comp={}, Proj proj={})
Definition ranges.hh:448
TEST_CASE("ranges::copy")
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))> >
Definition stl.hh:278
Definition stl_test.cc:7
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)