Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / gil / test / core / promote_integral.cpp
1 // Boost.GIL (Generic Image Library)
2 //
3 // Copyright (c) 2015, Oracle and/or its affiliates.
4 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
5 //
6 // Licensed under the Boost Software License version 1.0.
7 // http://www.boost.org/users/license.html
8 //
9 // Source: Boost.Geometry (aka GGL, Generic Geometry Library)
10 // Modifications: adapted for Boost.GIL
11 //  - Rename namespace boost::geometry to boost::gil
12 //  - Rename define BOOST_GEOMETRY_TEST_DEBUG to BOOST_GIL_TEST_DEBUG
13 //  - Remove use of macro BOOST_GEOMETRY_CONDITION
14 //  - Remove support for boost::multiprecision types
15 //  - Remove support for 128-bit integer types
16 //  - Update and sort includes
17 //  - Add explicit conversions to avoid warnings due to implicit integral promotions
18 //
19 // Uncomment to enable debugging output
20 //#define BOOST_GIL_TEST_DEBUG 1
21
22 #include <boost/gil/promote_integral.hpp>
23
24 #include <algorithm>
25 #include <climits>
26 #include <cstddef>
27 #ifdef BOOST_GIL_TEST_DEBUG
28 #include <iostream>
29 #endif
30 #include <limits>
31 #include <string>
32
33 #ifndef BOOST_TEST_MODULE
34 #define BOOST_TEST_MODULE test_promote_integral
35 #endif
36 #include "unit_test.hpp"
37
38 namespace bg = boost::gil;
39
40 template
41 <
42     typename T,
43     bool Signed = std::is_fundamental<T>::value && !std::is_unsigned<T>::type::value
44 >
45 struct absolute_value
46 {
47     static inline T apply(T const& t)
48     {
49         return static_cast<T>(t < 0 ? -t : t);
50     }
51 };
52
53 template <typename T>
54 struct absolute_value<T, false>
55 {
56     static inline T apply(T const& t)
57     {
58         return t;
59     }
60 };
61
62 template
63     <
64         typename Integral,
65         typename Promoted,
66         bool Signed = !std::is_unsigned<Promoted>::value
67     >
68 struct test_max_values
69 {
70     static inline void apply()
71     {
72         // Use >= where value is guaranteed to never be greater than comparator
73         // but to avoid warning: comparing floating point with == is unsafe.
74
75         Promoted min_value = (std::numeric_limits<Integral>::min)();
76         // Explicit casts to avoid warning: conversion to short int from int may alter its value
77         min_value = static_cast<Promoted>(min_value * min_value);
78         BOOST_CHECK(absolute_value<Promoted>::apply(min_value) >= min_value);
79         BOOST_CHECK(absolute_value<Promoted>::apply(min_value) <= min_value);
80         Promoted max_value = (std::numeric_limits<Integral>::max)();
81         max_value = static_cast<Promoted>(max_value * max_value);
82         BOOST_CHECK(absolute_value<Promoted>::apply(max_value) >= max_value);
83         BOOST_CHECK(absolute_value<Promoted>::apply(max_value) <= max_value);
84
85 #ifdef BOOST_GIL_TEST_DEBUG
86         std::cout << "integral min_value^2: " << min_value << std::endl;
87         std::cout << "promoted max_value:   "
88                   << (std::numeric_limits<Promoted>::max)() << std::endl;
89 #endif
90     }
91 };
92
93 template <typename Integral, typename Promoted>
94 struct test_max_values<Integral, Promoted, false>
95 {
96     static inline void apply()
97     {
98         Promoted max_value = (std::numeric_limits<Integral>::max)();
99         Promoted max_value_sqr = static_cast<Promoted>(max_value * max_value);
100         BOOST_CHECK(max_value_sqr < (std::numeric_limits<Promoted>::max)()
101                     &&
102                     max_value_sqr > max_value);
103
104 #ifdef BOOST_GIL_TEST_DEBUG
105         std::cout << "integral max_value^2: " << max_value_sqr << std::endl;
106         std::cout << "promoted max_value:   "
107                   << (std::numeric_limits<Promoted>::max)() << std::endl;
108 #endif
109     }
110 };
111
112
113 // helper function that returns the bit size of a type
114 template
115     <
116         typename T,
117         bool IsFundamental = std::is_fundamental<T>::value
118     >
119 struct bit_size_impl : std::integral_constant<std::size_t, 0>
120 {};
121
122 template <typename T>
123 struct bit_size_impl<T, true> : bg::detail::promote_integral::bit_size<T>::type
124 {};
125
126 template <typename T>
127 std::size_t bit_size()
128 {
129     return bit_size_impl<T>::value;
130 }
131
132 template <bool PromoteUnsignedToUnsigned>
133 struct test_promote_integral
134 {
135     template <typename Type, typename ExpectedPromotedType>
136     static inline void apply(std::string const& case_id)
137     {
138         using promoted_integral_type = typename bg::promote_integral
139             <
140                 Type, PromoteUnsignedToUnsigned
141             >::type;
142
143         bool const same_types = std::is_same
144             <
145                 promoted_integral_type, ExpectedPromotedType
146             >::value;
147
148         BOOST_CHECK_MESSAGE(same_types,
149                             "case ID: " << case_id
150                                         << "input type: " << typeid(Type).name()
151                                         << "; detected: "
152                                         << typeid(promoted_integral_type).name()
153                                         << "; expected: "
154                                         << typeid(ExpectedPromotedType).name());
155
156         if (!std::is_same<Type, promoted_integral_type>::value)
157         {
158             test_max_values<Type, promoted_integral_type>::apply();
159         }
160
161 #ifdef BOOST_GIL_TEST_DEBUG
162         std::cout << "case ID: " << case_id << std::endl
163                   << "type : " << typeid(Type).name()
164                   << ", sizeof (bits): " << bit_size<Type>()
165                   << ", min value: "
166                   << (std::numeric_limits<Type>::min)()
167                   << ", max value: "
168                   << (std::numeric_limits<Type>::max)()
169                   << std::endl;
170         std::cout << "detected promoted type : "
171                   << typeid(promoted_integral_type).name()
172                   << ", sizeof (bits): " << bit_size<promoted_integral_type>()
173                   << ", min value: "
174                   << (std::numeric_limits<promoted_integral_type>::min)()
175                   << ", max value: "
176                   << (std::numeric_limits<promoted_integral_type>::max)()
177                   << std::endl;
178         std::cout << "expected promoted type : "
179                   << typeid(ExpectedPromotedType).name()
180                   << ", sizeof (bits): " << bit_size<ExpectedPromotedType>()
181                   << ", min value: "
182                   << (std::numeric_limits<ExpectedPromotedType>::min)()
183                   << ", max value: "
184                   << (std::numeric_limits<ExpectedPromotedType>::max)()
185                   << std::endl;
186         std::cout << std::endl;
187 #endif
188     }
189 };
190
191 template
192         <
193                 typename T,
194                 bool PromoteUnsignedToUnsigned = false,
195                 bool IsSigned = !std::is_unsigned<T>::value
196         >
197 struct test_promotion
198 {
199     static inline void apply(std::string case_id)
200     {
201 #ifdef BOOST_GIL_TEST_DEBUG
202         std::cout << "*** "
203                   << (IsSigned ? "signed" : "unsigned")
204                   << " -> signed ***" << std::endl;
205 #endif
206
207         using tester = test_promote_integral<PromoteUnsignedToUnsigned>;
208
209         case_id += (PromoteUnsignedToUnsigned ? "-t" : "-f");
210
211         std::size_t min_size = 2 * bit_size<T>() - 1;
212         if (!IsSigned)
213         {
214             min_size += 2;
215         }
216
217 #ifdef BOOST_GIL_TEST_DEBUG
218         std::cout << "min size: " << min_size << std::endl;
219 #endif
220
221         if (bit_size<short>() >= min_size)
222         {
223             tester::template apply<T, short>(case_id);
224         }
225         else if (bit_size<int>() >= min_size)
226         {
227             tester::template apply<T, int>(case_id);
228         }
229         else if (bit_size<long>() >= min_size)
230         {
231             tester::template apply<T, long>(case_id);
232         }
233 #if defined(BOOST_HAS_LONG_LONG)
234         else if (bit_size<boost::long_long_type>() >= min_size)
235         {
236             tester::template apply<T, boost::long_long_type>(case_id);
237         }
238 #endif
239         else
240         {
241             tester::template apply<T, T>(case_id);
242         }
243     }
244 };
245
246 template <typename T>
247 struct test_promotion<T, true, false>
248 {
249     static inline void apply(std::string case_id)
250     {
251 #ifdef BOOST_GIL_TEST_DEBUG
252         std::cout << "*** unsigned -> unsigned ***" << std::endl;
253 #endif
254         case_id += "-t";
255
256         using tester = test_promote_integral<true>;
257
258         std::size_t min_size = 2 * bit_size<T>();
259
260 #ifdef BOOST_GIL_TEST_DEBUG
261         std::cout << "min size: " << min_size << std::endl;
262 #endif
263
264         if (bit_size<unsigned short>() >= min_size)
265         {
266             tester::apply<T, unsigned short>(case_id);
267         }
268         else if (bit_size<unsigned int>() >= min_size)
269         {
270             tester::apply<T, unsigned int>(case_id);
271         }
272         else if (bit_size<unsigned long>() >= min_size)
273         {
274             tester::apply<T, unsigned long>(case_id);
275         }
276         else if (bit_size<std::size_t>() >= min_size)
277         {
278             tester::apply<T, std::size_t>(case_id);
279         }
280 #if defined(BOOST_HAS_LONG_LONG)
281         else if (bit_size<boost::ulong_long_type>() >= min_size)
282         {
283             tester::template apply<T, boost::ulong_long_type>(case_id);
284         }
285 #endif
286         else
287         {
288             tester::apply<T, T>(case_id);
289         }
290     }
291 };
292
293 BOOST_AUTO_TEST_CASE( test_char )
294 {
295     test_promotion<char>::apply("char");
296     test_promotion<char, true>::apply("char");
297     test_promotion<signed char>::apply("schar");
298     test_promotion<signed char, true>::apply("schar");
299     test_promotion<unsigned char>::apply("uchar");
300     test_promotion<unsigned char, true>::apply("uchar");
301 }
302
303 BOOST_AUTO_TEST_CASE( test_short )
304 {
305     test_promotion<short>::apply("short");
306     test_promotion<short, true>::apply("short");
307     test_promotion<unsigned short>::apply("ushort");
308     test_promotion<unsigned short, true>::apply("ushort");
309 }
310
311 BOOST_AUTO_TEST_CASE( test_int )
312 {
313     test_promotion<int>::apply("int");
314     test_promotion<int, true>::apply("int");
315     test_promotion<unsigned int>::apply("uint");
316     test_promotion<unsigned int, true>::apply("uint");
317 }
318
319 BOOST_AUTO_TEST_CASE( test_long )
320 {
321     test_promotion<long>::apply("long");
322     test_promotion<long, true>::apply("long");
323     test_promotion<unsigned long>::apply("ulong");
324     test_promotion<unsigned long, true>::apply("ulong");
325 }
326
327 BOOST_AUTO_TEST_CASE( test_std_size_t )
328 {
329     test_promotion<std::size_t>::apply("size_t");
330     test_promotion<std::size_t, true>::apply("size_t");
331 }
332
333 #ifdef BOOST_HAS_LONG_LONG
334 BOOST_AUTO_TEST_CASE( test_long_long )
335 {
336     test_promotion<boost::long_long_type>::apply("long long");
337     test_promotion<boost::long_long_type, true>::apply("long long");
338     test_promotion<boost::ulong_long_type>::apply("ulong long");
339     test_promotion<boost::ulong_long_type, true>::apply("ulong long");
340 }
341 #endif
342
343 BOOST_AUTO_TEST_CASE( test_floating_point )
344 {
345     using tester1 = test_promote_integral<true>;
346     using tester2 = test_promote_integral<false>;
347
348     // for floating-point types we do not do any promotion
349     tester1::apply<float, float>("fp-f");
350     tester1::apply<double, double>("fp-d");
351     tester1::apply<long double, long double>("fp-ld");
352
353     tester2::apply<float, float>("fp-f");
354     tester2::apply<double, double>("fp-d");
355     tester2::apply<long double, long double>("fp-ld");
356 }