LCOV - code coverage report
Current view: top level - usr/include/boost/spirit/home/classic/core/primitives/impl - numerics.ipp (source / functions) Hit Total Coverage
Test: ROSE Lines: 0 42 0.0 %
Date: 2022-12-08 13:48:47 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*=============================================================================
       2             :     Copyright (c) 1998-2003 Joel de Guzman
       3             :     Copyright (c) 2001-2003 Hartmut Kaiser
       4             :     http://spirit.sourceforge.net/
       5             : 
       6             :     Use, modification and distribution is subject to the Boost Software
       7             :     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
       8             :     http://www.boost.org/LICENSE_1_0.txt)
       9             : =============================================================================*/
      10             : #ifndef BOOST_SPIRIT_NUMERICS_IPP
      11             : #define BOOST_SPIRIT_NUMERICS_IPP
      12             : 
      13             : #include <boost/config/no_tr1/cmath.hpp>
      14             : #include <limits>
      15             : 
      16             : namespace boost { namespace spirit {
      17             : 
      18             : BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
      19             : 
      20             :     struct sign_parser; // forward declaration only
      21             : 
      22             :     namespace impl
      23             :     {
      24             :         ///////////////////////////////////////////////////////////////////////
      25             :         //
      26             :         //  Extract the prefix sign (- or +)
      27             :         //
      28             :         ///////////////////////////////////////////////////////////////////////
      29             :         template <typename ScannerT>
      30             :         bool
      31           0 :         extract_sign(ScannerT const& scan, std::size_t& count)
      32             :         {
      33             :             //  Extract the sign
      34           0 :             count = 0;
      35           0 :             bool neg = *scan == '-';
      36           0 :             if (neg || (*scan == '+'))
      37             :             {
      38           0 :                 ++scan;
      39           0 :                 ++count;
      40             :                 return neg;
      41             :             }
      42             : 
      43             :             return false;
      44             :         }
      45             : 
      46             :         ///////////////////////////////////////////////////////////////////////
      47             :         //
      48             :         //  Traits class for radix specific number conversion
      49             :         //
      50             :         //      Convert a digit from character representation, ch, to binary
      51             :         //      representation, returned in val.
      52             :         //      Returns whether the conversion was successful.
      53             :         //
      54             :         //        template<typename CharT> static bool digit(CharT ch, T& val);
      55             :         //
      56             :         ///////////////////////////////////////////////////////////////////////
      57             :         template<const int Radix>
      58             :         struct radix_traits;
      59             : 
      60             :         ////////////////////////////////// Binary
      61             :         template<>
      62             :         struct radix_traits<2>
      63             :         {
      64             :             template<typename CharT, typename T>
      65             :             static bool digit(CharT ch, T& val)
      66             :             {
      67             :                 val = ch - '0';
      68             :                 return ('0' == ch || '1' == ch);
      69             :             }
      70             :         };
      71             : 
      72             :         ////////////////////////////////// Octal
      73             :         template<>
      74             :         struct radix_traits<8>
      75             :         {
      76             :             template<typename CharT, typename T>
      77             :             static bool digit(CharT ch, T& val)
      78             :             {
      79             :                 val = ch - '0';
      80             :                 return ('0' <= ch && ch <= '7');
      81             :             }
      82             :         };
      83             : 
      84             :         ////////////////////////////////// Decimal
      85             :         template<>
      86             :         struct radix_traits<10>
      87             :         {
      88             :             template<typename CharT, typename T>
      89           0 :             static bool digit(CharT ch, T& val)
      90             :             {
      91           0 :                 val = ch - '0';
      92           0 :                 return impl::isdigit_(ch);
      93             :             }
      94             :         };
      95             : 
      96             :         ////////////////////////////////// Hexadecimal
      97             :         template<>
      98             :         struct radix_traits<16>
      99             :         {
     100             :             template<typename CharT, typename T>
     101             :             static bool digit(CharT ch, T& val)
     102             :             {
     103             :                 if (radix_traits<10>::digit(ch, val))
     104             :                     return true;
     105             : 
     106             :                 CharT lc = impl::tolower_(ch);
     107             :                 if ('a' <= lc && lc <= 'f')
     108             :                 {
     109             :                     val = lc - 'a' + 10;
     110             :                     return true;
     111             :                 }
     112             :                 return false;
     113             :             }
     114             :         };
     115             : 
     116             :         ///////////////////////////////////////////////////////////////////////
     117             :         //
     118             :         //      Helper templates for encapsulation of radix specific
     119             :         //      conversion of an input string to an integral value.
     120             :         //
     121             :         //      main entry point:
     122             :         //
     123             :         //          extract_int<Radix, MinDigits, MaxDigits, Accumulate>
     124             :         //              ::f(first, last, n, count);
     125             :         //
     126             :         //          The template parameter Radix represents the radix of the
     127             :         //          number contained in the parsed string. The template
     128             :         //          parameter MinDigits specifies the minimum digits to
     129             :         //          accept. The template parameter MaxDigits specifies the
     130             :         //          maximum digits to parse. A -1 value for MaxDigits will
     131             :         //          make it parse an arbitrarilly large number as long as the
     132             :         //          numeric type can hold it. Accumulate is either
     133             :         //          positive_accumulate<Radix> (default) for parsing positive
     134             :         //          numbers or negative_accumulate<Radix> otherwise.
     135             :         //          Checking is only performed when std::numeric_limits<T>::
     136             :         //          is_specialized is true. Otherwise, there's no way to
     137             :         //          do the check.
     138             :         //
     139             :         //          scan.first and scan.last are iterators as usual (i.e.
     140             :         //          first is mutable and is moved forward when a match is
     141             :         //          found), n is a variable that holds the number (passed by
     142             :         //          reference). The number of parsed characters is added to
     143             :         //          count (also passed by reference)
     144             :         //
     145             :         //      NOTE:
     146             :         //              Returns a non-match, if the number to parse
     147             :         //              overflows (or underflows) the used type.
     148             :         //
     149             :         //      BEWARE:
     150             :         //              the parameters 'n' and 'count' should be properly
     151             :         //              initialized before calling this function.
     152             :         //
     153             :         ///////////////////////////////////////////////////////////////////////
     154             : #if defined(BOOST_MSVC)
     155             : #pragma warning(push) 
     156             : #pragma warning(disable:4127) //conditional expression is constant
     157             : #endif
     158             :         
     159             :         template <typename T, int Radix>
     160             :         struct positive_accumulate
     161             :         {
     162             :             //  Use this accumulator if number is positive
     163           0 :             static bool add(T& n, T digit)
     164             :             {
     165             :                 if (std::numeric_limits<T>::is_specialized)
     166             :                 {
     167             :                     static T const max = (std::numeric_limits<T>::max)();
     168             :                     static T const max_div_radix = max/Radix;
     169             : 
     170           0 :                     if (n > max_div_radix)
     171             :                         return false;
     172           0 :                     n *= Radix;
     173             : 
     174           0 :                     if (n > max - digit)
     175             :                         return false;
     176           0 :                     n += digit;
     177             : 
     178             :                     return true;
     179             :                 }
     180             :                 else
     181             :                 {
     182             :                     n *= Radix;
     183             :                     n += digit;
     184             :                     return true;
     185             :                 }
     186             :             }
     187             :         };
     188             : 
     189             :         template <typename T, int Radix>
     190             :         struct negative_accumulate
     191             :         {
     192             :             //  Use this accumulator if number is negative
     193           0 :             static bool add(T& n, T digit)
     194             :             {
     195             :                 if (std::numeric_limits<T>::is_specialized)
     196             :                 {
     197             :                     typedef std::numeric_limits<T> num_limits;
     198             :                     static T const min =
     199             :                         (!num_limits::is_integer && num_limits::is_signed && num_limits::has_denorm) ?
     200             :                         -(num_limits::max)() : (num_limits::min)();
     201             :                     static T const min_div_radix = min/Radix;
     202             : 
     203           0 :                     if (n < min_div_radix)
     204             :                         return false;
     205           0 :                     n *= Radix;
     206             : 
     207           0 :                     if (n < min + digit)
     208             :                         return false;
     209           0 :                     n -= digit;
     210             : 
     211             :                     return true;
     212             :                 }
     213             :                 else
     214             :                 {
     215             :                     n *= Radix;
     216             :                     n -= digit;
     217             :                     return true;
     218             :                 }
     219             :             }
     220             :         };
     221             : 
     222             :         template <int MaxDigits>
     223             :         inline bool allow_more_digits(std::size_t i)
     224             :         {
     225             :             return i < MaxDigits;
     226             :         }
     227             : 
     228             :         template <>
     229           0 :         inline bool allow_more_digits<-1>(std::size_t)
     230             :         {
     231           0 :             return true;
     232             :         }
     233             : 
     234             :         //////////////////////////////////
     235             :         template <
     236             :             int Radix, unsigned MinDigits, int MaxDigits,
     237             :             typename Accumulate
     238             :         >
     239             :         struct extract_int
     240             :         {
     241             :             template <typename ScannerT, typename T>
     242             :             static bool
     243           0 :             f(ScannerT& scan, T& n, std::size_t& count)
     244             :             {
     245           0 :                 std::size_t i = 0;
     246             :                 T digit;
     247           0 :                 while( allow_more_digits<MaxDigits>(i) && !scan.at_end() &&
     248           0 :                     radix_traits<Radix>::digit(*scan, digit) )
     249             :                 {
     250           0 :                     if (!Accumulate::add(n, digit))
     251           0 :                         return false; // Overflow
     252           0 :                     ++i, ++scan, ++count;
     253             :                 }
     254           0 :                 return i >= MinDigits;
     255             :             }
     256             :         };
     257             : 
     258             :         ///////////////////////////////////////////////////////////////////////
     259             :         //
     260             :         //  uint_parser_impl class
     261             :         //
     262             :         ///////////////////////////////////////////////////////////////////////
     263             :         template <
     264             :             typename T = unsigned,
     265             :             int Radix = 10,
     266             :             unsigned MinDigits = 1,
     267             :             int MaxDigits = -1
     268             :         >
     269             :         struct uint_parser_impl
     270             :             : parser<uint_parser_impl<T, Radix, MinDigits, MaxDigits> >
     271             :         {
     272             :             typedef uint_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
     273             : 
     274             :             template <typename ScannerT>
     275             :             struct result
     276             :             {
     277             :                 typedef typename match_result<ScannerT, T>::type type;
     278             :             };
     279             : 
     280             :             template <typename ScannerT>
     281             :             typename parser_result<self_t, ScannerT>::type
     282             :             parse(ScannerT const& scan) const
     283             :             {
     284             :                 if (!scan.at_end())
     285             :                 {
     286             :                     T n = 0;
     287             :                     std::size_t count = 0;
     288             :                     typename ScannerT::iterator_t save = scan.first;
     289             :                     if (extract_int<Radix, MinDigits, MaxDigits,
     290             :                         positive_accumulate<T, Radix> >::f(scan, n, count))
     291             :                     {
     292             :                         return scan.create_match(count, n, save, scan.first);
     293             :                     }
     294             :                     // return no-match if number overflows
     295             :                 }
     296             :                 return scan.no_match();
     297             :             }
     298             :         };
     299             : 
     300             :         ///////////////////////////////////////////////////////////////////////
     301             :         //
     302             :         //  int_parser_impl class
     303             :         //
     304             :         ///////////////////////////////////////////////////////////////////////
     305             :         template <
     306             :             typename T = unsigned,
     307             :             int Radix = 10,
     308             :             unsigned MinDigits = 1,
     309             :             int MaxDigits = -1
     310             :         >
     311             :         struct int_parser_impl
     312             :             : parser<int_parser_impl<T, Radix, MinDigits, MaxDigits> >
     313             :         {
     314             :             typedef int_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
     315             : 
     316             :             template <typename ScannerT>
     317             :             struct result
     318             :             {
     319             :                 typedef typename match_result<ScannerT, T>::type type;
     320             :             };
     321             : 
     322             :             template <typename ScannerT>
     323             :             typename parser_result<self_t, ScannerT>::type
     324           0 :             parse(ScannerT const& scan) const
     325             :             {
     326             :                 typedef extract_int<Radix, MinDigits, MaxDigits,
     327             :                     negative_accumulate<T, Radix> > extract_int_neg_t;
     328             :                 typedef extract_int<Radix, MinDigits, MaxDigits,
     329             :                     positive_accumulate<T, Radix> > extract_int_pos_t;
     330             : 
     331           0 :                 if (!scan.at_end())
     332             :                 {
     333           0 :                     T n = 0;
     334           0 :                     std::size_t count = 0;
     335           0 :                     typename ScannerT::iterator_t save = scan.first;
     336             : 
     337           0 :                     bool hit = impl::extract_sign(scan, count);
     338             : 
     339           0 :                     if (hit)
     340           0 :                         hit = extract_int_neg_t::f(scan, n, count);
     341             :                     else
     342           0 :                         hit = extract_int_pos_t::f(scan, n, count);
     343             : 
     344           0 :                     if (hit)
     345           0 :                         return scan.create_match(count, n, save, scan.first);
     346             :                     else
     347           0 :                         scan.first = save;
     348             :                     // return no-match if number overflows or underflows
     349             :                 }
     350           0 :                 return scan.no_match();
     351             :             }
     352             :         };
     353             : 
     354             :         ///////////////////////////////////////////////////////////////////////
     355             :         //
     356             :         //  real_parser_impl class
     357             :         //
     358             :         ///////////////////////////////////////////////////////////////////////
     359             :         template <typename RT, typename T, typename RealPoliciesT>
     360             :         struct real_parser_impl
     361             :         {
     362             :             typedef real_parser_impl<RT, T, RealPoliciesT> self_t;
     363             : 
     364             :             template <typename ScannerT>
     365             :             RT parse_main(ScannerT const& scan) const
     366             :             {
     367             :                 if (scan.at_end())
     368             :                     return scan.no_match();
     369             :                 typename ScannerT::iterator_t save = scan.first;
     370             : 
     371             :                 typedef typename parser_result<sign_parser, ScannerT>::type
     372             :                     sign_match_t;
     373             :                 typedef typename parser_result<chlit<>, ScannerT>::type
     374             :                     exp_match_t;
     375             : 
     376             :                 sign_match_t    sign_match = RealPoliciesT::parse_sign(scan);
     377             :                 std::size_t     count = sign_match ? sign_match.length() : 0;
     378             :                 bool            neg = sign_match.has_valid_attribute() ?
     379             :                                     sign_match.value() : false;
     380             : 
     381             :                 RT              n_match = RealPoliciesT::parse_n(scan);
     382             :                 T               n = n_match.has_valid_attribute() ?
     383             :                                     n_match.value() : T(0);
     384             :                 bool            got_a_number = n_match;
     385             :                 exp_match_t     e_hit;
     386             : 
     387             :                 if (!got_a_number && !RealPoliciesT::allow_leading_dot)
     388             :                      return scan.no_match();
     389             :                 else
     390             :                     count += n_match.length();
     391             : 
     392             :                 if (neg)
     393             :                     n = -n;
     394             : 
     395             :                 if (RealPoliciesT::parse_dot(scan))
     396             :                 {
     397             :                     //  We got the decimal point. Now we will try to parse
     398             :                     //  the fraction if it is there. If not, it defaults
     399             :                     //  to zero (0) only if we already got a number.
     400             : 
     401             :                     if (RT hit = RealPoliciesT::parse_frac_n(scan))
     402             :                     {
     403             : #if !defined(BOOST_NO_STDC_NAMESPACE)
     404             :                         using namespace std;  // allow for ADL to find pow()
     405             : #endif
     406             :                         hit.value(hit.value()
     407             :                             * pow(T(10), T(-hit.length())));
     408             :                         if (neg)
     409             :                             n -= hit.value();
     410             :                         else
     411             :                             n += hit.value();
     412             :                         count += hit.length() + 1;
     413             : 
     414             :                     }
     415             : 
     416             :                     else if (!got_a_number ||
     417             :                         !RealPoliciesT::allow_trailing_dot)
     418             :                         return scan.no_match();
     419             : 
     420             :                     e_hit = RealPoliciesT::parse_exp(scan);
     421             :                 }
     422             :                 else
     423             :                 {
     424             :                     //  We have reached a point where we
     425             :                     //  still haven't seen a number at all.
     426             :                     //  We return early with a no-match.
     427             :                     if (!got_a_number)
     428             :                         return scan.no_match();
     429             : 
     430             :                     //  If we must expect a dot and we didn't see
     431             :                     //  an exponent, return early with a no-match.
     432             :                     e_hit = RealPoliciesT::parse_exp(scan);
     433             :                     if (RealPoliciesT::expect_dot && !e_hit)
     434             :                         return scan.no_match();
     435             :                 }
     436             : 
     437             :                 if (e_hit)
     438             :                 {
     439             :                     //  We got the exponent prefix. Now we will try to parse the
     440             :                     //  actual exponent. It is an error if it is not there.
     441             :                     if (RT e_n_hit = RealPoliciesT::parse_exp_n(scan))
     442             :                     {
     443             : #if !defined(BOOST_NO_STDC_NAMESPACE)
     444             :                         using namespace std;    // allow for ADL to find pow()
     445             : #endif
     446             :                         n *= pow(T(10), T(e_n_hit.value()));
     447             :                         count += e_n_hit.length() + e_hit.length();
     448             :                     }
     449             :                     else
     450             :                     {
     451             :                         //  Oops, no exponent, return a no-match
     452             :                         return scan.no_match();
     453             :                     }
     454             :                 }
     455             : 
     456             :                 return scan.create_match(count, n, save, scan.first);
     457             :             }
     458             : 
     459             :             template <typename ScannerT>
     460             :             static RT parse(ScannerT const& scan)
     461             :             {
     462             :                 static self_t this_;
     463             :                 return impl::implicit_lexeme_parse<RT>(this_, scan, scan);
     464             :             }
     465             :         };
     466             : 
     467             : #if defined(BOOST_MSVC)
     468             : #pragma warning(pop)
     469             : #endif
     470             : 
     471             :     }   //  namespace impl
     472             : 
     473             : ///////////////////////////////////////////////////////////////////////////////
     474             : BOOST_SPIRIT_CLASSIC_NAMESPACE_END
     475             : 
     476             : }} // namespace boost::spirit
     477             : 
     478             : #endif

Generated by: LCOV version 1.14