1 /*=============================================================================
2     Copyright (c) 2001-2014 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(BOOST_SPIRIT_X3_EXTRACT_REAL_APRIL_18_2006_0901AM)
10 #define BOOST_SPIRIT_X3_EXTRACT_REAL_APRIL_18_2006_0901AM
11 
12 #include <cmath>
13 #include <boost/limits.hpp>
14 #include <boost/type_traits/is_same.hpp>
15 #include <boost/spirit/home/x3/support/unused.hpp>
16 #include <boost/spirit/home/x3/support/numeric_utils/pow10.hpp>
17 #include <boost/spirit/home/x3/support/traits/move_to.hpp>
18 #include <boost/assert.hpp>
19 
20 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
21 # pragma warning(push)
22 # pragma warning(disable: 4100)   // 'p': unreferenced formal parameter
23 # pragma warning(disable: 4127)   // conditional expression is constant
24 #endif
25 
26 namespace boost { namespace spirit { namespace x3 { namespace extension
27 {
28     using x3::traits::pow10;
29 
30     template <typename T>
31     inline bool
scale(int exp,T & n)32     scale(int exp, T& n)
33     {
34         constexpr auto max_exp = std::numeric_limits<T>::max_exponent10;
35         constexpr auto min_exp = std::numeric_limits<T>::min_exponent10;
36 
37         if (exp >= 0)
38         {
39             // return false if exp exceeds the max_exp
40             // do this check only for primitive types!
41             if (is_floating_point<T>() && exp > max_exp)
42                 return false;
43             n *= pow10<T>(exp);
44         }
45         else
46         {
47             if (exp < min_exp)
48             {
49                 n /= pow10<T>(-min_exp);
50 
51                 // return false if exp still exceeds the min_exp
52                 // do this check only for primitive types!
53                 exp += -min_exp;
54                 if (is_floating_point<T>() && exp < min_exp)
55                     return false;
56 
57                 n /= pow10<T>(-exp);
58             }
59             else
60             {
61                 n /= pow10<T>(-exp);
62             }
63         }
64         return true;
65     }
66 
67     inline bool
scale(int,unused_type)68     scale(int /*exp*/, unused_type /*n*/)
69     {
70         // no-op for unused_type
71         return true;
72     }
73 
74     template <typename T>
75     inline bool
scale(int exp,int frac,T & n)76     scale(int exp, int frac, T& n)
77     {
78         return scale(exp - frac, n);
79     }
80 
81     inline bool
scale(int,int,unused_type)82     scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
83     {
84         // no-op for unused_type
85         return true;
86     }
87 
88     inline float
negate(bool neg,float n)89     negate(bool neg, float n)
90     {
91         return neg ? (std::copysignf)(n, -1.f) : n;
92     }
93 
94     inline double
negate(bool neg,double n)95     negate(bool neg, double n)
96     {
97         return neg ? (std::copysign)(n, -1.) : n;
98     }
99 
100     inline long double
negate(bool neg,long double n)101     negate(bool neg, long double n)
102     {
103         return neg ? (std::copysignl)(n, -1.) : n;
104     }
105 
106     template <typename T>
107     inline T
negate(bool neg,T const & n)108     negate(bool neg, T const& n)
109     {
110         return neg ? -n : n;
111     }
112 
113     inline unused_type
negate(bool,unused_type n)114     negate(bool /*neg*/, unused_type n)
115     {
116         // no-op for unused_type
117         return n;
118     }
119 }}}}
120 
121 namespace boost { namespace spirit { namespace x3
122 {
123     template <typename T, typename RealPolicies>
124     struct extract_real
125     {
126         template <typename Iterator, typename Attribute>
127         static bool
parseboost::spirit::x3::extract_real128         parse(Iterator& first, Iterator const& last, Attribute& attr,
129             RealPolicies const& p)
130         {
131             if (first == last)
132                 return false;
133             Iterator save = first;
134 
135             // Start by parsing the sign. neg will be true if
136             // we got a "-" sign, false otherwise.
137             bool neg = p.parse_sign(first, last);
138 
139             // Now attempt to parse an integer
140             T n = 0;
141             bool got_a_number = p.parse_n(first, last, n);
142 
143             // If we did not get a number it might be a NaN, Inf or a leading
144             // dot.
145             if (!got_a_number)
146             {
147                 // Check whether the number to parse is a NaN or Inf
148                 if (p.parse_nan(first, last, n) ||
149                     p.parse_inf(first, last, n))
150                 {
151                     // If we got a negative sign, negate the number
152                     traits::move_to(extension::negate(neg, n), attr);
153                     return true;    // got a NaN or Inf, return early
154                 }
155 
156                 // If we did not get a number and our policies do not
157                 // allow a leading dot, fail and return early (no-match)
158                 if (!p.allow_leading_dot)
159                 {
160                     first = save;
161                     return false;
162                 }
163             }
164 
165             bool e_hit = false;
166             Iterator e_pos;
167             int frac_digits = 0;
168 
169             // Try to parse the dot ('.' decimal point)
170             if (p.parse_dot(first, last))
171             {
172                 // We got the decimal point. Now we will try to parse
173                 // the fraction if it is there. If not, it defaults
174                 // to zero (0) only if we already got a number.
175                 Iterator savef = first;
176                 if (p.parse_frac_n(first, last, n))
177                 {
178                     // Optimization note: don't compute frac_digits if T is
179                     // an unused_type. This should be optimized away by the compiler.
180                     if (!is_same<T, unused_type>::value)
181                         frac_digits =
182                             static_cast<int>(std::distance(savef, first));
183                     BOOST_ASSERT(frac_digits >= 0);
184                 }
185                 else if (!got_a_number || !p.allow_trailing_dot)
186                 {
187                     // We did not get a fraction. If we still haven't got a
188                     // number and our policies do not allow a trailing dot,
189                     // return no-match.
190                     first = save;
191                     return false;
192                 }
193 
194                 // Now, let's see if we can parse the exponent prefix
195                 e_pos = first;
196                 e_hit = p.parse_exp(first, last);
197             }
198             else
199             {
200                 // No dot and no number! Return no-match.
201                 if (!got_a_number)
202                 {
203                     first = save;
204                     return false;
205                 }
206 
207                 // If we must expect a dot and we didn't see an exponent
208                 // prefix, return no-match.
209                 e_pos = first;
210                 e_hit = p.parse_exp(first, last);
211                 if (p.expect_dot && !e_hit)
212                 {
213                     first = save;
214                     return false;
215                 }
216             }
217 
218             if (e_hit)
219             {
220                 // We got the exponent prefix. Now we will try to parse the
221                 // actual exponent. It is an error if it is not there.
222                 int exp = 0;
223                 if (p.parse_exp_n(first, last, exp))
224                 {
225                     // Got the exponent value. Scale the number by
226                     // exp-frac_digits.
227                     if (!extension::scale(exp, frac_digits, n))
228                         return false;
229                 }
230                 else
231                 {
232                     // If there is no number, disregard the exponent altogether.
233                     // by resetting 'first' prior to the exponent prefix (e|E)
234                     first = e_pos;
235 
236                     // Scale the number by -frac_digits.
237                     if (!extension::scale(-frac_digits, n))
238                         return false;
239                 }
240             }
241             else if (frac_digits)
242             {
243                 // No exponent found. Scale the number by -frac_digits.
244                 if (!extension::scale(-frac_digits, n))
245                     return false;
246             }
247 
248             // If we got a negative sign, negate the number
249             traits::move_to(extension::negate(neg, n), attr);
250 
251             // Success!!!
252             return true;
253         }
254     };
255 
256 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
257 # pragma warning(pop)
258 #endif
259 
260 }}}
261 
262 #endif
263