openMSX
view_test.cc
Go to the documentation of this file.
1#include "catch.hpp"
2#include "view.hh"
3
4#include "hash_map.hh"
5#include "ranges.hh"
6#include "stl.hh"
7#include "xrange.hh"
8#include "StringOp.hh"
9
10#include <algorithm>
11#include <list>
12#include <map>
13#include <string>
14#include <tuple>
15#include <vector>
16
17using std::vector;
18using namespace view;
19
20static vector<int> getVector(int n)
21{
22 return to_vector(xrange(n));
23}
24
25TEST_CASE("view::drop random-access-range")
26{
27 SECTION("empty") {
28 vector<int> v;
29 CHECK(to_vector(drop(v, 0)) == vector<int>{});
30 CHECK(to_vector(drop(v, 3)) == vector<int>{});
31 }
32 SECTION("non-empty") {
33 vector<int> v = {1, 2, 3, 4, 5};
34 CHECK(to_vector(drop(v, 0)) == vector<int>{1, 2, 3, 4, 5});
35 CHECK(to_vector(drop(v, 1)) == vector<int>{2, 3, 4, 5});
36 CHECK(to_vector(drop(v, 2)) == vector<int>{3, 4, 5});
37 CHECK(to_vector(drop(v, 3)) == vector<int>{4, 5});
38 CHECK(to_vector(drop(v, 4)) == vector<int>{5});
39 CHECK(to_vector(drop(v, 5)) == vector<int>{});
40 CHECK(to_vector(drop(v, 6)) == vector<int>{});
41 CHECK(to_vector(drop(v, 7)) == vector<int>{});
42 }
43 SECTION("r-value") {
44 CHECK(to_vector(drop(getVector(6), 3)) == vector<int>{3, 4, 5});
45 }
46}
47
48TEST_CASE("view::drop non-random-access-range")
49{
50 SECTION("empty") {
51 std::list<int> l;
52 CHECK(to_vector(drop(l, 0)) == vector<int>{});
53 CHECK(to_vector(drop(l, 3)) == vector<int>{});
54 }
55 SECTION("non-empty") {
56 std::list<int> l = {1, 2, 3, 4, 5};
57 CHECK(to_vector(drop(l, 0)) == vector<int>{1, 2, 3, 4, 5});
58 CHECK(to_vector(drop(l, 1)) == vector<int>{2, 3, 4, 5});
59 CHECK(to_vector(drop(l, 2)) == vector<int>{3, 4, 5});
60 CHECK(to_vector(drop(l, 3)) == vector<int>{4, 5});
61 CHECK(to_vector(drop(l, 4)) == vector<int>{5});
62 CHECK(to_vector(drop(l, 5)) == vector<int>{});
63 CHECK(to_vector(drop(l, 6)) == vector<int>{});
64 CHECK(to_vector(drop(l, 7)) == vector<int>{});
65 }
66}
67
68TEST_CASE("view::drop capture")
69{
70 REQUIRE(sizeof(vector<int>*) != sizeof(vector<int>));
71 SECTION("l-value") {
72 vector<int> v = {0, 1, 2, 3};
73 auto d = drop(v, 1);
74 // 'd' stores a reference to 'v'
75 CHECK(sizeof(d) == (sizeof(vector<int>*) + sizeof(size_t)));
76 }
77 SECTION("r-value") {
78 auto d = drop(getVector(4), 1);
79 // 'd' stores a vector by value
80 CHECK(sizeof(d) == (sizeof(vector<int>) + sizeof(size_t)));
81 }
82}
83
84
85TEST_CASE("view::drop_back random-access-range")
86{
87 SECTION("empty") {
88 vector<int> v;
89 CHECK(to_vector(drop_back(v, 0)) == vector<int>{});
90 CHECK(to_vector(drop_back(v, 3)) == vector<int>{});
91 }
92 SECTION("non-empty") {
93 vector<int> v = {1, 2, 3, 4, 5};
94 CHECK(to_vector(drop_back(v, 0)) == vector<int>{1, 2, 3, 4, 5});
95 CHECK(to_vector(drop_back(v, 1)) == vector<int>{1, 2, 3, 4});
96 CHECK(to_vector(drop_back(v, 2)) == vector<int>{1, 2, 3});
97 CHECK(to_vector(drop_back(v, 3)) == vector<int>{1, 2});
98 CHECK(to_vector(drop_back(v, 4)) == vector<int>{1});
99 CHECK(to_vector(drop_back(v, 5)) == vector<int>{});
100 CHECK(to_vector(drop_back(v, 6)) == vector<int>{});
101 CHECK(to_vector(drop_back(v, 7)) == vector<int>{});
102 }
103 SECTION("r-value") {
104 CHECK(to_vector(drop_back(getVector(6), 3)) == vector<int>{0, 1, 2});
105 }
106}
107
108TEST_CASE("view::drop_back non-random-access-range")
109{
110 SECTION("empty") {
111 std::list<int> l;
112 CHECK(to_vector(drop_back(l, 0)) == vector<int>{});
113 CHECK(to_vector(drop_back(l, 3)) == vector<int>{});
114 }
115 SECTION("non-empty") {
116 std::list<int> l = {1, 2, 3, 4, 5};
117 CHECK(to_vector(drop_back(l, 0)) == vector<int>{1, 2, 3, 4, 5});
118 CHECK(to_vector(drop_back(l, 1)) == vector<int>{1, 2, 3, 4});
119 CHECK(to_vector(drop_back(l, 2)) == vector<int>{1, 2, 3});
120 CHECK(to_vector(drop_back(l, 3)) == vector<int>{1, 2});
121 CHECK(to_vector(drop_back(l, 4)) == vector<int>{1});
122 CHECK(to_vector(drop_back(l, 5)) == vector<int>{});
123 CHECK(to_vector(drop_back(l, 6)) == vector<int>{});
124 CHECK(to_vector(drop_back(l, 7)) == vector<int>{});
125 }
126}
127
128
129TEST_CASE("view::reverse")
130{
131 vector<int> out;
132 SECTION("l-value") {
133 vector<int> in = {1, 2, 3, 4};
134 for (auto& e : reverse(in)) out.push_back(e);
135 CHECK(out == vector<int>{4, 3, 2, 1});
136 }
137 SECTION("r-value") {
138 for (auto& e : reverse(getVector(3))) out.push_back(e);
139 CHECK(out == vector<int>{2, 1, 0});
140 }
141 SECTION("2 x reverse") {
142 for (auto& e : reverse(reverse(getVector(4)))) out.push_back(e);
143 CHECK(out == vector<int>{0, 1, 2, 3});
144 }
145}
146
147TEST_CASE("view::transform")
148{
149 auto square = [](auto& x) { return x * x; };
150 size_t i = 1;
151 auto plus_i = [&](auto& x) { return int(x + i); };
152
153 SECTION("l-value") {
154 vector<int> v = {1, 2, 3, 4};
155 CHECK(to_vector(transform(v, square)) == vector<int>{1, 4, 9, 16});
156 }
157 SECTION("r-value") {
158 i = 10;
159 CHECK(to_vector(transform(getVector(4), plus_i)) == vector<int>{10, 11, 12, 13});
160 }
161}
162
163/*
164No longer true since we use semiregular_t<> in TransformIterator
165TEST_CASE("view::transform sizes")
166{
167 auto square = [](auto& x) { return x * x; };
168 size_t i = 1;
169 auto plus_i = [&](auto& x) { return int(x + i); };
170
171 vector<int> v = {1, 2, 3, 4};
172
173 SECTION("l-value, stateless") {
174 auto vw = transform(v, square);
175 CHECK(sizeof(vw) == sizeof(std::vector<int>*));
176 CHECK(sizeof(vw.begin()) == sizeof(std::vector<int>::iterator));
177 }
178 SECTION("l-value, state") {
179 auto vw = transform(v, plus_i);
180 CHECK(sizeof(vw) == (sizeof(size_t&) + sizeof(std::vector<int>*)));
181 CHECK(sizeof(vw.begin()) == (sizeof(size_t&) + sizeof(std::vector<int>::iterator)));
182 }
183 SECTION("r-value, stateless") {
184 auto vw = transform(getVector(3), square);
185 CHECK(sizeof(vw) == sizeof(std::vector<int>));
186 CHECK(sizeof(vw.begin()) == sizeof(std::vector<int>::iterator));
187 }
188 SECTION("r-value, state") {
189 auto vw = transform(getVector(3), plus_i);
190 CHECK(sizeof(vw) == (sizeof(size_t&) + sizeof(std::vector<int>)));
191 CHECK(sizeof(vw.begin()) == (sizeof(size_t&) + sizeof(std::vector<int>::iterator)));
192 }
193}*/
194
195template<typename RANGE, typename T>
196static void check(const RANGE& range, const vector<T>& expected)
197{
198 CHECK(ranges::equal(range, expected));
199}
200
201template<typename RANGE, typename T>
202static void check_unordered(const RANGE& range, const vector<T>& expected_)
203{
204 auto result = to_vector<T>(range);
205 auto expected = expected_;
206 ranges::sort(result);
207 ranges::sort(expected);
208 CHECK(result == expected);
209}
210
211TEST_CASE("view::keys, view::values") {
212 SECTION("std::map") {
213 std::map<int, int> m = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
214 check(keys (m), vector<int>{1, 3, 5, 7});
215 check(values(m), vector<int>{2, 4, 6, 8});
216 }
217 SECTION("std::vector<std::pair>") {
218 vector<std::pair<int, int>> v = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
219 check(keys (v), vector<int>{1, 3, 5, 7});
220 check(values(v), vector<int>{2, 4, 6, 8});
221 }
222 SECTION("hash_map") {
224 {"foo", 1}, {"bar", 2}, {"qux", 3},
225 {"baz", 4}, {"a", 5}, {"z", 6}
226 };
227 check_unordered(keys(m), vector<std::string>{
228 "foo", "bar", "qux", "baz", "a", "z"});
229 check_unordered(values(m), vector<int>{1, 2, 3, 4, 5, 6});
230 }
231 SECTION("std::vector<std::tuple>") {
232 vector<std::tuple<int, char, double, std::string>> v = {
233 std::tuple(1, 2, 1.2, "foo"),
234 std::tuple(3, 4, 3.4, "bar"),
235 std::tuple(5, 6, 5.6, "qux")
236 };
237 check(keys (v), vector<int>{1, 3, 5});
238 check(values(v), vector<char>{2, 4, 6});
239 }
240}
241
242struct F {
243 int i;
244 /*implicit*/ F(int i_) : i(i_) {}
245 /*implicit*/ operator int() const { return i; }
246 bool isOdd() const { return i & 1; }
247};
248
249TEST_CASE("view::filter") {
250 vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
251
252 SECTION("removed front") {
253 check(view::filter(v, [](int i) { return i > 5; }),
254 vector{6, 7, 8, 9});
255 }
256 SECTION("removed back") {
257 check(view::filter(v, [](int i) { return i < 5; }),
258 vector{1, 2, 3, 4});
259 }
260 SECTION("keep front and back") {
261 check(view::filter(v, [](int i) { return i & 1; }),
262 vector{1, 3, 5, 7, 9});
263 }
264 SECTION("remove front and back") {
265 check(view::filter(v, [](int i) { return (i & 1) == 0; }),
266 vector{2, 4, 6, 8});
267 }
268
269 SECTION("projection") {
270 vector<F> f = {1, 2, 3, 4, 5};
271 auto view = view::filter(f, &F::isOdd);
272 auto it = view.begin();
273 auto et = view.end();
274 REQUIRE(it != et);
275 CHECK(*it == 1);
276 ++it;
277 REQUIRE(it != et);
278 CHECK(*it == 3);
279 it++;
280 REQUIRE(it != et);
281 CHECK(*it == 5);
282 ++it;
283 REQUIRE(it == et);
284 }
285}
286
287TEST_CASE("view::take") {
288 SECTION("n") {
289 vector v = {1, 2, 3, 4};
290 check(view::take(v, 0), vector<int>{});
291 check(view::take(v, 1), vector{1});
292 check(view::take(v, 2), vector{1, 2});
293 check(view::take(v, 3), vector{1, 2, 3});
294 check(view::take(v, 4), vector{1, 2, 3, 4});
295 check(view::take(v, 5), vector{1, 2, 3, 4});
296 check(view::take(v, 6), vector{1, 2, 3, 4});
297 }
298 SECTION("split_view") {
299 std::string_view str = "abc def\t \tghi jkl mno pqr";
300 auto v = view::take(StringOp::split_view<StringOp::REMOVE_EMPTY_PARTS>(str, " \t"), 3);
301
302 auto it = v.begin();
303 auto et = v.end();
304 REQUIRE(it != et);
305 CHECK(*it == "abc");
306
307 ++it;
308 REQUIRE(it != et);
309 CHECK(*it == "def");
310
311 ++it;
312 REQUIRE(it != et);
313 CHECK(*it == "ghi");
314
315 ++it;
316 REQUIRE(it == et);
317 }
318}
319
320template<typename In1, typename In2, typename Expected>
321void test_zip(const In1& in1, const In2& in2, const Expected& expected)
322{
323 Expected result;
324 for (const auto& t : view::zip(in1, in2)) {
325 result.push_back(t);
326 }
327 CHECK(result == expected);
328}
329
330template<typename In1, typename In2, typename In3, typename Expected>
331void test_zip(const In1& in1, const In2& in2, const In3& in3, const Expected& expected)
332{
333 Expected result;
334 for (const auto& t : view::zip(in1, in2, in3)) {
335 result.push_back(t);
336 }
337 CHECK(result == expected);
338}
339
340TEST_CASE("view::zip")
341{
342 std::vector v4 = {1, 2, 3, 4};
343 std::array a3 = {'a', 'b', 'c'};
344 std::list l4 = {1.2, 2.3, 3.4, 4.5};
345
346 test_zip(v4, a3, std::vector<std::tuple<int, char>>{{1, 'a'}, {2, 'b'}, {3, 'c'}});
347 test_zip(a3, v4, std::vector<std::tuple<char, int>>{{'a', 1}, {'b', 2}, {'c', 3}});
348
349 test_zip(v4, l4, std::vector<std::tuple<int, double>>{{1, 1.2}, {2, 2.3}, {3, 3.4}, {4, 4.5}});
350 test_zip(l4, v4, std::vector<std::tuple<double, int>>{{1.2, 1}, {2.3, 2}, {3.4, 3}, {4.5, 4}});
351
352 test_zip(a3, l4, std::vector<std::tuple<char, double>>{{'a', 1.2}, {'b', 2.3}, {'c', 3.4}});
353 test_zip(l4, a3, std::vector<std::tuple<double, char>>{{1.2, 'a'}, {2.3, 'b'}, {3.4, 'c'}});
354
355 test_zip(v4, a3, l4, std::vector<std::tuple<int, char, double>>{{1, 'a', 1.2}, {2, 'b', 2.3}, {3, 'c', 3.4}});
356
357 for (auto [x, y] : zip(v4, a3)) {
358 x = 0;
359 ++y;
360 }
361 CHECK(v4 == std::vector{0, 0, 0, 4});
362 CHECK(a3 == std::array{'b', 'c', 'd'});
363}
364
365template<typename In1, typename In2, typename Expected>
366void test_zip_equal(const In1& in1, const In2& in2, const Expected& expected)
367{
368 Expected result;
369 for (const auto& t : view::zip_equal(in1, in2)) {
370 result.push_back(t);
371 }
372 CHECK(result == expected);
373}
374
375template<typename In1, typename In2, typename In3, typename Expected>
376void test_zip_equal(const In1& in1, const In2& in2, const In3& in3, const Expected& expected)
377{
378 Expected result;
379 for (const auto& t : view::zip_equal(in1, in2, in3)) {
380 result.push_back(t);
381 }
382 CHECK(result == expected);
383}
384
385TEST_CASE("view::zip_equal")
386{
387 std::vector v = {1, 2, 3};
388 std::array a = {'a', 'b', 'c'};
389 std::list l = {1.2, 2.3, 3.4};
390
391 test_zip_equal(v, a, std::vector<std::tuple<int, char>>{{1, 'a'}, {2, 'b'}, {3, 'c'}});
392 test_zip_equal(v, l, std::vector<std::tuple<int, double>>{{1, 1.2}, {2, 2.3}, {3, 3.4}});
393 test_zip_equal(a, l, std::vector<std::tuple<char, double>>{{'a', 1.2}, {'b', 2.3}, {'c', 3.4}});
394
395 test_zip_equal(v, a, l, std::vector<std::tuple<int, char, double>>{{1, 'a', 1.2}, {2, 'b', 2.3}, {3, 'c', 3.4}});
396
397 for (auto [x, y, z] : zip_equal(v, l, a)) {
398 x = 0;
399 y *= 2.0;
400 z += 2;
401 }
402 CHECK(v == std::vector{0, 0, 0});
403 CHECK(a == std::array{'c', 'd', 'e'});
404 CHECK(l == std::list{2.4, 4.6, 6.8});
405}
TclObject t
CHECK(m3==m3)
imat4 l4(ivec4(1, 2, 3, 4), ivec4(3, 4, 5, 6), ivec4(5, 6, 7, 0), ivec4(7, 8, 9, 0))
vec4 v4(2, 1, -4, -3)
bool equal(InputRange1 &&range1, InputRange2 &&range2, Pred pred={}, Proj1 proj1={}, Proj2 proj2={})
Definition ranges.hh:368
constexpr void sort(RandomAccessRange &&range)
Definition ranges.hh:49
Definition view.hh:15
auto zip_equal(Ranges &&... ranges)
Definition view.hh:559
auto filter(ForwardRange &&range, Predicate pred)
Definition view.hh:538
constexpr auto transform(Range &&range, UnaryOp op)
Definition view.hh:520
constexpr auto take(ForwardRange &&range, size_t n)
Definition view.hh:544
constexpr auto reverse(Range &&range)
Definition view.hh:514
constexpr auto drop(Range &&range, size_t n)
Definition view.hh:502
constexpr auto drop_back(Range &&range, size_t n)
Definition view.hh:508
auto zip(Ranges &&... ranges)
Definition view.hh:551
constexpr auto keys(Map &&map)
Definition view.hh:525
constexpr auto values(Map &&map)
Definition view.hh:531
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))> >
Definition stl.hh:275
int i
Definition view_test.cc:243
F(int i_)
Definition view_test.cc:244
bool isOdd() const
Definition view_test.cc:246
TEST_CASE("view::drop random-access-range")
Definition view_test.cc:25
void test_zip(const In1 &in1, const In2 &in2, const Expected &expected)
Definition view_test.cc:321
void test_zip_equal(const In1 &in1, const In2 &in2, const Expected &expected)
Definition view_test.cc:366
constexpr auto xrange(T e)
Definition xrange.hh:132