1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2015, Oracle and/or its affiliates.
5 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
10 #ifndef BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP
11 #define BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP
13 // For now deactivate the use of multiprecision integers
14 // TODO: activate it later
15 #define BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER
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>
28 #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
29 #include <boost/multiprecision/cpp_int.hpp>
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>
38 namespace boost { namespace geometry
41 #ifndef DOXYGEN_NO_DETAIL
42 namespace detail { namespace promote_integral
45 // meta-function that returns the bit size of a type
49 bool IsFundamental = boost::is_fundamental<T>::type::value
55 // for fundamental types, just return CHAR_BIT * sizeof(T)
57 struct bit_size<T, true>
58 : boost::mpl::size_t<(CHAR_BIT * sizeof(T))>
62 #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
63 // partial specialization for cpp_int
68 boost::multiprecision::cpp_integer_type SignType,
69 boost::multiprecision::cpp_int_check_type Checked,
71 boost::multiprecision::expression_template_option ExpressionTemplates
75 boost::multiprecision::number
77 boost::multiprecision::cpp_int_backend
79 MinSize, MaxSize, SignType, Checked, Allocator
84 > : boost::mpl::size_t<MaxSize>
86 #endif // BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER
96 struct promote_to_larger
98 typedef typename boost::mpl::deref<Iterator>::type current_type;
100 typedef typename boost::mpl::if_c
102 (bit_size<current_type>::type::value >= MinSize),
104 typename promote_to_larger
107 typename boost::mpl::next<Iterator>::type,
114 // The following specialization is required to finish the loop over
116 template <typename T, typename EndIterator, std::size_t MinSize>
117 struct promote_to_larger<T, EndIterator, EndIterator, MinSize>
119 // if promotion fails, keep the number T
120 // (and cross fingers that overflow will not occur)
124 }} // namespace detail::promote_integral
125 #endif // DOXYGEN_NO_DETAIL
130 \brief Meta-function to define an integral type with size
131 than is (roughly) twice the bit size of T
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.
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.
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
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.
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".
154 If the macro BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER is not
155 defined, boost's multiprecision integer cpp_int<> is used as a
158 If BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER is defined and an
159 appropriate type cannot be detected, the input type is returned as is.
161 Finally, if the passed type is either a floating-point type or a
162 user-defined type it is returned as is.
164 \note boost::long_long_type and boost::ulong_long_type are
165 considered only if the macro BOOST_HAS_LONG_LONG is defined
167 \note boost::int128_type and boost::uint128_type are considered
168 only if the macros BOOST_HAS_INT128 and BOOST_GEOMETRY_ENABLE_INT128
174 bool PromoteUnsignedToUnsigned = false,
175 bool UseCheckedInteger = false,
176 bool IsIntegral = boost::is_integral<T>::type::value
178 class promote_integral
181 static bool const is_unsigned = boost::is_unsigned<T>::type::value;
183 typedef detail::promote_integral::bit_size<T> bit_size_type;
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
190 boost::integral_constant
192 boost::multiprecision::cpp_int_check_type,
193 boost::multiprecision::checked
195 boost::integral_constant
197 boost::multiprecision::cpp_int_check_type,
198 boost::multiprecision::unchecked
200 >::type check_policy_type;
202 // Meta-function to get the multiprecision integer type for the
203 // given size and sign type (signed/unsigned)
207 boost::multiprecision::cpp_integer_type SignType
209 struct multiprecision_integer_type
211 typedef boost::multiprecision::number
213 boost::multiprecision::cpp_int_backend
218 check_policy_type::value,
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
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
234 (PromoteUnsignedToUnsigned && is_unsigned),
235 boost::mpl::size_t<(2 * bit_size_type::value)>,
236 typename boost::mpl::if_c
239 boost::mpl::size_t<(2 * bit_size_type::value + 1)>,
240 boost::mpl::size_t<(2 * bit_size_type::value - 1)>
242 >::type min_bit_size_type;
244 // Define the list of signed integral types we are going to use
246 typedef boost::mpl::list
249 #if defined(BOOST_HAS_LONG_LONG)
250 , boost::long_long_type
252 #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128)
255 #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
256 , typename multiprecision_integer_type
258 min_bit_size_type::value,
259 boost::multiprecision::signed_magnitude
262 > signed_integral_types;
264 // Define the list of unsigned integral types we are going to use
266 typedef boost::mpl::list
268 unsigned short, unsigned int, unsigned long, std::size_t
269 #if defined(BOOST_HAS_LONG_LONG)
270 , boost::ulong_long_type
272 #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128)
273 , boost::uint128_type
275 #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER)
276 , typename multiprecision_integer_type
278 min_bit_size_type::value,
279 boost::multiprecision::unsigned_magnitude
282 > unsigned_integral_types;
284 // Define the list of integral types that will be used for
285 // promotion (depending in whether we was to promote unsigned to
287 typedef typename boost::mpl::if_c
289 (is_unsigned && PromoteUnsignedToUnsigned),
290 unsigned_integral_types,
291 signed_integral_types
292 >::type integral_types;
295 typedef typename detail::promote_integral::promote_to_larger
298 typename boost::mpl::begin<integral_types>::type,
299 typename boost::mpl::end<integral_types>::type,
300 min_bit_size_type::value
305 template <typename T, bool PromoteUnsignedToUnsigned, bool UseCheckedInteger>
306 class promote_integral
308 T, PromoteUnsignedToUnsigned, UseCheckedInteger, false
316 }} // namespace boost::geometry
318 #endif // BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP