1 //
2 // Copyright 2019-2020 Mateusz Loskot <mateusz at loskot dot net>
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 #include <boost/gil.hpp>
9 #include <boost/gil/extension/numeric/channel_numeric_operations.hpp>
10
11 #include <boost/core/lightweight_test.hpp>
12
13 #include <tuple>
14 #include <type_traits>
15
16 #include "test_utility_output_stream.hpp"
17 #include "core/channel/test_fixture.hpp"
18
19 namespace gil = boost::gil;
20 namespace fixture = boost::gil::test::fixture;
21
22 struct test_plus_integer_same_types
23 {
24 template <typename Channel>
operator ()test_plus_integer_same_types25 void operator()(Channel const&)
26 {
27 using channel_t = Channel;
28 gil::channel_plus_t<channel_t, channel_t, channel_t> f;
29 BOOST_TEST_EQ(f(0, 0), channel_t(0));
30 BOOST_TEST_EQ(f(100, 27), channel_t(127));
31 }
runtest_plus_integer_same_types32 static void run()
33 {
34 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_plus_integer_same_types{});
35 }
36 };
37
38 struct test_plus_integer_mixed_types
39 {
40 template <typename Channel>
operator ()test_plus_integer_mixed_types41 void operator()(Channel const&)
42 {
43 using channel_t = Channel;
44 {
45 using channel1_t = channel_t;
46 using channel2_t = std::uint8_t; // duplicates only one of fixture::channel_integer_types
47 gil::channel_plus_t<channel1_t, channel2_t, channel1_t> f;
48 BOOST_TEST_EQ(f(0, 0), channel1_t(0));
49 BOOST_TEST_EQ(f(100, 27), channel_t(127));
50 }
51 {
52 using channel1_t = std::uint8_t; // duplicates only one of fixture::channel_integer_types
53 using channel2_t = channel_t;
54 gil::channel_plus_t<channel1_t, channel2_t, channel2_t> f;
55 BOOST_TEST_EQ(f(0, 0), channel2_t(0));
56 BOOST_TEST_EQ(f(100, 27), channel_t(127));
57 }
58 }
runtest_plus_integer_mixed_types59 static void run()
60 {
61 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_plus_integer_mixed_types{});
62 }
63 };
64
65 struct test_plus_integer_signed_types_with_overflow
66 {
67 template <typename Channel>
operator ()test_plus_integer_signed_types_with_overflow68 void operator()(Channel const&)
69 {
70 using channel_t = Channel;
71 // Signed integer overflow is UB, so just check addition does not yield mathematically
72 // expected value but is constrained by the range of representable values for given type.
73
74 auto const max_value = gil::channel_traits<channel_t>::max_value();
75 gil::channel_plus_t<channel_t, channel_t, channel_t> f;
76 BOOST_TEST_NE(f(max_value, 1), std::int64_t(max_value) + 1);
77 BOOST_TEST_NE(f(max_value, max_value), std::int64_t(max_value) + max_value);
78 }
runtest_plus_integer_signed_types_with_overflow79 static void run()
80 {
81 boost::mp11::mp_for_each<fixture::channel_integer_signed_types>(test_plus_integer_signed_types_with_overflow{});
82 }
83 };
84
85 struct test_plus_integer_unsigned_types_with_wraparound
86 {
87 template <typename Channel>
operator ()test_plus_integer_unsigned_types_with_wraparound88 void operator()(Channel const&)
89 {
90 using channel_t = Channel;
91 // The C Standard, 6.2.5, paragraph 9 [ISO/IEC 9899:2011], states:
92 // A computation involving unsigned operands can never overflow, because a result that
93 // cannot be represented by the resulting unsigned integer type is reduced modulo the number
94 // that is one greater than the largest value that can be represented by the resulting type.
95
96 auto const max_value = gil::channel_traits<channel_t>::max_value();
97 auto const min_value = gil::channel_traits<channel_t>::min_value();
98 gil::channel_plus_t<channel_t, channel_t, channel_t> f;
99 BOOST_TEST_EQ(f(max_value, 1), min_value);
100 BOOST_TEST_EQ(f(max_value, max_value), max_value - 1);
101 }
runtest_plus_integer_unsigned_types_with_wraparound102 static void run()
103 {
104 boost::mp11::mp_for_each<fixture::channel_integer_unsigned_types>(test_plus_integer_unsigned_types_with_wraparound{});
105 }
106 };
107
108 struct test_minus_integer_same_types
109 {
110 template <typename Channel>
operator ()test_minus_integer_same_types111 void operator()(Channel const&)
112 {
113 using channel_t = Channel;
114 gil::channel_minus_t<channel_t, channel_t, channel_t> f;
115 BOOST_TEST_EQ(f(0, 0), channel_t(0));
116 BOOST_TEST_EQ(f(100, 27), channel_t(73));
117 }
runtest_minus_integer_same_types118 static void run()
119 {
120 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_minus_integer_same_types{});
121 }
122 };
123
124 struct test_minus_integer_mixed_types
125 {
126 template <typename Channel>
operator ()test_minus_integer_mixed_types127 void operator()(Channel const&)
128 {
129 using channel_t = Channel;
130 {
131 using channel1_t = channel_t;
132 using channel2_t = std::uint8_t; // duplicates only one of fixture::channel_integer_types
133 gil::channel_minus_t<channel1_t, channel2_t, channel1_t> f;
134 BOOST_TEST_EQ(f(0, 0), channel1_t(0));
135 BOOST_TEST_EQ(f(100, 27), channel_t(73));
136 }
137 {
138 using channel1_t = std::uint8_t; // duplicates only one of fixture::channel_integer_types
139 using channel2_t = channel_t;
140 gil::channel_minus_t<channel1_t, channel2_t, channel2_t> f;
141 BOOST_TEST_EQ(f(0, 0), channel2_t(0));
142 BOOST_TEST_EQ(f(100, 27), channel_t(73));
143 }
144 }
runtest_minus_integer_mixed_types145 static void run()
146 {
147 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_minus_integer_mixed_types{});
148 }
149 };
150
151 struct test_multiplies_integer_same_types
152 {
153 template <typename Channel>
operator ()test_multiplies_integer_same_types154 void operator()(Channel const&)
155 {
156 using channel_t = Channel;
157 gil::channel_multiplies_t<channel_t, channel_t, channel_t> f;
158 BOOST_TEST_EQ(f(0, 0), channel_t(0));
159 BOOST_TEST_EQ(f(1, 1), channel_t(1));
160 BOOST_TEST_EQ(f(4, 2), channel_t(8));
161 }
runtest_multiplies_integer_same_types162 static void run()
163 {
164 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_multiplies_integer_same_types{});
165 }
166 };
167
168 struct test_multiplies_integer_mixed_types
169 {
170 template <typename Channel>
operator ()test_multiplies_integer_mixed_types171 void operator()(Channel const&)
172 {
173 using channel_t = Channel;
174 {
175 using channel1_t = channel_t;
176 using channel2_t = std::uint8_t; // duplicates only one of fixture::channel_integer_types
177 gil::channel_multiplies_t<channel1_t, channel2_t, channel1_t> f;
178 BOOST_TEST_EQ(f(0, 0), channel1_t(0));
179 BOOST_TEST_EQ(f(4, 2), channel_t(8));
180 }
181 {
182 using channel1_t = std::uint8_t; // duplicates only one of fixture::channel_integer_types
183 using channel2_t = channel_t;
184 gil::channel_multiplies_t<channel1_t, channel2_t, channel2_t> f;
185 BOOST_TEST_EQ(f(0, 0), channel2_t(0));
186 BOOST_TEST_EQ(f(4, 2), channel_t(8));
187 }
188 }
runtest_multiplies_integer_mixed_types189 static void run()
190 {
191 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_multiplies_integer_mixed_types{});
192 }
193 };
194
195 struct test_divides_integer_same_types
196 {
197 template <typename Channel>
operator ()test_divides_integer_same_types198 void operator()(Channel const&)
199 {
200 using channel_t = Channel;
201 gil::channel_divides_t<channel_t, channel_t, channel_t> f;
202 BOOST_TEST_EQ(f(0, 1), channel_t(0));
203 BOOST_TEST_EQ(f(1, 1), channel_t(1));
204 BOOST_TEST_EQ(f(4, 2), channel_t(2));
205 }
runtest_divides_integer_same_types206 static void run()
207 {
208 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_divides_integer_same_types{});
209 }
210 };
211
212 struct test_divides_integer_mixed_types
213 {
214 template <typename Channel>
operator ()test_divides_integer_mixed_types215 void operator()(Channel const&)
216 {
217 using channel_t = Channel;
218 {
219 using channel1_t = channel_t;
220 using channel2_t = std::uint8_t; // duplicates only one of fixture::channel_integer_types
221 gil::channel_divides_t<channel1_t, channel2_t, channel1_t> f;
222 BOOST_TEST_EQ(f(0, 1), channel1_t(0));
223 BOOST_TEST_EQ(f(4, 2), channel_t(2));
224 }
225 {
226 using channel1_t = std::uint8_t; // duplicates only one of fixture::channel_integer_types
227 using channel2_t = channel_t;
228 gil::channel_divides_t<channel1_t, channel2_t, channel2_t> f;
229 BOOST_TEST_EQ(f(0, 1), channel2_t(0));
230 BOOST_TEST_EQ(f(4, 2), channel_t(2));
231 }
232 }
runtest_divides_integer_mixed_types233 static void run()
234 {
235 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_divides_integer_mixed_types{});
236 }
237 };
238
239 struct test_plus_scalar_integer_same_types
240 {
241 template <typename Channel>
operator ()test_plus_scalar_integer_same_types242 void operator()(Channel const&)
243 {
244 using channel_t = Channel;
245 gil::channel_plus_scalar_t<channel_t, int, channel_t> f;
246 BOOST_TEST_EQ(f(0, 0), channel_t(0));
247 BOOST_TEST_EQ(f(100, 27), channel_t(127));
248 }
runtest_plus_scalar_integer_same_types249 static void run()
250 {
251 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_plus_scalar_integer_same_types{});
252 }
253 };
254
255 struct test_plus_scalar_integer_mixed_types
256 {
257 template <typename Channel>
operator ()test_plus_scalar_integer_mixed_types258 void operator()(Channel const&)
259 {
260 using channel_t = Channel;
261 using channel_result_t = std::uint8_t;
262 gil::channel_plus_scalar_t<channel_t, int, channel_result_t> f;
263 BOOST_TEST_EQ(f(0, 0), channel_result_t(0));
264 BOOST_TEST_EQ(f(100, 27), channel_result_t(127));
265 }
runtest_plus_scalar_integer_mixed_types266 static void run()
267 {
268 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_plus_scalar_integer_mixed_types{});
269 }
270 };
271
272 struct test_minus_scalar_integer_same_types
273 {
274 template <typename Channel>
operator ()test_minus_scalar_integer_same_types275 void operator()(Channel const&)
276 {
277 using channel_t = Channel;
278 gil::channel_minus_scalar_t<channel_t, int, channel_t> f;
279 BOOST_TEST_EQ(f(0, 0), channel_t(0));
280 BOOST_TEST_EQ(f(100, 27), channel_t(73));
281 }
runtest_minus_scalar_integer_same_types282 static void run()
283 {
284 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_minus_scalar_integer_same_types{});
285 }
286 };
287
288 struct test_minus_scalar_integer_mixed_types
289 {
290 template <typename Channel>
operator ()test_minus_scalar_integer_mixed_types291 void operator()(Channel const&)
292 {
293 using channel_t = Channel;
294 using channel_result_t = std::uint8_t;
295 gil::channel_minus_scalar_t<channel_t, int, std::uint8_t> f;
296 BOOST_TEST_EQ(f(0, 0), channel_result_t(0));
297 BOOST_TEST_EQ(f(100, 27), channel_result_t(73));
298 }
runtest_minus_scalar_integer_mixed_types299 static void run()
300 {
301 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_minus_scalar_integer_mixed_types{});
302 }
303 };
304
305 struct test_multiplies_scalar_integer_same_types
306 {
307 template <typename Channel>
operator ()test_multiplies_scalar_integer_same_types308 void operator()(Channel const&)
309 {
310 using channel_t = Channel;
311 gil::channel_multiplies_scalar_t<channel_t, channel_t, channel_t> f;
312 BOOST_TEST_EQ(f(0, 0), channel_t(0));
313 BOOST_TEST_EQ(f(1, 1), channel_t(1));
314 BOOST_TEST_EQ(f(4, 2), channel_t(8));
315 }
runtest_multiplies_scalar_integer_same_types316 static void run()
317 {
318 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_multiplies_scalar_integer_same_types{});
319 }
320 };
321
322 struct test_multiplies_scalar_integer_mixed_types
323 {
324 template <typename Channel>
operator ()test_multiplies_scalar_integer_mixed_types325 void operator()(Channel const&)
326 {
327 using channel_t = Channel;
328 using channel_result_t = std::uint8_t;
329 gil::channel_multiplies_scalar_t<channel_t, int, channel_result_t> f;
330 BOOST_TEST_EQ(f(0, 0), channel_result_t(0));
331 BOOST_TEST_EQ(f(4, 2), channel_result_t(8));
332 }
runtest_multiplies_scalar_integer_mixed_types333 static void run()
334 {
335 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_multiplies_scalar_integer_mixed_types{});
336 }
337 };
338
339 struct test_divides_scalar_integer_same_types
340 {
341 template <typename Channel>
operator ()test_divides_scalar_integer_same_types342 void operator()(Channel const&)
343 {
344 using channel_t = Channel;
345 gil::channel_divides_scalar_t<channel_t, channel_t, channel_t> f;
346 BOOST_TEST_EQ(f(0, 1), channel_t(0));
347 BOOST_TEST_EQ(f(1, 1), channel_t(1));
348 BOOST_TEST_EQ(f(4, 2), channel_t(2));
349 }
runtest_divides_scalar_integer_same_types350 static void run()
351 {
352 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_divides_scalar_integer_same_types{});
353 }
354 };
355
356 struct test_divides_scalar_integer_mixed_types
357 {
358 template <typename Channel>
operator ()test_divides_scalar_integer_mixed_types359 void operator()(Channel const&)
360 {
361 using channel_t = Channel;
362 using channel_result_t = std::uint8_t; // duplicates only one of fixture::channel_integer_types
363 gil::channel_divides_scalar_t<channel_t, int, channel_result_t> f;
364 BOOST_TEST_EQ(f(0, 1), channel_t(0));
365 BOOST_TEST_EQ(f(4, 2), channel_t(2));
366 }
runtest_divides_scalar_integer_mixed_types367 static void run()
368 {
369 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_divides_scalar_integer_mixed_types{});
370 }
371 };
372
373 struct test_halves_integer_same_types
374 {
375 template <typename Channel>
operator ()test_halves_integer_same_types376 void operator()(Channel const&)
377 {
378 using channel_t = Channel;
379 gil::channel_halves_t<channel_t> f;
380 {
381 channel_t c(0);
382 f(c);
383 BOOST_TEST_EQ(c, channel_t(0));
384 }
385 {
386 channel_t c(2);
387 f(c);
388 BOOST_TEST_EQ(c, channel_t(1));
389 }
390 {
391 channel_t c(4);
392 f(c);
393 BOOST_TEST_EQ(c, channel_t(2));
394 }
395 }
runtest_halves_integer_same_types396 static void run()
397 {
398 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_halves_integer_same_types{});
399 }
400 };
401
402 struct test_zeros_integer_same_types
403 {
404 template <typename Channel>
operator ()test_zeros_integer_same_types405 void operator()(Channel const&)
406 {
407 using channel_t = Channel;
408 gil::channel_zeros_t<channel_t> f;
409 {
410 channel_t c(0);
411 f(c);
412 BOOST_TEST_EQ(c, channel_t(0));
413 }
414 {
415 channel_t c(2);
416 f(c);
417 BOOST_TEST_EQ(c, channel_t(0));
418 }
419 {
420 channel_t c(4);
421 f(c);
422 BOOST_TEST_EQ(c, channel_t(0));
423 }
424 }
runtest_zeros_integer_same_types425 static void run()
426 {
427 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_zeros_integer_same_types{});
428 }
429 };
430
431 struct test_assigns_integer_same_types
432 {
433 template <typename Channel>
operator ()test_assigns_integer_same_types434 void operator()(Channel const&)
435 {
436 using channel_t = Channel;
437 gil::channel_assigns_t<channel_t, channel_t> f;
438 {
439 channel_t c1(10);
440 channel_t c2(20);
441 f(c1, c2);
442 BOOST_TEST_EQ(c2, c1);
443 }
444 }
runtest_assigns_integer_same_types445 static void run()
446 {
447 boost::mp11::mp_for_each<fixture::channel_integer_types>(test_assigns_integer_same_types{});
448 }
449 };
450
main()451 int main()
452 {
453 test_plus_integer_same_types::run();
454 test_plus_integer_mixed_types::run();
455 test_plus_integer_signed_types_with_overflow::run();
456 test_plus_integer_unsigned_types_with_wraparound::run();
457
458 test_minus_integer_same_types::run();
459 test_minus_integer_mixed_types::run();
460
461 test_multiplies_integer_same_types::run();
462 test_multiplies_integer_mixed_types::run();
463
464 test_divides_integer_same_types::run();
465 test_divides_integer_mixed_types::run();
466
467 test_plus_scalar_integer_same_types::run();
468 test_plus_scalar_integer_mixed_types::run();
469
470 test_minus_scalar_integer_same_types::run();
471 test_minus_scalar_integer_mixed_types::run();
472
473 test_multiplies_scalar_integer_same_types::run();
474 test_multiplies_scalar_integer_mixed_types::run();
475
476 test_divides_scalar_integer_same_types::run();
477 test_divides_scalar_integer_mixed_types::run();
478
479 test_halves_integer_same_types::run();
480 test_zeros_integer_same_types::run();
481 test_assigns_integer_same_types::run();
482
483 return ::boost::report_errors();
484 }
485