• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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