]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/spirit/include/boost/spirit/home/qi/numeric/detail/real_impl.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / spirit / include / boost / spirit / home / qi / numeric / detail / real_impl.hpp
CommitLineData
7c673cae
FG
1/*=============================================================================
2 Copyright (c) 2001-2011 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#if !defined(SPIRIT_REAL_IMPL_APRIL_18_2006_0901AM)
10#define SPIRIT_REAL_IMPL_APRIL_18_2006_0901AM
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;
35
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 }
47
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 }
54
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 {
68 int max_exp = std::numeric_limits<T>::max_exponent10;
69
70 // return false if exp exceeds the max_exp
71 // do this check only for primitive types!
72 if (is_floating_point<T>() && exp > max_exp)
73 return false;
74 n = acc_n * pow10<T>(exp);
75 }
76 else
77 {
78 if (exp < std::numeric_limits<T>::min_exponent10)
79 {
80 int min_exp = std::numeric_limits<T>::min_exponent10;
81 detail::compensate_roundoff(n, acc_n);
82 n /= pow10<T>(-min_exp);
83
84 // return false if (-exp + min_exp) exceeds the -min_exp
85 // do this check only for primitive types!
86 if (is_floating_point<T>() && (-exp + min_exp) > -min_exp)
87 return false;
88
89 n /= pow10<T>(-exp + min_exp);
90 }
91 else
92 {
93 n = T(acc_n) / pow10<T>(-exp);
94 }
95 }
96 return true;
97 }
98
99 inline bool
100 scale(int /*exp*/, unused_type /*n*/, unused_type /*acc_n*/)
101 {
102 // no-op for unused_type
103 return true;
104 }
105
106 template <typename T, typename AccT>
107 inline bool
108 scale(int exp, int frac, T& n, AccT acc_n)
109 {
110 return scale(exp - frac, n, acc_n);
111 }
112
113 inline bool
114 scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
115 {
116 // no-op for unused_type
117 return true;
118 }
119
120 inline float
121 negate(bool neg, float n)
122 {
123 return neg ? spirit::detail::changesign(n) : n;
124 }
125
126 inline double
127 negate(bool neg, double n)
128 {
129 return neg ? spirit::detail::changesign(n) : n;
130 }
131
132 inline long double
133 negate(bool neg, long double n)
134 {
135 return neg ? spirit::detail::changesign(n) : n;
136 }
137
138 template <typename T>
139 inline T
140 negate(bool neg, T const& n)
141 {
142 return neg ? -n : n;
143 }
144
145 inline unused_type
146 negate(bool /*neg*/, unused_type n)
147 {
148 // no-op for unused_type
149 return n;
150 }
151
152 template <typename T>
153 inline bool
154 is_equal_to_one(T const& value)
155 {
156 return value == 1.0;
157 }
158
159 inline bool
160 is_equal_to_one(unused_type)
161 {
162 // no-op for unused_type
163 return false;
164 }
165
166 template <typename T>
167 struct real_accumulator : mpl::identity<T> {};
168
169 template <>
170 struct real_accumulator<float>
171 : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {};
172
173 template <>
174 struct real_accumulator<double>
175 : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {};
176}}}
177
178namespace boost { namespace spirit { namespace qi { namespace detail
179{
180 template <typename T, typename RealPolicies>
181 struct real_impl
182 {
183 template <typename Iterator, typename Attribute>
184 static bool
185 parse(Iterator& first, Iterator const& last, Attribute& attr,
186 RealPolicies const& p)
187 {
188 if (first == last)
189 return false;
190 Iterator save = first;
191
192 // Start by parsing the sign. neg will be true if
193 // we got a "-" sign, false otherwise.
194 bool neg = p.parse_sign(first, last);
195
196 // Now attempt to parse an integer
197 T n;
198
199 typename traits::real_accumulator<T>::type acc_n = 0;
200 bool got_a_number = p.parse_n(first, last, acc_n);
201
202 // If we did not get a number it might be a NaN, Inf or a leading
203 // dot.
204 if (!got_a_number)
205 {
206 // Check whether the number to parse is a NaN or Inf
207 if (p.parse_nan(first, last, n) ||
208 p.parse_inf(first, last, n))
209 {
210 // If we got a negative sign, negate the number
211 traits::assign_to(traits::negate(neg, n), attr);
212 return true; // got a NaN or Inf, return early
213 }
214
215 // If we did not get a number and our policies do not
216 // allow a leading dot, fail and return early (no-match)
217 if (!p.allow_leading_dot)
218 {
219 first = save;
220 return false;
221 }
222 }
223
224 bool e_hit = false;
225 Iterator e_pos;
226 int frac_digits = 0;
227
228 // Try to parse the dot ('.' decimal point)
229 if (p.parse_dot(first, last))
230 {
231 // We got the decimal point. Now we will try to parse
232 // the fraction if it is there. If not, it defaults
233 // to zero (0) only if we already got a number.
234 if (p.parse_frac_n(first, last, acc_n, frac_digits))
235 {
236 }
237 else if (!got_a_number || !p.allow_trailing_dot)
238 {
239 // We did not get a fraction. If we still haven't got a
240 // number and our policies do not allow a trailing dot,
241 // return no-match.
242 first = save;
243 return false;
244 }
245
246 // Now, let's see if we can parse the exponent prefix
247 e_pos = first;
248 e_hit = p.parse_exp(first, last);
249 }
250 else
251 {
252 // No dot and no number! Return no-match.
253 if (!got_a_number)
254 {
255 first = save;
256 return false;
257 }
258
259 // If we must expect a dot and we didn't see an exponent
260 // prefix, return no-match.
261 e_pos = first;
262 e_hit = p.parse_exp(first, last);
263 if (p.expect_dot && !e_hit)
264 {
265 first = save;
266 return false;
267 }
268 }
269
270 if (e_hit)
271 {
272 // We got the exponent prefix. Now we will try to parse the
273 // actual exponent.
274 int exp = 0;
275 if (p.parse_exp_n(first, last, exp))
276 {
277 // Got the exponent value. Scale the number by
278 // exp-frac_digits.
279 if (!traits::scale(exp, frac_digits, n, acc_n))
280 return false;
281 }
282 else
283 {
284 // If there is no number, disregard the exponent altogether.
285 // by resetting 'first' prior to the exponent prefix (e|E)
286 first = e_pos;
287 n = static_cast<T>(acc_n);
288 }
289 }
290 else if (frac_digits)
291 {
292 // No exponent found. Scale the number by -frac_digits.
293 traits::scale(-frac_digits, n, acc_n);
294 }
295 else if (traits::is_equal_to_one(acc_n))
296 {
297 // There is a chance of having to parse one of the 1.0#...
298 // styles some implementations use for representing NaN or Inf.
299
300 // Check whether the number to parse is a NaN or Inf
301 if (p.parse_nan(first, last, n) ||
302 p.parse_inf(first, last, n))
303 {
304 // If we got a negative sign, negate the number
305 traits::assign_to(traits::negate(neg, n), attr);
306 return true; // got a NaN or Inf, return immediately
307 }
308
309 n = static_cast<T>(acc_n);
310 }
311 else
312 {
313 n = static_cast<T>(acc_n);
314 }
315
316 // If we got a negative sign, negate the number
317 traits::assign_to(traits::negate(neg, n), attr);
318
319 // Success!!!
320 return true;
321 }
322 };
323
324#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
325# pragma warning(pop)
326#endif
327
328}}}}
329
330#endif