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