]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/util/promote_integral.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / geometry / util / promote_integral.hpp
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