promote_integral.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2015-2020, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  4. // Contributed and/or modified by Adam Wulkiewicz, 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_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP
  8. #define BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP
  9. // For now deactivate the use of multiprecision integers
  10. // TODO: activate it later
  11. #define BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER
  12. #include <climits>
  13. #include <cstddef>
  14. #include <type_traits>
  15. #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
  16. #include <boost/multiprecision/cpp_int.hpp>
  17. #endif
  18. namespace boost { namespace geometry
  19. {
  20. #ifndef DOXYGEN_NO_DETAIL
  21. namespace detail { namespace promote_integral
  22. {
  23. // meta-function that returns the bit size of a type
  24. template
  25. <
  26. typename T,
  27. bool IsFundamental = std::is_fundamental<T>::value
  28. >
  29. struct bit_size
  30. {};
  31. // for fundamental types, just return CHAR_BIT * sizeof(T)
  32. template <typename T>
  33. struct bit_size<T, true>
  34. : std::integral_constant<std::size_t, (CHAR_BIT * sizeof(T))>
  35. {};
  36. #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
  37. // partial specialization for cpp_int
  38. template
  39. <
  40. unsigned MinSize,
  41. unsigned MaxSize,
  42. boost::multiprecision::cpp_integer_type SignType,
  43. boost::multiprecision::cpp_int_check_type Checked,
  44. typename Allocator,
  45. boost::multiprecision::expression_template_option ExpressionTemplates
  46. >
  47. struct bit_size
  48. <
  49. boost::multiprecision::number
  50. <
  51. boost::multiprecision::cpp_int_backend
  52. <
  53. MinSize, MaxSize, SignType, Checked, Allocator
  54. >,
  55. ExpressionTemplates
  56. >,
  57. false
  58. >
  59. : std::integral_constant<std::size_t, MaxSize>
  60. {};
  61. #endif // BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER
  62. template <typename T, std::size_t MinSize, typename ...Ts>
  63. struct promote_to_larger
  64. {
  65. // if promotion fails, keep the number T
  66. // (and cross fingers that overflow will not occur)
  67. typedef T type;
  68. };
  69. template <typename T, std::size_t MinSize, typename CurrentT, typename ...Ts>
  70. struct promote_to_larger<T, MinSize, CurrentT, Ts...>
  71. {
  72. typedef std::conditional_t
  73. <
  74. (bit_size<CurrentT>::value >= MinSize),
  75. CurrentT,
  76. typename promote_to_larger<T, MinSize, Ts...>::type
  77. > type;
  78. };
  79. template <typename ...Ts>
  80. struct integral_types {};
  81. template <typename T, std::size_t MinSize, typename ...Ts>
  82. struct promote_to_larger<T, MinSize, integral_types<Ts...>>
  83. : promote_to_larger<T, MinSize, Ts...>
  84. {};
  85. }} // namespace detail::promote_integral
  86. #endif // DOXYGEN_NO_DETAIL
  87. /*!
  88. \brief Meta-function to define an integral type with size
  89. than is (roughly) twice the bit size of T
  90. \ingroup utility
  91. \details
  92. This meta-function tries to promote the fundamental integral type T
  93. to a another integral type with size (roughly) twice the bit size of T.
  94. To do this, two times the bit size of T is tested against the bit sizes of:
  95. short, int, long, long long, boost::int128_t
  96. and the one that first matches is chosen.
  97. For unsigned types the bit size of T is tested against the bit
  98. sizes of the types above, if T is promoted to a signed type, or
  99. the bit sizes of
  100. unsigned short, unsigned int, unsigned long, std::size_t,
  101. unsigned long long, boost::uint128_t
  102. if T is promoted to an unsigned type.
  103. By default an unsigned type is promoted to a signed type.
  104. This behavior is controlled by the PromoteUnsignedToUnsigned
  105. boolean template parameter, whose default value is "false".
  106. To promote an unsigned type to an unsigned type set the value of
  107. this template parameter to "true".
  108. If the macro BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER is not
  109. defined, boost's multiprecision integer cpp_int<> is used as a
  110. last resort.
  111. If BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER is defined and an
  112. appropriate type cannot be detected, the input type is returned as is.
  113. Finally, if the passed type is either a floating-point type or a
  114. user-defined type it is returned as is.
  115. \note boost::int128_type and boost::uint128_type are considered
  116. only if the macros BOOST_HAS_INT128 and BOOST_GEOMETRY_ENABLE_INT128
  117. are defined
  118. */
  119. template
  120. <
  121. typename T,
  122. bool PromoteUnsignedToUnsigned = false,
  123. bool UseCheckedInteger = false,
  124. bool IsIntegral = std::is_integral<T>::value
  125. >
  126. class promote_integral
  127. {
  128. private:
  129. static bool const is_unsigned = std::is_unsigned<T>::value;
  130. typedef detail::promote_integral::bit_size<T> bit_size_type;
  131. #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
  132. // Define the proper check policy for the multiprecision integer
  133. typedef std::conditional_t
  134. <
  135. UseCheckedInteger,
  136. std::integral_constant
  137. <
  138. boost::multiprecision::cpp_int_check_type,
  139. boost::multiprecision::checked
  140. >,
  141. std::integral_constant
  142. <
  143. boost::multiprecision::cpp_int_check_type,
  144. boost::multiprecision::unchecked
  145. >
  146. > check_policy_type;
  147. // Meta-function to get the multiprecision integer type for the
  148. // given size and sign type (signed/unsigned)
  149. template
  150. <
  151. unsigned int Size,
  152. boost::multiprecision::cpp_integer_type SignType
  153. >
  154. struct multiprecision_integer_type
  155. {
  156. typedef boost::multiprecision::number
  157. <
  158. boost::multiprecision::cpp_int_backend
  159. <
  160. Size,
  161. Size,
  162. SignType,
  163. check_policy_type::value,
  164. void
  165. >
  166. > type;
  167. };
  168. #endif
  169. // Define the minimum size (in bits) needed for the promoted type
  170. // If T is the input type and P the promoted type, then the
  171. // minimum number of bits for P are (below b stands for the number
  172. // of bits of T):
  173. // * if T is unsigned and P is unsigned: 2 * b
  174. // * if T is signed and P is signed: 2 * b - 1
  175. // * if T is unsigned and P is signed: 2 * b + 1
  176. typedef std::conditional_t
  177. <
  178. (PromoteUnsignedToUnsigned && is_unsigned),
  179. std::integral_constant<std::size_t, (2 * bit_size_type::value)>,
  180. std::conditional_t
  181. <
  182. is_unsigned,
  183. std::integral_constant<std::size_t, (2 * bit_size_type::value + 1)>,
  184. std::integral_constant<std::size_t, (2 * bit_size_type::value - 1)>
  185. >
  186. > min_bit_size_type;
  187. // Define the list of signed integral types we are going to use
  188. // for promotion
  189. typedef detail::promote_integral::integral_types
  190. <
  191. short,
  192. int,
  193. long,
  194. long long
  195. #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128)
  196. , boost::int128_type
  197. #endif
  198. #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
  199. , typename multiprecision_integer_type
  200. <
  201. min_bit_size_type::value,
  202. boost::multiprecision::signed_magnitude
  203. >::type
  204. #endif
  205. > signed_integral_types;
  206. // Define the list of unsigned integral types we are going to use
  207. // for promotion
  208. typedef detail::promote_integral::integral_types
  209. <
  210. unsigned short,
  211. unsigned int,
  212. unsigned long,
  213. std::size_t,
  214. unsigned long long
  215. #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128)
  216. , boost::uint128_type
  217. #endif
  218. #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
  219. , typename multiprecision_integer_type
  220. <
  221. min_bit_size_type::value,
  222. boost::multiprecision::unsigned_magnitude
  223. >::type
  224. #endif
  225. > unsigned_integral_types;
  226. // Define the list of integral types that will be used for
  227. // promotion (depending in whether we was to promote unsigned to
  228. // unsigned or not)
  229. typedef std::conditional_t
  230. <
  231. (is_unsigned && PromoteUnsignedToUnsigned),
  232. unsigned_integral_types,
  233. signed_integral_types
  234. > integral_types;
  235. public:
  236. typedef typename detail::promote_integral::promote_to_larger
  237. <
  238. T,
  239. min_bit_size_type::value,
  240. integral_types
  241. >::type type;
  242. };
  243. template <typename T, bool PromoteUnsignedToUnsigned, bool UseCheckedInteger>
  244. class promote_integral
  245. <
  246. T, PromoteUnsignedToUnsigned, UseCheckedInteger, false
  247. >
  248. {
  249. public:
  250. typedef T type;
  251. };
  252. }} // namespace boost::geometry
  253. #endif // BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP