promote_integral.hpp 9.5 KB

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