--- numerics.1.12.ipp Wed Jul 04 17:54:15 2007 +++ numerics.ipp Wed Jul 04 13:00:00 2007 @@ -11,6 +11,7 @@ #define BOOST_SPIRIT_NUMERICS_IPP #include +#include #if defined(BOOST_NO_STDC_NAMESPACE) # define BOOST_SPIRIT_IMPL_STD_NS @@ -50,14 +51,11 @@ // // Traits class for radix specific number conversion // - // Test the validity of a single character: + // Convert a digit from character representation, ch, to binary + // representation, returned in val. + // Returns whether the conversion was successful. // - // template static bool is_valid(CharT ch); - // - // Convert a digit from character representation to binary - // representation: - // - // template static int digit(CharT ch); + // template static bool digit(CharT ch, T& val); // /////////////////////////////////////////////////////////////////////// template @@ -67,69 +65,55 @@ template<> struct radix_traits<2> { - template - static bool is_valid(CharT ch) + template + static bool digit(CharT ch, T& val) { + val = ch - '0'; return ('0' == ch || '1' == ch); } - - template - static int digit(CharT ch) - { - return ch - '0'; - } }; ////////////////////////////////// Octal template<> struct radix_traits<8> { - template - static bool is_valid(CharT ch) + template + static bool digit(CharT ch, T& val) { + val = ch - '0'; return ('0' <= ch && ch <= '7'); } - - template - static int digit(CharT ch) - { - return ch - '0'; - } }; ////////////////////////////////// Decimal template<> struct radix_traits<10> { - template - static bool is_valid(CharT ch) + template + static bool digit(CharT ch, T& val) { + val = ch - '0'; return impl::isdigit_(ch); } - - template - static int digit(CharT ch) - { - return ch - '0'; - } }; ////////////////////////////////// Hexadecimal template<> struct radix_traits<16> { - template - static bool is_valid(CharT ch) + template + static bool digit(CharT ch, T& val) { - return impl::isxdigit_(ch); - } + if (radix_traits<10>::digit(ch, val)) + return true; - template - static int digit(CharT ch) - { - if (impl::isdigit_(ch)) - return ch - '0'; - return impl::tolower_(ch) - 'a' + 10; + CharT lc = impl::tolower_(ch); + if ('a' <= lc && lc <= 'f') + { + val = lc - 'a' + 10; + return true; + } + return false; } }; @@ -161,140 +145,74 @@ // // NOTE: // Returns a non-match, if the number to parse - // overflows (or underflows) the used integral type. - // Overflow (or underflow) is detected when an - // operation wraps a value from its maximum to its - // minimum (or vice-versa). For example, overflow - // occurs when the result of the expression n * x is - // less than n (assuming n is positive and x is - // greater than 1). + // overflows (or underflows) the used type. // // BEWARE: // the parameters 'n' and 'count' should be properly // initialized before calling this function. // /////////////////////////////////////////////////////////////////////// - template + template struct positive_accumulate { // Use this accumulator if number is positive - - template - static bool check(T const& n, T const& prev) + static bool add(T& n, T digit) { - return n < prev; - } - - template - static void add(T& n, CharT ch) - { - n += radix_traits::digit(ch); + static T const max = (std::numeric_limits::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; } }; - - template + + template struct negative_accumulate { // Use this accumulator if number is negative - - template - static bool check(T const& n, T const& prev) - { - return n > prev; - } - - template - static void add(T& n, CharT ch) + static bool add(T& n, T digit) { - n -= radix_traits::digit(ch); - } - }; - - template - struct extract_int_base - { - // Common code for extract_int specializations - template - static bool - f(ScannerT& scan, T& n) - { - T prev = n; + typedef std::numeric_limits 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 (Accumulate::check(n, prev)) - return false; // over/underflow! - prev = n; - Accumulate::add(n, *scan); - if (Accumulate::check(n, prev)) - return false; // over/underflow! + + if (n < min + digit) + return false; + n -= digit; + return true; } }; - template - struct extract_int_ - { - template < - int Radix, - unsigned MinDigits, - int MaxDigits, - typename Accumulate - > - struct apply - { - typedef extract_int_base base; - typedef radix_traits check; - - template - static bool - f(ScannerT& scan, T& n, std::size_t& count) - { - std::size_t i = 0; - for (; (i < MaxDigits) && !scan.at_end() - && check::is_valid(*scan); - ++i, ++scan, ++count) - { - if (!base::f(scan, n)) - return false; // over/underflow! - } - return i >= MinDigits; - } - }; - }; - + template + inline bool allow_more_digits(std::size_t i) + { + return i < MaxDigits; + } + template <> - struct extract_int_ + inline bool allow_more_digits<-1>(std::size_t) { - template < - int Radix, - unsigned MinDigits, - int MaxDigits, - typename Accumulate - > - struct apply - { - typedef extract_int_base base; - typedef radix_traits check; - - template - static bool - f(ScannerT& scan, T& n, std::size_t& count) - { - std::size_t i = 0; - for (; !scan.at_end() && check::is_valid(*scan); - ++i, ++scan, ++count) - { - if (!base::f(scan, n)) - return false; // over/underflow! - } - return i >= MinDigits; - } - }; - }; - + return true; + } + ////////////////////////////////// template < int Radix, unsigned MinDigits, int MaxDigits, - typename Accumulate = positive_accumulate + typename Accumulate > struct extract_int { @@ -302,9 +220,16 @@ static bool f(ScannerT& scan, T& n, std::size_t& count) { - typedef typename extract_int_<(MaxDigits >= 0)>::template - apply extractor; - return extractor::f(scan, n, count); + std::size_t i = 0; + T digit; + while( allow_more_digits(i) && !scan.at_end() && + radix_traits::digit(*scan, digit) ) + { + if (!Accumulate::add(n, digit)) + return false; // Overflow + ++i, ++scan, ++count; + } + return i >= MinDigits; } }; @@ -339,8 +264,8 @@ T n = 0; std::size_t count = 0; typename ScannerT::iterator_t save = scan.first; - if (extract_int:: - f(scan, n, count)) + if (extract_int >::f(scan, n, count)) { return scan.create_match(count, n, save, scan.first); } @@ -377,9 +302,9 @@ parse(ScannerT const& scan) const { typedef extract_int > extract_int_neg_t; - typedef extract_int - extract_int_pos_t; + negative_accumulate > extract_int_neg_t; + typedef extract_int > extract_int_pos_t; if (!scan.at_end()) {