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