diff options
Diffstat (limited to 'boost/spirit/home/qi')
-rw-r--r-- | boost/spirit/home/qi/nonterminal/rule.hpp | 10 | ||||
-rw-r--r-- | boost/spirit/home/qi/numeric/detail/numeric_utils.hpp | 35 | ||||
-rw-r--r-- | boost/spirit/home/qi/numeric/detail/real_impl.hpp | 125 | ||||
-rw-r--r-- | boost/spirit/home/qi/numeric/numeric_utils.hpp | 5 | ||||
-rw-r--r-- | boost/spirit/home/qi/numeric/real_policies.hpp | 18 |
5 files changed, 143 insertions, 50 deletions
diff --git a/boost/spirit/home/qi/nonterminal/rule.hpp b/boost/spirit/home/qi/nonterminal/rule.hpp index 8dd42373b0..0901420312 100644 --- a/boost/spirit/home/qi/nonterminal/rule.hpp +++ b/boost/spirit/home/qi/nonterminal/rule.hpp @@ -111,16 +111,16 @@ namespace boost { namespace spirit { namespace qi qi::domain, template_params>::type skipper_type; - // The rule's signature - typedef typename - spirit::detail::extract_sig<template_params>::type - sig_type; - // The rule's encoding type typedef typename spirit::detail::extract_encoding<template_params>::type encoding_type; + // The rule's signature + typedef typename + spirit::detail::extract_sig<template_params, encoding_type, qi::domain>::type + sig_type; + // This is the rule's attribute type typedef typename spirit::detail::attr_from_sig<sig_type>::type diff --git a/boost/spirit/home/qi/numeric/detail/numeric_utils.hpp b/boost/spirit/home/qi/numeric/detail/numeric_utils.hpp index 5137f87f10..7e96a3757f 100644 --- a/boost/spirit/home/qi/numeric/detail/numeric_utils.hpp +++ b/boost/spirit/home/qi/numeric/detail/numeric_utils.hpp @@ -2,7 +2,7 @@ Copyright (c) 2001-2011 Joel de Guzman Copyright (c) 2001-2011 Hartmut Kaiser Copyright (c) 2011 Jan Frederick Eick - Copyright (c) 2011 Christopher Jefferson + Copyright (c) 2011 Christopher Jefferson Copyright (c) 2006 Stephen Nutt Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -32,6 +32,11 @@ #include <boost/mpl/and.hpp> #include <boost/limits.hpp> +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +#endif + #if !defined(SPIRIT_NUMERICS_LOOP_UNROLL) # define SPIRIT_NUMERICS_LOOP_UNROLL 3 #endif @@ -132,6 +137,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail // Ensure n *= Radix will not overflow static T const max = (std::numeric_limits<T>::max)(); static T const val = max / Radix; + if (n > val) return false; @@ -181,7 +187,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail /////////////////////////////////////////////////////////////////////////// // Common code for extract_int::parse specializations /////////////////////////////////////////////////////////////////////////// - template <unsigned Radix, typename Accumulator, int MaxDigits> + template <unsigned Radix, typename Accumulator, int MaxDigits, bool AlwaysCheckOverflow> struct int_extractor { template <typename Char, typename T> @@ -191,7 +197,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail static std::size_t const overflow_free = digits_traits<T, Radix>::value - 1; - if (count < overflow_free) + if (!AlwaysCheckOverflow && (count < overflow_free)) { Accumulator::add(n, ch, mpl::false_()); } @@ -267,8 +273,15 @@ namespace boost { namespace spirit { namespace qi { namespace detail || it == last) \ break; \ ch = *it; \ - if (!radix_check::is_valid(ch) || !extractor::call(ch, count, val)) \ + if (!radix_check::is_valid(ch)) \ break; \ + if (!extractor::call(ch, count, val)) \ + { \ + if (IgnoreOverflowDigits) \ + first = it; \ + traits::assign_to(val, attr); \ + return IgnoreOverflowDigits; \ + } \ ++it; \ ++count; \ /**/ @@ -277,6 +290,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail typename T, unsigned Radix, unsigned MinDigits, int MaxDigits , typename Accumulator = positive_accumulator<Radix> , bool Accumulate = false + , bool IgnoreOverflowDigits = false > struct extract_int { @@ -292,7 +306,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail , Attribute& attr) { typedef radix_traits<Radix> radix_check; - typedef int_extractor<Radix, Accumulator, MaxDigits> extractor; + typedef int_extractor<Radix, Accumulator, MaxDigits, Accumulate> extractor; typedef typename boost::detail::iterator_traits<Iterator>::value_type char_type; @@ -370,7 +384,10 @@ namespace boost { namespace spirit { namespace qi { namespace detail if (!radix_check::is_valid(ch)) \ break; \ if (!extractor::call(ch, count, val)) \ + { \ + traits::assign_to(val, attr); \ return false; \ + } \ ++it; \ ++count; \ /**/ @@ -390,7 +407,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail , Attribute& attr) { typedef radix_traits<Radix> radix_check; - typedef int_extractor<Radix, Accumulator, -1> extractor; + typedef int_extractor<Radix, Accumulator, -1, Accumulate> extractor; typedef typename boost::detail::iterator_traits<Iterator>::value_type char_type; @@ -432,7 +449,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail return true; } - count = 0; + // count = 0; $$$ verify: I think this is wrong $$$ ++it; while (true) { @@ -503,4 +520,8 @@ namespace boost { namespace spirit { namespace qi { namespace detail }; }}}} +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + #endif diff --git a/boost/spirit/home/qi/numeric/detail/real_impl.hpp b/boost/spirit/home/qi/numeric/detail/real_impl.hpp index a4bd8789b6..cf92712a24 100644 --- a/boost/spirit/home/qi/numeric/detail/real_impl.hpp +++ b/boost/spirit/home/qi/numeric/detail/real_impl.hpp @@ -20,6 +20,7 @@ #include <boost/spirit/home/qi/detail/attributes.hpp> #include <boost/spirit/home/support/detail/pow10.hpp> #include <boost/spirit/home/support/detail/sign.hpp> +#include <boost/integer.hpp> #include <boost/assert.hpp> #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) @@ -31,49 +32,89 @@ namespace boost { namespace spirit { namespace traits { using spirit::traits::pow10; + + namespace detail + { + template <typename T, typename AccT> + void compensate_roundoff(T& n, AccT acc_n, mpl::true_) + { + // at the lowest extremes, we compensate for floating point + // roundoff errors by doing imprecise computation using T + int const comp = 10; + n = T((acc_n / comp) * comp); + n += T(acc_n % comp); + } + + template <typename T, typename AccT> + void compensate_roundoff(T& n, AccT acc_n, mpl::false_) + { + // no need to compensate + n = acc_n; + } + + template <typename T, typename AccT> + void compensate_roundoff(T& n, AccT acc_n) + { + compensate_roundoff(n, acc_n, is_integral<AccT>()); + } + } - template <typename T> - inline void - scale(int exp, T& n) + template <typename T, typename AccT> + inline bool + scale(int exp, T& n, AccT acc_n) { if (exp >= 0) { - // $$$ Why is this failing for boost.math.concepts ? $$$ - //~ int nn = std::numeric_limits<T>::max_exponent10; - //~ BOOST_ASSERT(exp <= std::numeric_limits<T>::max_exponent10); - n *= pow10<T>(exp); + std::size_t max_exp = std::numeric_limits<T>::max_exponent10; + + // return false if exp exceeds the max_exp + // do this check only for primitive types! + if (is_floating_point<T>() && exp > max_exp) + return false; + n = acc_n * pow10<T>(exp); } else { if (exp < std::numeric_limits<T>::min_exponent10) { - n /= pow10<T>(-std::numeric_limits<T>::min_exponent10); - n /= pow10<T>(-exp + std::numeric_limits<T>::min_exponent10); + int min_exp = std::numeric_limits<T>::min_exponent10; + detail::compensate_roundoff(n, acc_n); + n /= pow10<T>(-min_exp); + + // return false if (-exp + min_exp) exceeds the -min_exp + // do this check only for primitive types! + if (is_floating_point<T>() && (-exp + min_exp) > -min_exp) + return false; + + n /= pow10<T>(-exp + min_exp); } else { - n /= pow10<T>(-exp); + n = T(acc_n) / pow10<T>(-exp); } } + return true; } - inline void - scale(int /*exp*/, unused_type /*n*/) + inline bool + scale(int /*exp*/, unused_type /*n*/, unused_type /*acc_n*/) { // no-op for unused_type + return true; } - template <typename T> - inline void - scale(int exp, int frac, T& n) + template <typename T, typename AccT> + inline bool + scale(int exp, int frac, T& n, AccT acc_n) { - scale(exp - frac, n); + return scale(exp - frac, n, acc_n); } - inline void + inline bool scale(int /*exp*/, int /*frac*/, unused_type /*n*/) { // no-op for unused_type + return true; } inline float @@ -121,6 +162,17 @@ namespace boost { namespace spirit { namespace traits // no-op for unused_type return false; } + + template <typename T> + struct real_accumulator : mpl::identity<T> {}; + + template <> + struct real_accumulator<float> + : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {}; + + template <> + struct real_accumulator<double> + : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {}; }}} namespace boost { namespace spirit { namespace qi { namespace detail @@ -142,8 +194,10 @@ namespace boost { namespace spirit { namespace qi { namespace detail bool neg = p.parse_sign(first, last); // Now attempt to parse an integer - T n = 0; - bool got_a_number = p.parse_n(first, last, n); + T n; + + typename traits::real_accumulator<T>::type acc_n = 0; + bool got_a_number = p.parse_n(first, last, acc_n); // If we did not get a number it might be a NaN, Inf or a leading // dot. @@ -168,6 +222,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail } bool e_hit = false; + Iterator e_pos; int frac_digits = 0; // Try to parse the dot ('.' decimal point) @@ -176,14 +231,8 @@ namespace boost { namespace spirit { namespace qi { namespace detail // We got the decimal point. Now we will try to parse // the fraction if it is there. If not, it defaults // to zero (0) only if we already got a number. - Iterator savef = first; - if (p.parse_frac_n(first, last, n)) + if (p.parse_frac_n(first, last, acc_n, frac_digits)) { - // Optimization note: don't compute frac_digits if T is - // an unused_type. This should be optimized away by the compiler. - if (!is_same<T, unused_type>::value) - frac_digits = - static_cast<int>(std::distance(savef, first)); } else if (!got_a_number || !p.allow_trailing_dot) { @@ -195,6 +244,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail } // Now, let's see if we can parse the exponent prefix + e_pos = first; e_hit = p.parse_exp(first, last); } else @@ -208,6 +258,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail // If we must expect a dot and we didn't see an exponent // prefix, return no-match. + e_pos = first; e_hit = p.parse_exp(first, last); if (p.expect_dot && !e_hit) { @@ -219,27 +270,29 @@ namespace boost { namespace spirit { namespace qi { namespace detail if (e_hit) { // We got the exponent prefix. Now we will try to parse the - // actual exponent. It is an error if it is not there. + // actual exponent. int exp = 0; if (p.parse_exp_n(first, last, exp)) { // Got the exponent value. Scale the number by // exp-frac_digits. - traits::scale(exp, frac_digits, n); + if (!traits::scale(exp, frac_digits, n, acc_n)) + return false; } else { - // Oops, no exponent, return no-match. - first = save; - return false; + // If there is no number, disregard the exponent altogether. + // by resetting 'first' prior to the exponent prefix (e|E) + first = e_pos; + n = acc_n; } } else if (frac_digits) { // No exponent found. Scale the number by -frac_digits. - traits::scale(-frac_digits, n); + traits::scale(-frac_digits, n, acc_n); } - else if (traits::is_equal_to_one(n)) + else if (traits::is_equal_to_one(acc_n)) { // There is a chance of having to parse one of the 1.0#... // styles some implementations use for representing NaN or Inf. @@ -252,6 +305,12 @@ namespace boost { namespace spirit { namespace qi { namespace detail traits::assign_to(traits::negate(neg, n), attr); return true; // got a NaN or Inf, return immediately } + + n = acc_n; + } + else + { + n = acc_n; } // If we got a negative sign, negate the number diff --git a/boost/spirit/home/qi/numeric/numeric_utils.hpp b/boost/spirit/home/qi/numeric/numeric_utils.hpp index eebf40a0fa..c37044a3b6 100644 --- a/boost/spirit/home/qi/numeric/numeric_utils.hpp +++ b/boost/spirit/home/qi/numeric/numeric_utils.hpp @@ -44,7 +44,7 @@ namespace boost { namespace spirit { namespace qi // Low level unsigned integer parser /////////////////////////////////////////////////////////////////////////// template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits - , bool Accumulate = false> + , bool Accumulate = false, bool IgnoreOverflowDigits = false> struct extract_uint { // check template parameter 'Radix' for validity @@ -64,7 +64,8 @@ namespace boost { namespace spirit { namespace qi , MinDigits , MaxDigits , detail::positive_accumulator<Radix> - , Accumulate> + , Accumulate + , IgnoreOverflowDigits> extract_type; Iterator save = first; diff --git a/boost/spirit/home/qi/numeric/real_policies.hpp b/boost/spirit/home/qi/numeric/real_policies.hpp index d4f5654b5b..d73a9dce8a 100644 --- a/boost/spirit/home/qi/numeric/real_policies.hpp +++ b/boost/spirit/home/qi/numeric/real_policies.hpp @@ -39,7 +39,7 @@ namespace boost { namespace spirit { namespace qi static bool parse_n(Iterator& first, Iterator const& last, Attribute& attr_) { - return extract_uint<T, 10, 1, -1>::call(first, last, attr_); + return extract_uint<Attribute, 10, 1, -1>::call(first, last, attr_); } template <typename Iterator> @@ -54,9 +54,21 @@ namespace boost { namespace spirit { namespace qi template <typename Iterator, typename Attribute> static bool - parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr_) + parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr_, int& frac_digits) { - return extract_uint<T, 10, 1, -1, true>::call(first, last, attr_); + Iterator savef = first; + bool r = extract_uint<Attribute, 10, 1, -1, true, true>::call(first, last, attr_); + if (r) + { + // Optimization note: don't compute frac_digits if T is + // an unused_type. This should be optimized away by the compiler. + if (!is_same<T, unused_type>::value) + frac_digits = + static_cast<int>(std::distance(savef, first)); + // ignore extra (non-significant digits) + extract_uint<unused_type, 10, 1, -1>::call(first, last, unused); + } + return r; } template <typename Iterator> |