promote_integral.hpp 6.0 KB

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