Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-19 09:47:45

0001 /*=============================================================================
0002     Copyright (c) 2001-2019 Joel de Guzman
0003     Copyright (c) 2001-2011 Hartmut Kaiser
0004     http://spirit.sourceforge.net/
0005 
0006     Distributed under the Boost Software License, Version 1.0. (See accompanying
0007     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0008 =============================================================================*/
0009 #ifndef BOOST_SPIRIT_QI_NUMERIC_DETAIL_REAL_IMPL_HPP
0010 #define BOOST_SPIRIT_QI_NUMERIC_DETAIL_REAL_IMPL_HPP
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <cmath>
0017 #include <boost/limits.hpp>
0018 #include <boost/type_traits/is_same.hpp>
0019 #include <boost/spirit/home/support/unused.hpp>
0020 #include <boost/spirit/home/qi/detail/attributes.hpp>
0021 #include <boost/spirit/home/support/detail/pow10.hpp>
0022 #include <boost/integer.hpp>
0023 #include <boost/assert.hpp>
0024 
0025 #include <boost/core/cmath.hpp>
0026 
0027 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0028 # pragma warning(push)
0029 # pragma warning(disable: 4100)   // 'p': unreferenced formal parameter
0030 # pragma warning(disable: 4127)   // conditional expression is constant
0031 #endif
0032 
0033 namespace boost { namespace spirit { namespace traits
0034 {
0035     using spirit::traits::pow10;
0036 
0037     namespace detail
0038     {
0039         template <typename T, typename AccT>
0040         void compensate_roundoff(T& n, AccT acc_n, mpl::true_)
0041         {
0042             // at the lowest extremes, we compensate for floating point
0043             // roundoff errors by doing imprecise computation using T
0044             int const comp = 10;
0045             n = T((acc_n / comp) * comp);
0046             n += T(acc_n % comp);
0047         }
0048 
0049         template <typename T, typename AccT>
0050         void compensate_roundoff(T& n, AccT acc_n, mpl::false_)
0051         {
0052             // no need to compensate
0053             n = acc_n;
0054         }
0055 
0056         template <typename T, typename AccT>
0057         void compensate_roundoff(T& n, AccT acc_n)
0058         {
0059             compensate_roundoff(n, acc_n, is_integral<AccT>());
0060         }
0061     }
0062 
0063     template <typename T, typename AccT>
0064     inline bool
0065     scale(int exp, T& n, AccT acc_n)
0066     {
0067         if (exp >= 0)
0068         {
0069             int const max_exp = std::numeric_limits<T>::max_exponent10;
0070 
0071             // return false if exp exceeds the max_exp
0072             // do this check only for primitive types!
0073             if (is_floating_point<T>() && (exp > max_exp))
0074                 return false;
0075             n = acc_n * pow10<T>(exp);
0076         }
0077         else
0078         {
0079             if (exp < std::numeric_limits<T>::min_exponent10)
0080             {
0081                 int const min_exp = std::numeric_limits<T>::min_exponent10;
0082                 detail::compensate_roundoff(n, acc_n);
0083                 n /= pow10<T>(-min_exp);
0084 
0085                 // return false if exp still exceeds the min_exp
0086                 // do this check only for primitive types!
0087                 exp += -min_exp;
0088                 if (is_floating_point<T>() && exp < min_exp)
0089                     return false;
0090 
0091                 n /= pow10<T>(-exp);
0092             }
0093             else
0094             {
0095                 n = T(acc_n) / pow10<T>(-exp);
0096             }
0097         }
0098         return true;
0099     }
0100 
0101     inline bool
0102     scale(int /*exp*/, unused_type /*n*/, unused_type /*acc_n*/)
0103     {
0104         // no-op for unused_type
0105         return true;
0106     }
0107 
0108     template <typename T, typename AccT>
0109     inline bool
0110     scale(int exp, int frac, T& n, AccT acc_n)
0111     {
0112         return scale(exp - frac, n, acc_n);
0113     }
0114 
0115     inline bool
0116     scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
0117     {
0118         // no-op for unused_type
0119         return true;
0120     }
0121 
0122     inline float
0123     negate(bool neg, float n)
0124     {
0125         return neg ? (core::copysign)(n, -1.f) : n;
0126     }
0127 
0128     inline double
0129     negate(bool neg, double n)
0130     {
0131         return neg ? (core::copysign)(n, -1.) : n;
0132     }
0133 
0134     inline long double
0135     negate(bool neg, long double n)
0136     {
0137         return neg ? (core::copysign)(n, static_cast<long double>(-1)) : n;
0138     }
0139 
0140     template <typename T>
0141     inline T
0142     negate(bool neg, T const& n)
0143     {
0144         return neg ? -n : n;
0145     }
0146 
0147     inline unused_type
0148     negate(bool /*neg*/, unused_type n)
0149     {
0150         // no-op for unused_type
0151         return n;
0152     }
0153 
0154     template <typename T>
0155     struct real_accumulator : mpl::identity<T> {};
0156 
0157     template <>
0158     struct real_accumulator<float>
0159         : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {};
0160 
0161     template <>
0162     struct real_accumulator<double>
0163         : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {};
0164 }}}
0165 
0166 namespace boost { namespace spirit { namespace qi  { namespace detail
0167 {
0168     BOOST_MPL_HAS_XXX_TRAIT_DEF(version)
0169 
0170     template <typename T, typename RealPolicies>
0171     struct real_impl
0172     {
0173         template <typename Iterator>
0174         static std::size_t
0175         ignore_excess_digits(Iterator& /* first */, Iterator const& /* last */, mpl::false_)
0176         {
0177             return 0;
0178         }
0179 
0180         template <typename Iterator>
0181         static std::size_t
0182         ignore_excess_digits(Iterator& first, Iterator const& last, mpl::true_)
0183         {
0184             return RealPolicies::ignore_excess_digits(first, last);
0185         }
0186 
0187         template <typename Iterator>
0188         static std::size_t
0189         ignore_excess_digits(Iterator& first, Iterator const& last)
0190         {
0191             typedef mpl::bool_<has_version<RealPolicies>::value> has_version;
0192             return ignore_excess_digits(first, last, has_version());
0193         }
0194 
0195         template <typename Iterator, typename Attribute>
0196         static bool
0197         parse(Iterator& first, Iterator const& last, Attribute& attr,
0198             RealPolicies const& p)
0199         {
0200             if (first == last)
0201                 return false;
0202             Iterator save = first;
0203 
0204             // Start by parsing the sign. neg will be true if
0205             // we got a "-" sign, false otherwise.
0206             bool neg = p.parse_sign(first, last);
0207 
0208             // Now attempt to parse an integer
0209             T n;
0210 
0211             typename traits::real_accumulator<T>::type acc_n = 0;
0212             bool got_a_number = p.parse_n(first, last, acc_n);
0213             int excess_n = 0;
0214 
0215             // If we did not get a number it might be a NaN, Inf or a leading
0216             // dot.
0217             if (!got_a_number)
0218             {
0219                 // Check whether the number to parse is a NaN or Inf
0220                 if (p.parse_nan(first, last, n) ||
0221                     p.parse_inf(first, last, n))
0222                 {
0223                     // If we got a negative sign, negate the number
0224                     traits::assign_to(traits::negate(neg, n), attr);
0225                     return true;    // got a NaN or Inf, return early
0226                 }
0227 
0228                 // If we did not get a number and our policies do not
0229                 // allow a leading dot, fail and return early (no-match)
0230                 if (!p.allow_leading_dot)
0231                 {
0232                     first = save;
0233                     return false;
0234                 }
0235             }
0236             else
0237             {
0238                 // We got a number and we still see digits. This happens if acc_n (an integer)
0239                 // exceeds the integer's capacity. Collect the excess digits.
0240                 excess_n = static_cast<int>(ignore_excess_digits(first, last));
0241             }
0242 
0243             bool e_hit = false;
0244             Iterator e_pos;
0245             int frac_digits = 0;
0246 
0247             // Try to parse the dot ('.' decimal point)
0248             if (p.parse_dot(first, last))
0249             {
0250                 // We got the decimal point. Now we will try to parse
0251                 // the fraction if it is there. If not, it defaults
0252                 // to zero (0) only if we already got a number.
0253                 if (excess_n != 0)
0254                 {
0255                     // We skip the fractions if we already exceeded our digits capacity
0256                     ignore_excess_digits(first, last);
0257                 }
0258                 else if (p.parse_frac_n(first, last, acc_n, frac_digits))
0259                 {
0260                     BOOST_ASSERT(frac_digits >= 0);
0261                 }
0262                 else if (!got_a_number || !p.allow_trailing_dot)
0263                 {
0264                     // We did not get a fraction. If we still haven't got a
0265                     // number and our policies do not allow a trailing dot,
0266                     // return no-match.
0267                     first = save;
0268                     return false;
0269                 }
0270 
0271                 // Now, let's see if we can parse the exponent prefix
0272                 e_pos = first;
0273                 e_hit = p.parse_exp(first, last);
0274             }
0275             else
0276             {
0277                 // No dot and no number! Return no-match.
0278                 if (!got_a_number)
0279                 {
0280                     first = save;
0281                     return false;
0282                 }
0283 
0284                 // If we must expect a dot and we didn't see an exponent
0285                 // prefix, return no-match.
0286                 e_pos = first;
0287                 e_hit = p.parse_exp(first, last);
0288                 if (p.expect_dot && !e_hit)
0289                 {
0290                     first = save;
0291                     return false;
0292                 }
0293             }
0294 
0295             if (e_hit)
0296             {
0297                 // We got the exponent prefix. Now we will try to parse the
0298                 // actual exponent.
0299                 int exp = 0;
0300                 if (p.parse_exp_n(first, last, exp))
0301                 {
0302                     // Got the exponent value. Scale the number by
0303                     // exp + excess_n - frac_digits.
0304                     if (!traits::scale(exp + excess_n, frac_digits, n, acc_n))
0305                         return false;
0306                 }
0307                 else
0308                 {
0309                     // If there is no number, disregard the exponent altogether.
0310                     // by resetting 'first' prior to the exponent prefix (e|E)
0311                     first = e_pos;
0312                     // Scale the number by -frac_digits.
0313                     bool r = traits::scale(-frac_digits, n, acc_n);
0314                     BOOST_VERIFY(r);
0315                 }
0316             }
0317             else if (frac_digits)
0318             {
0319                 // No exponent found. Scale the number by -frac_digits.
0320                 bool r = traits::scale(-frac_digits, n, acc_n);
0321                 BOOST_VERIFY(r);
0322             }
0323             else
0324             {
0325                 if (excess_n)
0326                 {
0327                     if (!traits::scale(excess_n, n, acc_n))
0328                         return false;
0329                 }
0330                 else
0331                 {
0332                     n = static_cast<T>(acc_n);
0333                 }
0334             }
0335 
0336             // If we got a negative sign, negate the number
0337             traits::assign_to(traits::negate(neg, n), attr);
0338 
0339             // Success!!!
0340             return true;
0341         }
0342     };
0343 
0344 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0345 # pragma warning(pop)
0346 #endif
0347 
0348 }}}}
0349 
0350 #endif