promote_integral.cpp 11 KB

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