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>
compensate_roundoff(T & n,AccT acc_n,mpl::true_)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>
compensate_roundoff(T & n,AccT acc_n,mpl::false_)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>
compensate_roundoff(T & n,AccT acc_n)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
scale(int exp,T & n,AccT acc_n)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
scale(int,unused_type,unused_type)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
scale(int exp,int frac,T & n,AccT acc_n)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
scale(int,int,unused_type)116     scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
117     {
118         // no-op for unused_type
119         return true;
120     }
121 
122     inline float
negate(bool neg,float n)123     negate(bool neg, float n)
124     {
125         return neg ? (core::copysign)(n, -1.f) : n;
126     }
127 
128     inline double
negate(bool neg,double n)129     negate(bool neg, double n)
130     {
131         return neg ? (core::copysign)(n, -1.) : n;
132     }
133 
134     inline long double
negate(bool neg,long double n)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
negate(bool neg,T const & n)142     negate(bool neg, T const& n)
143     {
144         return neg ? -n : n;
145     }
146 
147     inline unused_type
negate(bool,unused_type n)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
ignore_excess_digitsboost::spirit::qi::detail::real_impl175         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
ignore_excess_digitsboost::spirit::qi::detail::real_impl182         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
ignore_excess_digitsboost::spirit::qi::detail::real_impl189         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
parseboost::spirit::qi::detail::real_impl197         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
351