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/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> compensate_roundoff(T & n,AccT acc_n,mpl::true_)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> compensate_roundoff(T & n,AccT acc_n,mpl::false_)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> compensate_roundoff(T & n,AccT acc_n)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 scale(int exp,T & n,AccT acc_n)64 scale(int exp, T& n, AccT acc_n) 65 { 66 if (exp >= 0) 67 { 68 int const 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 const 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 scale(int,unused_type,unused_type)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 scale(int exp,int frac,T & n,AccT acc_n)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 scale(int,int,unused_type)115 scale(int /*exp*/, int /*frac*/, unused_type /*n*/) 116 { 117 // no-op for unused_type 118 return true; 119 } 120 121 inline float negate(bool neg,float n)122 negate(bool neg, float n) 123 { 124 return neg ? spirit::detail::changesign(n) : n; 125 } 126 127 inline double negate(bool neg,double n)128 negate(bool neg, double n) 129 { 130 return neg ? spirit::detail::changesign(n) : n; 131 } 132 133 inline long double negate(bool neg,long double n)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 negate(bool neg,T const & n)141 negate(bool neg, T const& n) 142 { 143 return neg ? -n : n; 144 } 145 146 inline unused_type negate(bool,unused_type n)147 negate(bool /*neg*/, unused_type n) 148 { 149 // no-op for unused_type 150 return n; 151 } 152 153 template <typename T> 154 struct real_accumulator : mpl::identity<T> {}; 155 156 template <> 157 struct real_accumulator<float> 158 : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {}; 159 160 template <> 161 struct real_accumulator<double> 162 : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {}; 163 }}} 164 165 namespace boost { namespace spirit { namespace qi { namespace detail 166 { 167 BOOST_MPL_HAS_XXX_TRAIT_DEF(version) 168 169 template <typename T, typename RealPolicies> 170 struct real_impl 171 { 172 template <typename Iterator> 173 static std::size_t ignore_excess_digitsboost::spirit::qi::detail::real_impl174 ignore_excess_digits(Iterator& /* first */, Iterator const& /* last */, mpl::false_) 175 { 176 return 0; 177 } 178 179 template <typename Iterator> 180 static std::size_t ignore_excess_digitsboost::spirit::qi::detail::real_impl181 ignore_excess_digits(Iterator& first, Iterator const& last, mpl::true_) 182 { 183 return RealPolicies::ignore_excess_digits(first, last); 184 } 185 186 template <typename Iterator> 187 static std::size_t ignore_excess_digitsboost::spirit::qi::detail::real_impl188 ignore_excess_digits(Iterator& first, Iterator const& last) 189 { 190 typedef mpl::bool_<has_version<RealPolicies>::value> has_version; 191 return ignore_excess_digits(first, last, has_version()); 192 } 193 194 template <typename Iterator, typename Attribute> 195 static bool parseboost::spirit::qi::detail::real_impl196 parse(Iterator& first, Iterator const& last, Attribute& attr, 197 RealPolicies const& p) 198 { 199 if (first == last) 200 return false; 201 Iterator save = first; 202 203 // Start by parsing the sign. neg will be true if 204 // we got a "-" sign, false otherwise. 205 bool neg = p.parse_sign(first, last); 206 207 // Now attempt to parse an integer 208 T n; 209 210 typename traits::real_accumulator<T>::type acc_n = 0; 211 bool got_a_number = p.parse_n(first, last, acc_n); 212 int excess_n = 0; 213 214 // If we did not get a number it might be a NaN, Inf or a leading 215 // dot. 216 if (!got_a_number) 217 { 218 // Check whether the number to parse is a NaN or Inf 219 if (p.parse_nan(first, last, n) || 220 p.parse_inf(first, last, n)) 221 { 222 // If we got a negative sign, negate the number 223 traits::assign_to(traits::negate(neg, n), attr); 224 return true; // got a NaN or Inf, return early 225 } 226 227 // If we did not get a number and our policies do not 228 // allow a leading dot, fail and return early (no-match) 229 if (!p.allow_leading_dot) 230 { 231 first = save; 232 return false; 233 } 234 } 235 else 236 { 237 // We got a number and we still see digits. This happens if acc_n (an integer) 238 // exceeds the integer's capacity. Collect the excess digits. 239 excess_n = static_cast<int>(ignore_excess_digits(first, last)); 240 } 241 242 bool e_hit = false; 243 Iterator e_pos; 244 int frac_digits = 0; 245 246 // Try to parse the dot ('.' decimal point) 247 if (p.parse_dot(first, last)) 248 { 249 // We got the decimal point. Now we will try to parse 250 // the fraction if it is there. If not, it defaults 251 // to zero (0) only if we already got a number. 252 if (excess_n != 0) 253 { 254 // We skip the fractions if we already exceeded our digits capacity 255 ignore_excess_digits(first, last); 256 } 257 else if (p.parse_frac_n(first, last, acc_n, frac_digits)) 258 { 259 BOOST_ASSERT(frac_digits >= 0); 260 } 261 else if (!got_a_number || !p.allow_trailing_dot) 262 { 263 // We did not get a fraction. If we still haven't got a 264 // number and our policies do not allow a trailing dot, 265 // return no-match. 266 first = save; 267 return false; 268 } 269 270 // Now, let's see if we can parse the exponent prefix 271 e_pos = first; 272 e_hit = p.parse_exp(first, last); 273 } 274 else 275 { 276 // No dot and no number! Return no-match. 277 if (!got_a_number) 278 { 279 first = save; 280 return false; 281 } 282 283 // If we must expect a dot and we didn't see an exponent 284 // prefix, return no-match. 285 e_pos = first; 286 e_hit = p.parse_exp(first, last); 287 if (p.expect_dot && !e_hit) 288 { 289 first = save; 290 return false; 291 } 292 } 293 294 if (e_hit) 295 { 296 // We got the exponent prefix. Now we will try to parse the 297 // actual exponent. 298 int exp = 0; 299 if (p.parse_exp_n(first, last, exp)) 300 { 301 // Got the exponent value. Scale the number by 302 // exp + excess_n - frac_digits. 303 if (!traits::scale(exp + excess_n, frac_digits, n, acc_n)) 304 return false; 305 } 306 else 307 { 308 // If there is no number, disregard the exponent altogether. 309 // by resetting 'first' prior to the exponent prefix (e|E) 310 first = e_pos; 311 // Scale the number by -frac_digits. 312 bool r = traits::scale(-frac_digits, n, acc_n); 313 BOOST_VERIFY(r); 314 } 315 } 316 else if (frac_digits) 317 { 318 // No exponent found. Scale the number by -frac_digits. 319 bool r = traits::scale(-frac_digits, n, acc_n); 320 BOOST_VERIFY(r); 321 } 322 else 323 { 324 if (excess_n) 325 { 326 if (!traits::scale(excess_n, n, acc_n)) 327 return false; 328 } 329 else 330 { 331 n = static_cast<T>(acc_n); 332 } 333 } 334 335 // If we got a negative sign, negate the number 336 traits::assign_to(traits::negate(neg, n), attr); 337 338 // Success!!! 339 return true; 340 } 341 }; 342 343 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 344 # pragma warning(pop) 345 #endif 346 347 }}}} 348 349 #endif 350