]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/spirit/home/qi/numeric/detail/real_impl.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / spirit / home / qi / numeric / detail / real_impl.hpp
1 /*=============================================================================
2 Copyright (c) 2001-2019 Joel de Guzman
3 Copyright (c) 2001-2011 Hartmut Kaiser
4 http://spirit.sourceforge.net/
5
6 Distributed under the Boost Software License, Version 1.0. (See accompanying
7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 #ifndef BOOST_SPIRIT_QI_NUMERIC_DETAIL_REAL_IMPL_HPP
10 #define BOOST_SPIRIT_QI_NUMERIC_DETAIL_REAL_IMPL_HPP
11
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15
16 #include <cmath>
17 #include <boost/limits.hpp>
18 #include <boost/type_traits/is_same.hpp>
19 #include <boost/spirit/home/support/unused.hpp>
20 #include <boost/spirit/home/qi/detail/attributes.hpp>
21 #include <boost/spirit/home/support/detail/pow10.hpp>
22 #include <boost/integer.hpp>
23 #include <boost/assert.hpp>
24
25 #include <boost/core/cmath.hpp>
26
27 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
28 # pragma warning(push)
29 # pragma warning(disable: 4100) // 'p': unreferenced formal parameter
30 # pragma warning(disable: 4127) // conditional expression is constant
31 #endif
32
33 namespace boost { namespace spirit { namespace traits
34 {
35 using spirit::traits::pow10;
36
37 namespace detail
38 {
39 template <typename T, typename AccT>
40 void compensate_roundoff(T& n, AccT acc_n, mpl::true_)
41 {
42 // at the lowest extremes, we compensate for floating point
43 // roundoff errors by doing imprecise computation using T
44 int const comp = 10;
45 n = T((acc_n / comp) * comp);
46 n += T(acc_n % comp);
47 }
48
49 template <typename T, typename AccT>
50 void compensate_roundoff(T& n, AccT acc_n, mpl::false_)
51 {
52 // no need to compensate
53 n = acc_n;
54 }
55
56 template <typename T, typename AccT>
57 void compensate_roundoff(T& n, AccT acc_n)
58 {
59 compensate_roundoff(n, acc_n, is_integral<AccT>());
60 }
61 }
62
63 template <typename T, typename AccT>
64 inline bool
65 scale(int exp, T& n, AccT acc_n)
66 {
67 if (exp >= 0)
68 {
69 int const max_exp = std::numeric_limits<T>::max_exponent10;
70
71 // return false if exp exceeds the max_exp
72 // do this check only for primitive types!
73 if (is_floating_point<T>() && (exp > max_exp))
74 return false;
75 n = acc_n * pow10<T>(exp);
76 }
77 else
78 {
79 if (exp < std::numeric_limits<T>::min_exponent10)
80 {
81 int const min_exp = std::numeric_limits<T>::min_exponent10;
82 detail::compensate_roundoff(n, acc_n);
83 n /= pow10<T>(-min_exp);
84
85 // return false if exp still exceeds the min_exp
86 // do this check only for primitive types!
87 exp += -min_exp;
88 if (is_floating_point<T>() && exp < min_exp)
89 return false;
90
91 n /= pow10<T>(-exp);
92 }
93 else
94 {
95 n = T(acc_n) / pow10<T>(-exp);
96 }
97 }
98 return true;
99 }
100
101 inline bool
102 scale(int /*exp*/, unused_type /*n*/, unused_type /*acc_n*/)
103 {
104 // no-op for unused_type
105 return true;
106 }
107
108 template <typename T, typename AccT>
109 inline bool
110 scale(int exp, int frac, T& n, AccT acc_n)
111 {
112 return scale(exp - frac, n, acc_n);
113 }
114
115 inline bool
116 scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
117 {
118 // no-op for unused_type
119 return true;
120 }
121
122 inline float
123 negate(bool neg, float n)
124 {
125 return neg ? (core::copysign)(n, -1.f) : n;
126 }
127
128 inline double
129 negate(bool neg, double n)
130 {
131 return neg ? (core::copysign)(n, -1.) : n;
132 }
133
134 inline long double
135 negate(bool neg, long double n)
136 {
137 return neg ? (core::copysign)(n, static_cast<long double>(-1)) : n;
138 }
139
140 template <typename T>
141 inline T
142 negate(bool neg, T const& n)
143 {
144 return neg ? -n : n;
145 }
146
147 inline unused_type
148 negate(bool /*neg*/, unused_type n)
149 {
150 // no-op for unused_type
151 return n;
152 }
153
154 template <typename T>
155 struct real_accumulator : mpl::identity<T> {};
156
157 template <>
158 struct real_accumulator<float>
159 : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {};
160
161 template <>
162 struct real_accumulator<double>
163 : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {};
164 }}}
165
166 namespace boost { namespace spirit { namespace qi { namespace detail
167 {
168 BOOST_MPL_HAS_XXX_TRAIT_DEF(version)
169
170 template <typename T, typename RealPolicies>
171 struct real_impl
172 {
173 template <typename Iterator>
174 static std::size_t
175 ignore_excess_digits(Iterator& /* first */, Iterator const& /* last */, mpl::false_)
176 {
177 return 0;
178 }
179
180 template <typename Iterator>
181 static std::size_t
182 ignore_excess_digits(Iterator& first, Iterator const& last, mpl::true_)
183 {
184 return RealPolicies::ignore_excess_digits(first, last);
185 }
186
187 template <typename Iterator>
188 static std::size_t
189 ignore_excess_digits(Iterator& first, Iterator const& last)
190 {
191 typedef mpl::bool_<has_version<RealPolicies>::value> has_version;
192 return ignore_excess_digits(first, last, has_version());
193 }
194
195 template <typename Iterator, typename Attribute>
196 static bool
197 parse(Iterator& first, Iterator const& last, Attribute& attr,
198 RealPolicies const& p)
199 {
200 if (first == last)
201 return false;
202 Iterator save = first;
203
204 // Start by parsing the sign. neg will be true if
205 // we got a "-" sign, false otherwise.
206 bool neg = p.parse_sign(first, last);
207
208 // Now attempt to parse an integer
209 T n;
210
211 typename traits::real_accumulator<T>::type acc_n = 0;
212 bool got_a_number = p.parse_n(first, last, acc_n);
213 int excess_n = 0;
214
215 // If we did not get a number it might be a NaN, Inf or a leading
216 // dot.
217 if (!got_a_number)
218 {
219 // Check whether the number to parse is a NaN or Inf
220 if (p.parse_nan(first, last, n) ||
221 p.parse_inf(first, last, n))
222 {
223 // If we got a negative sign, negate the number
224 traits::assign_to(traits::negate(neg, n), attr);
225 return true; // got a NaN or Inf, return early
226 }
227
228 // If we did not get a number and our policies do not
229 // allow a leading dot, fail and return early (no-match)
230 if (!p.allow_leading_dot)
231 {
232 first = save;
233 return false;
234 }
235 }
236 else
237 {
238 // We got a number and we still see digits. This happens if acc_n (an integer)
239 // exceeds the integer's capacity. Collect the excess digits.
240 excess_n = static_cast<int>(ignore_excess_digits(first, last));
241 }
242
243 bool e_hit = false;
244 Iterator e_pos;
245 int frac_digits = 0;
246
247 // Try to parse the dot ('.' decimal point)
248 if (p.parse_dot(first, last))
249 {
250 // We got the decimal point. Now we will try to parse
251 // the fraction if it is there. If not, it defaults
252 // to zero (0) only if we already got a number.
253 if (excess_n != 0)
254 {
255 // We skip the fractions if we already exceeded our digits capacity
256 ignore_excess_digits(first, last);
257 }
258 else if (p.parse_frac_n(first, last, acc_n, frac_digits))
259 {
260 BOOST_ASSERT(frac_digits >= 0);
261 }
262 else if (!got_a_number || !p.allow_trailing_dot)
263 {
264 // We did not get a fraction. If we still haven't got a
265 // number and our policies do not allow a trailing dot,
266 // return no-match.
267 first = save;
268 return false;
269 }
270
271 // Now, let's see if we can parse the exponent prefix
272 e_pos = first;
273 e_hit = p.parse_exp(first, last);
274 }
275 else
276 {
277 // No dot and no number! Return no-match.
278 if (!got_a_number)
279 {
280 first = save;
281 return false;
282 }
283
284 // If we must expect a dot and we didn't see an exponent
285 // prefix, return no-match.
286 e_pos = first;
287 e_hit = p.parse_exp(first, last);
288 if (p.expect_dot && !e_hit)
289 {
290 first = save;
291 return false;
292 }
293 }
294
295 if (e_hit)
296 {
297 // We got the exponent prefix. Now we will try to parse the
298 // actual exponent.
299 int exp = 0;
300 if (p.parse_exp_n(first, last, exp))
301 {
302 // Got the exponent value. Scale the number by
303 // exp + excess_n - frac_digits.
304 if (!traits::scale(exp + excess_n, frac_digits, n, acc_n))
305 return false;
306 }
307 else
308 {
309 // If there is no number, disregard the exponent altogether.
310 // by resetting 'first' prior to the exponent prefix (e|E)
311 first = e_pos;
312 // Scale the number by -frac_digits.
313 bool r = traits::scale(-frac_digits, n, acc_n);
314 BOOST_VERIFY(r);
315 }
316 }
317 else if (frac_digits)
318 {
319 // No exponent found. Scale the number by -frac_digits.
320 bool r = traits::scale(-frac_digits, n, acc_n);
321 BOOST_VERIFY(r);
322 }
323 else
324 {
325 if (excess_n)
326 {
327 if (!traits::scale(excess_n, n, acc_n))
328 return false;
329 }
330 else
331 {
332 n = static_cast<T>(acc_n);
333 }
334 }
335
336 // If we got a negative sign, negate the number
337 traits::assign_to(traits::negate(neg, n), attr);
338
339 // Success!!!
340 return true;
341 }
342 };
343
344 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
345 # pragma warning(pop)
346 #endif
347
348 }}}}
349
350 #endif