1// Boost.Geometry (aka GGL, Generic Geometry Library)
2// Unit Test
3
4// Copyright (c) 2015-2021, Oracle and/or its affiliates.
5// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
6// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
7
8// Licensed under the Boost Software License version 1.0.
9// http://www.boost.org/users/license.html
10
11#ifndef BOOST_TEST_MODULE
12#define BOOST_TEST_MODULE test_promote_integral
13#endif
14
15#include <climits>
16#include <cstddef>
17#include <algorithm>
18#include <limits>
19#include <iostream>
20#include <string>
21#include <sstream>
22
23#include <boost/test/included/unit_test.hpp>
24
25#include <boost/config.hpp>
26
27#include <geometry_test_common.hpp>
28
29#include <boost/geometry/util/condition.hpp>
30#include <boost/geometry/util/promote_integral.hpp>
31
32#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
33#include <boost/multiprecision/cpp_int.hpp>
34#endif
35
36#if defined(BOOST_GEOMETRY_TEST_DEBUG)
37#if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128)
38void print_uint128_t(std::ostream& os, boost::uint128_type i)
39{
40 if (i == 0)
41 {
42 os << "0";
43 return;
44 }
45
46 std::stringstream stream;
47 while (i > 0)
48 {
49 stream << static_cast<int>(i % 10);
50 i /= 10;
51 }
52 std::string str = stream.str();
53 std::reverse(str.begin(), str.end());
54 os << str;
55}
56
57std::ostream& operator<<(std::ostream& os, boost::int128_type i)
58{
59 if (i < 0)
60 {
61 os << "-";
62 print_uint128_t(os, static_cast<boost::uint128_type>(-i));
63 }
64 else
65 {
66 print_uint128_t(os, static_cast<boost::uint128_type>(i));
67 }
68 return os;
69}
70
71std::ostream& operator<<(std::ostream& os, boost::uint128_type i)
72{
73 print_uint128_t(os, i);
74 return os;
75}
76#endif // BOOST_HAS_INT128 && BOOST_GEOMETRY_ENABLE_INT128
77#endif // BOOST_GEOMETRY_TEST_DEBUG
78
79namespace bg = boost::geometry;
80
81template
82<
83 typename T,
84 bool Signed = std::is_fundamental<T>::value
85 && ! std::is_unsigned<T>::value
86>
87struct absolute_value
88{
89 static inline T apply(T const& t)
90 {
91 return t < 0 ? -t : t;
92 }
93};
94
95template <typename T>
96struct absolute_value<T, false>
97{
98 static inline T apply(T const& t)
99 {
100 return t;
101 }
102};
103
104
105
106template
107<
108 typename Integral,
109 typename Promoted,
110 bool Signed = ! std::is_unsigned<Promoted>::value
111>
112struct test_max_values
113{
114 static inline void apply()
115 {
116 Promoted min_value = (std::numeric_limits<Integral>::min)();
117 min_value *= min_value;
118 BOOST_CHECK(absolute_value<Promoted>::apply(min_value) == min_value);
119 Promoted max_value = (std::numeric_limits<Integral>::max)();
120 max_value *= max_value;
121 BOOST_CHECK(absolute_value<Promoted>::apply(max_value) == max_value);
122
123#ifdef BOOST_GEOMETRY_TEST_DEBUG
124 std::cout << "integral min_value^2: " << min_value << std::endl;
125 std::cout << "promoted max_value: "
126 << (std::numeric_limits<Promoted>::max)() << std::endl;
127#endif
128 }
129};
130
131template <typename Integral, typename Promoted>
132struct test_max_values<Integral, Promoted, false>
133{
134 static inline void apply()
135 {
136 Promoted max_value = (std::numeric_limits<Integral>::max)();
137 Promoted max_value_sqr = max_value * max_value;
138 BOOST_CHECK(max_value_sqr < (std::numeric_limits<Promoted>::max)()
139 &&
140 max_value_sqr > max_value);
141
142#ifdef BOOST_GEOMETRY_TEST_DEBUG
143 std::cout << "integral max_value^2: " << max_value_sqr << std::endl;
144 std::cout << "promoted max_value: "
145 << (std::numeric_limits<Promoted>::max)() << std::endl;
146#endif
147 }
148};
149
150
151// helper function that returns the bit size of a type
152template
153<
154 typename T,
155 bool IsFundamental = std::is_fundamental<T>::value
156>
157struct bit_size_impl : std::integral_constant<std::size_t, 0>
158{};
159
160template <typename T>
161struct bit_size_impl<T, true> : bg::detail::promote_integral::bit_size<T>::type
162{};
163
164#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
165template
166<
167 typename Backend,
168 boost::multiprecision::expression_template_option ExpressionTemplates
169>
170struct bit_size_impl
171 <
172 boost::multiprecision::number<Backend, ExpressionTemplates>,
173 false
174 > : bg::detail::promote_integral::bit_size
175 <
176 boost::multiprecision::number<Backend, ExpressionTemplates>
177 >
178{};
179#endif
180
181
182template <typename T>
183std::size_t bit_size()
184{
185 return bit_size_impl<T>::type::value;
186}
187
188template <bool PromoteUnsignedToUnsigned>
189struct test_promote_integral
190{
191 template <typename Type, typename ExpectedPromotedType>
192 static inline void apply(std::string const& case_id)
193 {
194 typedef typename bg::promote_integral
195 <
196 Type, PromoteUnsignedToUnsigned
197 >::type promoted_integral_type;
198
199 bool const same_types = std::is_same
200 <
201 promoted_integral_type, ExpectedPromotedType
202 >::value;
203
204 BOOST_CHECK_MESSAGE(same_types,
205 "case ID: " << case_id
206 << "input type: " << typeid(Type).name()
207 << "; detected: "
208 << typeid(promoted_integral_type).name()
209 << "; expected: "
210 << typeid(ExpectedPromotedType).name());
211
212 if (BOOST_GEOMETRY_CONDITION((! std::is_same
213 <
214 Type, promoted_integral_type
215 >::value)))
216 {
217 test_max_values<Type, promoted_integral_type>::apply();
218 }
219
220#ifdef BOOST_GEOMETRY_TEST_DEBUG
221 std::cout << "case ID: " << case_id << std::endl
222 << "type : " << typeid(Type).name()
223 << ", sizeof (bits): " << bit_size<Type>()
224 << ", min value: "
225 << (std::numeric_limits<Type>::min)()
226 << ", max value: "
227 << (std::numeric_limits<Type>::max)()
228 << std::endl;
229 std::cout << "detected promoted type : "
230 << typeid(promoted_integral_type).name()
231 << ", sizeof (bits): " << bit_size<promoted_integral_type>()
232 << ", min value: "
233 << (std::numeric_limits<promoted_integral_type>::min)()
234 << ", max value: "
235 << (std::numeric_limits<promoted_integral_type>::max)()
236 << std::endl;
237 std::cout << "expected promoted type : "
238 << typeid(ExpectedPromotedType).name()
239 << ", sizeof (bits): " << bit_size<ExpectedPromotedType>()
240 << ", min value: "
241 << (std::numeric_limits<ExpectedPromotedType>::min)()
242 << ", max value: "
243 << (std::numeric_limits<ExpectedPromotedType>::max)()
244 << std::endl;
245 std::cout << std::endl;
246#endif
247 }
248};
249
250template
251<
252 typename T,
253 bool PromoteUnsignedToUnsigned = false,
254 bool IsSigned = ! std::is_unsigned<T>::value
255>
256struct test_promotion
257{
258 static inline void apply(std::string case_id)
259 {
260#ifdef BOOST_GEOMETRY_TEST_DEBUG
261 std::cout << "*** "
262 << (IsSigned ? "signed" : "unsigned")
263 << " -> signed ***" << std::endl;
264#endif
265
266 typedef test_promote_integral<PromoteUnsignedToUnsigned> tester;
267
268 case_id += (PromoteUnsignedToUnsigned ? "-t" : "-f");
269
270 std::size_t min_size = 2 * bit_size<T>() - 1;
271 if (BOOST_GEOMETRY_CONDITION(! IsSigned))
272 {
273 min_size += 2;
274 }
275
276#ifdef BOOST_GEOMETRY_TEST_DEBUG
277 std::cout << "min size: " << min_size << std::endl;
278#endif
279
280 if (bit_size<short>() >= min_size)
281 {
282 tester::template apply<T, short>(case_id);
283 }
284 else if (bit_size<int>() >= min_size)
285 {
286 tester::template apply<T, int>(case_id);
287 }
288 else if (bit_size<long>() >= min_size)
289 {
290 tester::template apply<T, long>(case_id);
291 }
292 else if (bit_size<long long>() >= min_size)
293 {
294 tester::template apply<T, long long>(case_id);
295 }
296#if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128)
297 else if (bit_size<boost::int128_type>() >= min_size)
298 {
299 tester::template apply<T, boost::int128_type>(case_id);
300 }
301#endif
302 else
303 {
304#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
305 namespace bm = boost::multiprecision;
306 typedef bm::number
307 <
308 bm::cpp_int_backend
309 <
310 2 * CHAR_BIT * sizeof(T) + (IsSigned ? -1 : 1),
311 2 * CHAR_BIT * sizeof(T) + (IsSigned ? -1 : 1),
312 bm::signed_magnitude,
313 bm::unchecked,
314 void
315 >
316 > multiprecision_integer_type;
317
318 tester::template apply<T, multiprecision_integer_type>(case_id);
319#else
320 tester::template apply<T, T>(case_id);
321#endif
322 }
323 }
324};
325
326template <typename T>
327struct test_promotion<T, true, false>
328{
329 static inline void apply(std::string case_id)
330 {
331#ifdef BOOST_GEOMETRY_TEST_DEBUG
332 std::cout << "*** unsigned -> unsigned ***" << std::endl;
333#endif
334 case_id += "-t";
335
336 typedef test_promote_integral<true> tester;
337
338 std::size_t min_size = 2 * bit_size<T>();
339
340#ifdef BOOST_GEOMETRY_TEST_DEBUG
341 std::cout << "min size: " << min_size << std::endl;
342#endif
343
344 if (bit_size<unsigned short>() >= min_size)
345 {
346 tester::apply<T, unsigned short>(case_id);
347 }
348 else if (bit_size<unsigned int>() >= min_size)
349 {
350 tester::apply<T, unsigned int>(case_id);
351 }
352 else if (bit_size<unsigned long>() >= min_size)
353 {
354 tester::apply<T, unsigned long>(case_id);
355 }
356 else if (bit_size<std::size_t>() >= min_size)
357 {
358 tester::apply<T, std::size_t>(case_id);
359 }
360 else if (bit_size<unsigned long long>() >= min_size)
361 {
362 tester::template apply<T, unsigned long long>(case_id);
363 }
364#if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128)
365 else if (bit_size<boost::uint128_type>() >= min_size)
366 {
367 tester::template apply<T, boost::uint128_type>(case_id);
368 }
369#endif
370 else
371 {
372#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
373 namespace bm = boost::multiprecision;
374 typedef bm::number
375 <
376 bm::cpp_int_backend
377 <
378 2 * CHAR_BIT * sizeof(T),
379 2 * CHAR_BIT * sizeof(T),
380 bm::unsigned_magnitude,
381 bm::unchecked,
382 void
383 >
384 > multiprecision_integer_type;
385
386 tester::apply<T, multiprecision_integer_type>(case_id);
387#else
388 tester::apply<T, T>(case_id);
389#endif
390 }
391 }
392};
393
394
395
396BOOST_AUTO_TEST_CASE( test_char )
397{
398 test_promotion<char>::apply(case_id: "char");
399 test_promotion<char, true>::apply(case_id: "char");
400 test_promotion<signed char>::apply(case_id: "schar");
401 test_promotion<signed char, true>::apply(case_id: "schar");
402 test_promotion<unsigned char>::apply(case_id: "uchar");
403 test_promotion<unsigned char, true>::apply(case_id: "uchar");
404}
405
406BOOST_AUTO_TEST_CASE( test_short )
407{
408 test_promotion<short>::apply(case_id: "short");
409 test_promotion<short, true>::apply(case_id: "short");
410 test_promotion<unsigned short>::apply(case_id: "ushort");
411 test_promotion<unsigned short, true>::apply(case_id: "ushort");
412}
413
414BOOST_AUTO_TEST_CASE( test_int )
415{
416 test_promotion<int>::apply(case_id: "int");
417 test_promotion<int, true>::apply(case_id: "int");
418 test_promotion<unsigned int>::apply(case_id: "uint");
419 test_promotion<unsigned int, true>::apply(case_id: "uint");
420}
421
422BOOST_AUTO_TEST_CASE( test_long )
423{
424 test_promotion<long>::apply(case_id: "long");
425 test_promotion<long, true>::apply(case_id: "long");
426 test_promotion<unsigned long>::apply(case_id: "ulong");
427 test_promotion<unsigned long, true>::apply(case_id: "ulong");
428}
429
430BOOST_AUTO_TEST_CASE( test_std_size_t )
431{
432 test_promotion<std::size_t>::apply(case_id: "size_t");
433 test_promotion<std::size_t, true>::apply(case_id: "size_t");
434}
435
436BOOST_AUTO_TEST_CASE( test_long_long )
437{
438 test_promotion<long long>::apply(case_id: "long long");
439 test_promotion<long long, true>::apply(case_id: "long long");
440 test_promotion<unsigned long long>::apply(case_id: "ulong long");
441 test_promotion<unsigned long long, true>::apply(case_id: "ulong long");
442}
443
444#if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128)
445BOOST_AUTO_TEST_CASE( test_int128 )
446{
447 test_promotion<boost::int128_type>::apply("int128_t");
448 test_promotion<boost::int128_type, true>::apply("int128_t");
449 test_promotion<boost::uint128_type>::apply("uint128_t");
450 test_promotion<boost::uint128_type, true>::apply("uint128_t");
451}
452#endif
453
454#if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
455BOOST_AUTO_TEST_CASE( test_user_types )
456{
457 namespace bm = boost::multiprecision;
458 typedef bm::number
459 <
460 bm::cpp_int_backend
461 <
462 17,
463 17,
464 bm::signed_magnitude,
465 bm::unchecked,
466 void
467 >
468 > user_signed_type1;
469
470 typedef bm::number
471 <
472 bm::cpp_int_backend
473 <
474 17,
475 17,
476 bm::unsigned_magnitude,
477 bm::unchecked,
478 void
479 >
480 > user_unsigned_type1;
481
482 typedef bm::number
483 <
484 bm::cpp_int_backend
485 <
486 500,
487 500,
488 bm::signed_magnitude,
489 bm::unchecked,
490 void
491 >
492 > user_signed_type2;
493
494 typedef bm::number
495 <
496 bm::cpp_int_backend
497 <
498 500,
499 500,
500 bm::unsigned_magnitude,
501 bm::unchecked,
502 void
503 >
504 > user_unsigned_type2;
505
506 // for user defined number types we do not do any promotion
507 typedef test_promote_integral<true> tester1;
508 typedef test_promote_integral<false> tester2;
509 tester1::apply<user_signed_type1, user_signed_type1>("u1s");
510 tester1::apply<user_signed_type2, user_signed_type2>("u2s");
511 tester1::apply<user_unsigned_type1, user_unsigned_type1>("u1u");
512 tester1::apply<user_unsigned_type2, user_unsigned_type2>("u2u");
513
514 tester2::apply<user_signed_type1, user_signed_type1>("u1s");
515 tester2::apply<user_signed_type2, user_signed_type2>("u2s");
516 tester2::apply<user_unsigned_type1, user_unsigned_type1>("u1u");
517 tester2::apply<user_unsigned_type2, user_unsigned_type2>("u1u");
518}
519#endif
520
521BOOST_AUTO_TEST_CASE( test_floating_point )
522{
523 typedef test_promote_integral<true> tester1;
524 typedef test_promote_integral<false> tester2;
525
526 // for floating-point types we do not do any promotion
527 tester1::apply<float, float>(case_id: "fp-f");
528 tester1::apply<double, double>(case_id: "fp-d");
529 tester1::apply<long double, long double>(case_id: "fp-ld");
530
531 tester2::apply<float, float>(case_id: "fp-f");
532 tester2::apply<double, double>(case_id: "fp-d");
533 tester2::apply<long double, long double>(case_id: "fp-ld");
534}
535

source code of boost/libs/geometry/test/util/promote_integral.cpp