promote_integral.cpp 16 KB

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