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
26namespace boost { namespace spirit { namespace x3 { namespace extension
27{
28 using x3::traits::pow10;
29
30 template <typename T>
31 inline bool
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
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
76 scale(int exp, int frac, T& n)
77 {
78 return scale(exp - frac, n);
79 }
80
81 inline bool
82 scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
83 {
84 // no-op for unused_type
85 return true;
86 }
87
88 inline float
89 negate(bool neg, float n)
90 {
91 return neg ? (std::copysignf)(x: n, y: -1.f) : n;
92 }
93
94 inline double
95 negate(bool neg, double n)
96 {
97 return neg ? (std::copysign)(x: n, y: -1.) : n;
98 }
99
100 inline long double
101 negate(bool neg, long double n)
102 {
103 return neg ? (std::copysignl)(x: n, y: -1.) : n;
104 }
105
106 template <typename T>
107 inline T
108 negate(bool neg, T const& n)
109 {
110 return neg ? -n : n;
111 }
112
113 inline unused_type
114 negate(bool /*neg*/, unused_type n)
115 {
116 // no-op for unused_type
117 return n;
118 }
119}}}}
120
121namespace 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
128 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

source code of boost/libs/spirit/include/boost/spirit/home/x3/support/numeric_utils/extract_real.hpp