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