]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/spirit/home/qi/numeric/detail/real_impl.hpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / boost / spirit / home / qi / numeric / detail / real_impl.hpp
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
32 namespace 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 still exceeds the min_exp
85 // do this check only for primitive types!
86 exp += -min_exp;
87 if (is_floating_point<T>() && exp < min_exp)
88 return false;
89
90 n /= pow10<T>(-exp);
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
153 template <typename T>
154 inline bool
155 is_equal_to_one(T const& value)
156 {
157 return value == 1.0;
158 }
159
160 inline bool
161 is_equal_to_one(unused_type)
162 {
163 // no-op for unused_type
164 return false;
165 }
166
167 template <typename T>
168 struct real_accumulator : mpl::identity<T> {};
169
170 template <>
171 struct real_accumulator<float>
172 : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {};
173
174 template <>
175 struct real_accumulator<double>
176 : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {};
177 }}}
178
179 namespace boost { namespace spirit { namespace qi { namespace detail
180 {
181 template <typename T, typename RealPolicies>
182 struct real_impl
183 {
184 template <typename Iterator, typename Attribute>
185 static bool
186 parse(Iterator& first, Iterator const& last, Attribute& attr,
187 RealPolicies const& p)
188 {
189 if (first == last)
190 return false;
191 Iterator save = first;
192
193 // Start by parsing the sign. neg will be true if
194 // we got a "-" sign, false otherwise.
195 bool neg = p.parse_sign(first, last);
196
197 // Now attempt to parse an integer
198 T n;
199
200 typename traits::real_accumulator<T>::type acc_n = 0;
201 bool got_a_number = p.parse_n(first, last, acc_n);
202
203 // If we did not get a number it might be a NaN, Inf or a leading
204 // dot.
205 if (!got_a_number)
206 {
207 // Check whether the number to parse is a NaN or Inf
208 if (p.parse_nan(first, last, n) ||
209 p.parse_inf(first, last, n))
210 {
211 // If we got a negative sign, negate the number
212 traits::assign_to(traits::negate(neg, n), attr);
213 return true; // got a NaN or Inf, return early
214 }
215
216 // If we did not get a number and our policies do not
217 // allow a leading dot, fail and return early (no-match)
218 if (!p.allow_leading_dot)
219 {
220 first = save;
221 return false;
222 }
223 }
224
225 bool e_hit = false;
226 Iterator e_pos;
227 int frac_digits = 0;
228
229 // Try to parse the dot ('.' decimal point)
230 if (p.parse_dot(first, last))
231 {
232 // We got the decimal point. Now we will try to parse
233 // the fraction if it is there. If not, it defaults
234 // to zero (0) only if we already got a number.
235 if (p.parse_frac_n(first, last, acc_n, frac_digits))
236 {
237 BOOST_ASSERT(frac_digits >= 0);
238 }
239 else if (!got_a_number || !p.allow_trailing_dot)
240 {
241 // We did not get a fraction. If we still haven't got a
242 // number and our policies do not allow a trailing dot,
243 // return no-match.
244 first = save;
245 return false;
246 }
247
248 // Now, let's see if we can parse the exponent prefix
249 e_pos = first;
250 e_hit = p.parse_exp(first, last);
251 }
252 else
253 {
254 // No dot and no number! Return no-match.
255 if (!got_a_number)
256 {
257 first = save;
258 return false;
259 }
260
261 // If we must expect a dot and we didn't see an exponent
262 // prefix, return no-match.
263 e_pos = first;
264 e_hit = p.parse_exp(first, last);
265 if (p.expect_dot && !e_hit)
266 {
267 first = save;
268 return false;
269 }
270 }
271
272 if (e_hit)
273 {
274 // We got the exponent prefix. Now we will try to parse the
275 // actual exponent.
276 int exp = 0;
277 if (p.parse_exp_n(first, last, exp))
278 {
279 // Got the exponent value. Scale the number by
280 // exp-frac_digits.
281 if (!traits::scale(exp, frac_digits, n, acc_n))
282 return false;
283 }
284 else
285 {
286 // If there is no number, disregard the exponent altogether.
287 // by resetting 'first' prior to the exponent prefix (e|E)
288 first = e_pos;
289 // Scale the number by -frac_digits.
290 bool r = traits::scale(-frac_digits, n, acc_n);
291 BOOST_VERIFY(r);
292 }
293 }
294 else if (frac_digits)
295 {
296 // No exponent found. Scale the number by -frac_digits.
297 bool r = traits::scale(-frac_digits, n, acc_n);
298 BOOST_VERIFY(r);
299 }
300 else if (traits::is_equal_to_one(acc_n))
301 {
302 // There is a chance of having to parse one of the 1.0#...
303 // styles some implementations use for representing NaN or Inf.
304
305 // Check whether the number to parse is a NaN or Inf
306 if (p.parse_nan(first, last, n) ||
307 p.parse_inf(first, last, n))
308 {
309 // If we got a negative sign, negate the number
310 traits::assign_to(traits::negate(neg, n), attr);
311 return true; // got a NaN or Inf, return immediately
312 }
313
314 n = static_cast<T>(acc_n);
315 }
316 else
317 {
318 n = static_cast<T>(acc_n);
319 }
320
321 // If we got a negative sign, negate the number
322 traits::assign_to(traits::negate(neg, n), attr);
323
324 // Success!!!
325 return true;
326 }
327 };
328
329 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
330 # pragma warning(pop)
331 #endif
332
333 }}}}
334
335 #endif