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