EVOLUTION-MANAGER
Edit File: numerics.ipp
/*============================================================================= Copyright (c) 1998-2003 Joel de Guzman Copyright (c) 2001-2003 Hartmut Kaiser http://spirit.sourceforge.net/ Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #ifndef BOOST_SPIRIT_NUMERICS_IPP #define BOOST_SPIRIT_NUMERICS_IPP #include <boost/config/no_tr1/cmath.hpp> #include <limits> namespace boost { namespace spirit { BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN struct sign_parser; // forward declaration only namespace impl { /////////////////////////////////////////////////////////////////////// // // Extract the prefix sign (- or +) // /////////////////////////////////////////////////////////////////////// template <typename ScannerT> bool extract_sign(ScannerT const& scan, std::size_t& count) { // Extract the sign count = 0; bool neg = *scan == '-'; if (neg || (*scan == '+')) { ++scan; ++count; return neg; } return false; } /////////////////////////////////////////////////////////////////////// // // Traits class for radix specific number conversion // // Convert a digit from character representation, ch, to binary // representation, returned in val. // Returns whether the conversion was successful. // // template<typename CharT> static bool digit(CharT ch, T& val); // /////////////////////////////////////////////////////////////////////// template<const int Radix> struct radix_traits; ////////////////////////////////// Binary template<> struct radix_traits<2> { template<typename CharT, typename T> static bool digit(CharT ch, T& val) { val = ch - '0'; return ('0' == ch || '1' == ch); } }; ////////////////////////////////// Octal template<> struct radix_traits<8> { template<typename CharT, typename T> static bool digit(CharT ch, T& val) { val = ch - '0'; return ('0' <= ch && ch <= '7'); } }; ////////////////////////////////// Decimal template<> struct radix_traits<10> { template<typename CharT, typename T> static bool digit(CharT ch, T& val) { val = ch - '0'; return impl::isdigit_(ch); } }; ////////////////////////////////// Hexadecimal template<> struct radix_traits<16> { template<typename CharT, typename T> static bool digit(CharT ch, T& val) { if (radix_traits<10>::digit(ch, val)) return true; CharT lc = impl::tolower_(ch); if ('a' <= lc && lc <= 'f') { val = lc - 'a' + 10; return true; } return false; } }; /////////////////////////////////////////////////////////////////////// // // Helper templates for encapsulation of radix specific // conversion of an input string to an integral value. // // main entry point: // // extract_int<Radix, MinDigits, MaxDigits, Accumulate> // ::f(first, last, n, count); // // The template parameter Radix represents the radix of the // number contained in the parsed string. The template // parameter MinDigits specifies the minimum digits to // accept. The template parameter MaxDigits specifies the // maximum digits to parse. A -1 value for MaxDigits will // make it parse an arbitrarilly large number as long as the // numeric type can hold it. Accumulate is either // positive_accumulate<Radix> (default) for parsing positive // numbers or negative_accumulate<Radix> otherwise. // Checking is only performed when std::numeric_limits<T>:: // is_specialized is true. Otherwise, there's no way to // do the check. // // scan.first and scan.last are iterators as usual (i.e. // first is mutable and is moved forward when a match is // found), n is a variable that holds the number (passed by // reference). The number of parsed characters is added to // count (also passed by reference) // // NOTE: // Returns a non-match, if the number to parse // overflows (or underflows) the used type. // // BEWARE: // the parameters 'n' and 'count' should be properly // initialized before calling this function. // /////////////////////////////////////////////////////////////////////// #if defined(BOOST_MSVC) #pragma warning(push) #pragma warning(disable:4127) //conditional expression is constant #endif template <typename T, int Radix> struct positive_accumulate { // Use this accumulator if number is positive static bool add(T& n, T digit) { if (std::numeric_limits<T>::is_specialized) { static T const max = (std::numeric_limits<T>::max)(); static T const max_div_radix = max/Radix; if (n > max_div_radix) return false; n *= Radix; if (n > max - digit) return false; n += digit; return true; } else { n *= Radix; n += digit; return true; } } }; template <typename T, int Radix> struct negative_accumulate { // Use this accumulator if number is negative static bool add(T& n, T digit) { if (std::numeric_limits<T>::is_specialized) { typedef std::numeric_limits<T> num_limits; static T const min = (!num_limits::is_integer && num_limits::is_signed && num_limits::has_denorm) ? -(num_limits::max)() : (num_limits::min)(); static T const min_div_radix = min/Radix; if (n < min_div_radix) return false; n *= Radix; if (n < min + digit) return false; n -= digit; return true; } else { n *= Radix; n -= digit; return true; } } }; template <int MaxDigits> inline bool allow_more_digits(std::size_t i) { return i < MaxDigits; } template <> inline bool allow_more_digits<-1>(std::size_t) { return true; } ////////////////////////////////// template < int Radix, unsigned MinDigits, int MaxDigits, typename Accumulate > struct extract_int { template <typename ScannerT, typename T> static bool f(ScannerT& scan, T& n, std::size_t& count) { std::size_t i = 0; T digit; while( allow_more_digits<MaxDigits>(i) && !scan.at_end() && radix_traits<Radix>::digit(*scan, digit) ) { if (!Accumulate::add(n, digit)) return false; // Overflow ++i, ++scan, ++count; } return i >= MinDigits; } }; /////////////////////////////////////////////////////////////////////// // // uint_parser_impl class // /////////////////////////////////////////////////////////////////////// template < typename T = unsigned, int Radix = 10, unsigned MinDigits = 1, int MaxDigits = -1 > struct uint_parser_impl : parser<uint_parser_impl<T, Radix, MinDigits, MaxDigits> > { typedef uint_parser_impl<T, Radix, MinDigits, MaxDigits> self_t; template <typename ScannerT> struct result { typedef typename match_result<ScannerT, T>::type type; }; template <typename ScannerT> typename parser_result<self_t, ScannerT>::type parse(ScannerT const& scan) const { if (!scan.at_end()) { T n = 0; std::size_t count = 0; typename ScannerT::iterator_t save = scan.first; if (extract_int<Radix, MinDigits, MaxDigits, positive_accumulate<T, Radix> >::f(scan, n, count)) { return scan.create_match(count, n, save, scan.first); } // return no-match if number overflows } return scan.no_match(); } }; /////////////////////////////////////////////////////////////////////// // // int_parser_impl class // /////////////////////////////////////////////////////////////////////// template < typename T = unsigned, int Radix = 10, unsigned MinDigits = 1, int MaxDigits = -1 > struct int_parser_impl : parser<int_parser_impl<T, Radix, MinDigits, MaxDigits> > { typedef int_parser_impl<T, Radix, MinDigits, MaxDigits> self_t; template <typename ScannerT> struct result { typedef typename match_result<ScannerT, T>::type type; }; template <typename ScannerT> typename parser_result<self_t, ScannerT>::type parse(ScannerT const& scan) const { typedef extract_int<Radix, MinDigits, MaxDigits, negative_accumulate<T, Radix> > extract_int_neg_t; typedef extract_int<Radix, MinDigits, MaxDigits, positive_accumulate<T, Radix> > extract_int_pos_t; if (!scan.at_end()) { T n = 0; std::size_t count = 0; typename ScannerT::iterator_t save = scan.first; bool hit = impl::extract_sign(scan, count); if (hit) hit = extract_int_neg_t::f(scan, n, count); else hit = extract_int_pos_t::f(scan, n, count); if (hit) return scan.create_match(count, n, save, scan.first); else scan.first = save; // return no-match if number overflows or underflows } return scan.no_match(); } }; /////////////////////////////////////////////////////////////////////// // // real_parser_impl class // /////////////////////////////////////////////////////////////////////// template <typename RT, typename T, typename RealPoliciesT> struct real_parser_impl { typedef real_parser_impl<RT, T, RealPoliciesT> self_t; template <typename ScannerT> RT parse_main(ScannerT const& scan) const { if (scan.at_end()) return scan.no_match(); typename ScannerT::iterator_t save = scan.first; typedef typename parser_result<sign_parser, ScannerT>::type sign_match_t; typedef typename parser_result<chlit<>, ScannerT>::type exp_match_t; sign_match_t sign_match = RealPoliciesT::parse_sign(scan); std::size_t count = sign_match ? sign_match.length() : 0; bool neg = sign_match.has_valid_attribute() ? sign_match.value() : false; RT n_match = RealPoliciesT::parse_n(scan); T n = n_match.has_valid_attribute() ? n_match.value() : T(0); bool got_a_number = n_match; exp_match_t e_hit; if (!got_a_number && !RealPoliciesT::allow_leading_dot) return scan.no_match(); else count += n_match.length(); if (neg) n = -n; if (RealPoliciesT::parse_dot(scan)) { // 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. if (RT hit = RealPoliciesT::parse_frac_n(scan)) { #if !defined(BOOST_NO_STDC_NAMESPACE) using namespace std; // allow for ADL to find pow() #endif hit.value(hit.value() * pow(T(10), T(-hit.length()))); if (neg) n -= hit.value(); else n += hit.value(); count += hit.length() + 1; } else if (!got_a_number || !RealPoliciesT::allow_trailing_dot) return scan.no_match(); e_hit = RealPoliciesT::parse_exp(scan); } else { // We have reached a point where we // still haven't seen a number at all. // We return early with a no-match. if (!got_a_number) return scan.no_match(); // If we must expect a dot and we didn't see // an exponent, return early with a no-match. e_hit = RealPoliciesT::parse_exp(scan); if (RealPoliciesT::expect_dot && !e_hit) return scan.no_match(); } 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. if (RT e_n_hit = RealPoliciesT::parse_exp_n(scan)) { #if !defined(BOOST_NO_STDC_NAMESPACE) using namespace std; // allow for ADL to find pow() #endif n *= pow(T(10), T(e_n_hit.value())); count += e_n_hit.length() + e_hit.length(); } else { // Oops, no exponent, return a no-match return scan.no_match(); } } return scan.create_match(count, n, save, scan.first); } template <typename ScannerT> static RT parse(ScannerT const& scan) { static self_t this_; return impl::implicit_lexeme_parse<RT>(this_, scan, scan); } }; #if defined(BOOST_MSVC) #pragma warning(pop) #endif } // namespace impl /////////////////////////////////////////////////////////////////////////////// BOOST_SPIRIT_CLASSIC_NAMESPACE_END }} // namespace boost::spirit #endif