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