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