promote_integral.hpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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 include guards
  13. // - Remove support for boost::multiprecision types
  14. // - Remove support for 128-bit integer types
  15. //
  16. #ifndef BOOST_GIL_PROMOTE_INTEGRAL_HPP
  17. #define BOOST_GIL_PROMOTE_INTEGRAL_HPP
  18. #include <boost/mpl/begin.hpp>
  19. #include <boost/mpl/deref.hpp>
  20. #include <boost/mpl/end.hpp>
  21. #include <boost/mpl/list.hpp>
  22. #include <boost/mpl/next.hpp>
  23. #include <climits>
  24. #include <cstddef>
  25. #include <type_traits>
  26. namespace boost { namespace gil
  27. {
  28. namespace detail { namespace promote_integral
  29. {
  30. // meta-function that returns the bit size of a type
  31. template
  32. <
  33. typename T,
  34. bool IsFundamental = std::is_fundamental<T>::value
  35. >
  36. struct bit_size {};
  37. // for fundamental types, just return CHAR_BIT * sizeof(T)
  38. template <typename T>
  39. struct bit_size<T, true> : std::integral_constant<std::size_t, (CHAR_BIT * sizeof(T))> {};
  40. template
  41. <
  42. typename T,
  43. typename Iterator,
  44. typename EndIterator,
  45. std::size_t MinSize
  46. >
  47. struct promote_to_larger
  48. {
  49. using current_type = typename boost::mpl::deref<Iterator>::type;
  50. using type = typename std::conditional
  51. <
  52. (bit_size<current_type>::value >= MinSize),
  53. current_type,
  54. typename promote_to_larger
  55. <
  56. T,
  57. typename boost::mpl::next<Iterator>::type,
  58. EndIterator,
  59. MinSize
  60. >::type
  61. >::type;
  62. };
  63. // The following specialization is required to finish the loop over
  64. // all list elements
  65. template <typename T, typename EndIterator, std::size_t MinSize>
  66. struct promote_to_larger<T, EndIterator, EndIterator, MinSize>
  67. {
  68. // if promotion fails, keep the number T
  69. // (and cross fingers that overflow will not occur)
  70. using type = T;
  71. };
  72. }} // namespace detail::promote_integral
  73. /*!
  74. \brief Meta-function to define an integral type with size
  75. than is (roughly) twice the bit size of T
  76. \ingroup utility
  77. \details
  78. This meta-function tries to promote the fundamental integral type T
  79. to a another integral type with size (roughly) twice the bit size of T.
  80. To do this, two times the bit size of T is tested against the bit sizes of:
  81. short, int, long, boost::long_long_type, boost::int128_t
  82. and the one that first matches is chosen.
  83. For unsigned types the bit size of T is tested against the bit
  84. sizes of the types above, if T is promoted to a signed type, or
  85. the bit sizes of
  86. unsigned short, unsigned int, unsigned long, std::size_t,
  87. boost::ulong_long_type, boost::uint128_t
  88. if T is promoted to an unsigned type.
  89. By default an unsigned type is promoted to a signed type.
  90. This behavior is controlled by the PromoteUnsignedToUnsigned
  91. boolean template parameter, whose default value is "false".
  92. To promote an unsigned type to an unsigned type set the value of
  93. this template parameter to "true".
  94. Finally, if the passed type is either a floating-point type or a
  95. user-defined type it is returned as is.
  96. \note boost::long_long_type and boost::ulong_long_type are
  97. considered only if the macro BOOST_HAS_LONG_LONG is defined
  98. */
  99. template
  100. <
  101. typename T,
  102. bool PromoteUnsignedToUnsigned = false,
  103. bool UseCheckedInteger = false,
  104. bool IsIntegral = std::is_integral<T>::value
  105. >
  106. class promote_integral
  107. {
  108. private:
  109. static bool const is_unsigned = std::is_unsigned<T>::value;
  110. using bit_size_type = detail::promote_integral::bit_size<T>;
  111. // Define the minimum size (in bits) needed for the promoted type
  112. // If T is the input type and P the promoted type, then the
  113. // minimum number of bits for P are (below b stands for the number
  114. // of bits of T):
  115. // * if T is unsigned and P is unsigned: 2 * b
  116. // * if T is signed and P is signed: 2 * b - 1
  117. // * if T is unsigned and P is signed: 2 * b + 1
  118. using min_bit_size_type = typename std::conditional
  119. <
  120. (PromoteUnsignedToUnsigned && is_unsigned),
  121. std::integral_constant<std::size_t, (2 * bit_size_type::value)>,
  122. typename std::conditional
  123. <
  124. is_unsigned,
  125. std::integral_constant<std::size_t, (2 * bit_size_type::value + 1)>,
  126. std::integral_constant<std::size_t, (2 * bit_size_type::value - 1)>
  127. >::type
  128. >::type;
  129. // Define the list of signed integral types we are going to use
  130. // for promotion
  131. using signed_integral_types = boost::mpl::list
  132. <
  133. short, int, long
  134. #if defined(BOOST_HAS_LONG_LONG)
  135. , boost::long_long_type
  136. #endif
  137. >;
  138. // Define the list of unsigned integral types we are going to use
  139. // for promotion
  140. using unsigned_integral_types = boost::mpl::list
  141. <
  142. unsigned short, unsigned int, unsigned long, std::size_t
  143. #if defined(BOOST_HAS_LONG_LONG)
  144. , boost::ulong_long_type
  145. #endif
  146. >;
  147. // Define the list of integral types that will be used for
  148. // promotion (depending in whether we was to promote unsigned to
  149. // unsigned or not)
  150. using integral_types = typename std::conditional
  151. <
  152. (is_unsigned && PromoteUnsignedToUnsigned),
  153. unsigned_integral_types,
  154. signed_integral_types
  155. >::type;
  156. public:
  157. using type = typename detail::promote_integral::promote_to_larger
  158. <
  159. T,
  160. typename boost::mpl::begin<integral_types>::type,
  161. typename boost::mpl::end<integral_types>::type,
  162. min_bit_size_type::value
  163. >::type;
  164. };
  165. template <typename T, bool PromoteUnsignedToUnsigned, bool UseCheckedInteger>
  166. class promote_integral
  167. <
  168. T, PromoteUnsignedToUnsigned, UseCheckedInteger, false
  169. >
  170. {
  171. public:
  172. using type = T;
  173. };
  174. }} // namespace boost::gil
  175. #endif // BOOST_GIL_PROMOTE_INTEGRAL_HPP