/Src/Dependencies/Boost/boost/spirit/home/classic/core/primitives/impl/numerics.ipp
http://hadesmem.googlecode.com/ · C++ Header · 478 lines · 323 code · 55 blank · 100 comment · 41 complexity · 6304de337af2e304c58d6562e06aa5c4 MD5 · raw file
- /*=============================================================================
- 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