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