/*============================================================================= Copyright (c) 2001-2011 Joel de Guzman Copyright (c) 2001-2011 Hartmut Kaiser Copyright (c) 2011 Jan Frederick Eick Copyright (c) 2011 Christopher Jefferson Copyright (c) 2006 Stephen Nutt Distributed under 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) =============================================================================*/ #if !defined(SPIRIT_NUMERIC_UTILS_APRIL_17_2006_0816AM) #define SPIRIT_NUMERIC_UTILS_APRIL_17_2006_0816AM #if defined(_MSC_VER) #pragma once #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(SPIRIT_NUMERICS_LOOP_UNROLL) # define SPIRIT_NUMERICS_LOOP_UNROLL 3 #endif namespace boost { namespace spirit { namespace qi { namespace detail { /////////////////////////////////////////////////////////////////////////// // // The maximum radix digits that can be represented without // overflow: // // template // struct digits_traits::value; // /////////////////////////////////////////////////////////////////////////// template struct digits_traits; // lookup table for log2(x) : 2 <= x <= 36 #define BOOST_SPIRIT_LOG2 (#error)(#error) \ (1000000)(1584960)(2000000)(2321920)(2584960)(2807350) \ (3000000)(3169920)(3321920)(3459430)(3584960)(3700430) \ (3807350)(3906890)(4000000)(4087460)(4169920)(4247920) \ (4321920)(4392310)(4459430)(4523560)(4584960)(4643850) \ (4700430)(4754880)(4807350)(4857980)(4906890)(4954190) \ (5000000)(5044390)(5087460)(5129280)(5169925) \ /***/ #define BOOST_PP_LOCAL_MACRO(Radix) \ template struct digits_traits \ { \ typedef std::numeric_limits numeric_limits_type; \ BOOST_STATIC_CONSTANT(int, value = static_cast( \ (numeric_limits_type::digits * 1000000) / \ BOOST_PP_SEQ_ELEM(Radix, BOOST_SPIRIT_LOG2))); \ }; \ /***/ #define BOOST_PP_LOCAL_LIMITS (2, 36) #include BOOST_PP_LOCAL_ITERATE() #undef BOOST_SPIRIT_LOG2 /////////////////////////////////////////////////////////////////////////// // // Traits class for radix specific number conversion // // Test the validity of a single character: // // template static bool is_valid(Char ch); // // Convert a digit from character representation to binary // representation: // // template static int digit(Char ch); // /////////////////////////////////////////////////////////////////////////// template struct radix_traits { template inline static bool is_valid(Char ch) { if (Radix <= 10) return (ch >= '0' && ch <= static_cast('0' + Radix -1)); return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= static_cast('a' + Radix -10 -1)) || (ch >= 'A' && ch <= static_cast('A' + Radix -10 -1)); } template inline static unsigned digit(Char ch) { if (Radix <= 10 || (ch >= '0' && ch <= '9')) return ch - '0'; return spirit::char_encoding::ascii::tolower(ch) - 'a' + 10; } }; /////////////////////////////////////////////////////////////////////////// // positive_accumulator/negative_accumulator: Accumulator policies for // extracting integers. Use positive_accumulator if number is positive. // Use negative_accumulator if number is negative. /////////////////////////////////////////////////////////////////////////// template struct positive_accumulator { template inline static void add(T& n, Char ch, mpl::false_) // unchecked add { const int digit = radix_traits::digit(ch); n = n * T(Radix) + T(digit); } template inline static bool add(T& n, Char ch, mpl::true_) // checked add { // Ensure n *= Radix will not overflow static T const max = (std::numeric_limits::max)(); static T const val = max / Radix; if (n > val) return false; n *= Radix; // Ensure n += digit will not overflow const int digit = radix_traits::digit(ch); if (n > max - digit) return false; n += static_cast(digit); return true; } }; template struct negative_accumulator { template inline static void add(T& n, Char ch, mpl::false_) // unchecked subtract { const int digit = radix_traits::digit(ch); n = n * T(Radix) - T(digit); } template inline static bool add(T& n, Char ch, mpl::true_) // checked subtract { // Ensure n *= Radix will not underflow static T const min = (std::numeric_limits::min)(); static T const val = (min + 1) / T(Radix); if (n < val) return false; n *= Radix; // Ensure n -= digit will not underflow int const digit = radix_traits::digit(ch); if (n < min + digit) return false; n -= static_cast(digit); return true; } }; /////////////////////////////////////////////////////////////////////////// // Common code for extract_int::parse specializations /////////////////////////////////////////////////////////////////////////// template struct int_extractor { template inline static bool call(Char ch, std::size_t count, T& n, mpl::true_) { static std::size_t const overflow_free = digits_traits::value - 1; if (count < overflow_free) { Accumulator::add(n, ch, mpl::false_()); } else { if (!Accumulator::add(n, ch, mpl::true_())) return false; // over/underflow! } return true; } template inline static bool call(Char ch, std::size_t /*count*/, T& n, mpl::false_) { // no need to check for overflow Accumulator::add(n, ch, mpl::false_()); return true; } template inline static bool call(Char /*ch*/, std::size_t /*count*/, unused_type, mpl::false_) { return true; } template inline static bool call(Char ch, std::size_t count, T& n) { return call(ch, count, n , mpl::bool_< ( (MaxDigits < 0) || (MaxDigits > digits_traits::value) ) && traits::check_overflow::value >() ); } }; /////////////////////////////////////////////////////////////////////////// // End of loop checking: check if the number of digits // being parsed exceeds MaxDigits. Note: if MaxDigits == -1 // we don't do any checking. /////////////////////////////////////////////////////////////////////////// template struct check_max_digits { inline static bool call(std::size_t count) { return count < MaxDigits; // bounded } }; template <> struct check_max_digits<-1> { inline static bool call(std::size_t /*count*/) { return true; // unbounded } }; /////////////////////////////////////////////////////////////////////////// // extract_int: main code for extracting integers /////////////////////////////////////////////////////////////////////////// #define SPIRIT_NUMERIC_INNER_LOOP(z, x, data) \ if (!check_max_digits::call(count + leading_zeros) \ || it == last) \ break; \ ch = *it; \ if (!radix_check::is_valid(ch) || !extractor::call(ch, count, val)) \ break; \ ++it; \ ++count; \ /**/ template < typename T, unsigned Radix, unsigned MinDigits, int MaxDigits , typename Accumulator = positive_accumulator , bool Accumulate = false > struct extract_int { #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant #endif template inline static bool parse_main( Iterator& first , Iterator const& last , Attribute& attr) { typedef radix_traits radix_check; typedef int_extractor extractor; typedef typename boost::detail::iterator_traits::value_type char_type; Iterator it = first; std::size_t leading_zeros = 0; if (!Accumulate) { // skip leading zeros while (it != last && *it == '0' && leading_zeros < MaxDigits) { ++it; ++leading_zeros; } } typedef typename traits::attribute_type::type attribute_type; attribute_type val = Accumulate ? attr : attribute_type(0); std::size_t count = 0; char_type ch; while (true) { BOOST_PP_REPEAT( SPIRIT_NUMERICS_LOOP_UNROLL , SPIRIT_NUMERIC_INNER_LOOP, _) } if (count + leading_zeros >= MinDigits) { traits::assign_to(val, attr); first = it; return true; } return false; } #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) # pragma warning(pop) #endif template inline static bool parse( Iterator& first , Iterator const& last , unused_type) { T n = 0; // must calculate value to detect over/underflow return parse_main(first, last, n); } template inline static bool parse( Iterator& first , Iterator const& last , Attribute& attr) { return parse_main(first, last, attr); } }; #undef SPIRIT_NUMERIC_INNER_LOOP /////////////////////////////////////////////////////////////////////////// // extract_int: main code for extracting integers // common case where MinDigits == 1 and MaxDigits = -1 /////////////////////////////////////////////////////////////////////////// #define SPIRIT_NUMERIC_INNER_LOOP(z, x, data) \ if (it == last) \ break; \ ch = *it; \ if (!radix_check::is_valid(ch)) \ break; \ if (!extractor::call(ch, count, val)) \ return false; \ ++it; \ ++count; \ /**/ template struct extract_int { #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant #endif template inline static bool parse_main( Iterator& first , Iterator const& last , Attribute& attr) { typedef radix_traits radix_check; typedef int_extractor extractor; typedef typename boost::detail::iterator_traits::value_type char_type; Iterator it = first; std::size_t count = 0; if (!Accumulate) { // skip leading zeros while (it != last && *it == '0') { ++it; ++count; } if (it == last) { if (count == 0) // must have at least one digit return false; traits::assign_to(0, attr); first = it; return true; } } typedef typename traits::attribute_type::type attribute_type; attribute_type val = Accumulate ? attr : attribute_type(0); char_type ch = *it; if (!radix_check::is_valid(ch) || !extractor::call(ch, 0, val)) { if (count == 0) // must have at least one digit return false; traits::assign_to(val, attr); first = it; return true; } count = 0; ++it; while (true) { BOOST_PP_REPEAT( SPIRIT_NUMERICS_LOOP_UNROLL , SPIRIT_NUMERIC_INNER_LOOP, _) } traits::assign_to(val, attr); first = it; return true; } #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) # pragma warning(pop) #endif template inline static bool parse( Iterator& first , Iterator const& last , unused_type) { T n = 0; // must calculate value to detect over/underflow return parse_main(first, last, n); } template inline static bool parse( Iterator& first , Iterator const& last , Attribute& attr) { return parse_main(first, last, attr); } }; #undef SPIRIT_NUMERIC_INNER_LOOP /////////////////////////////////////////////////////////////////////////// // Cast an signed integer to an unsigned integer /////////////////////////////////////////////////////////////////////////// template , is_signed >::value> struct cast_unsigned; template struct cast_unsigned { typedef typename make_unsigned::type unsigned_type; typedef typename make_unsigned::type& unsigned_type_ref; inline static unsigned_type_ref call(T& n) { return unsigned_type_ref(n); } }; template struct cast_unsigned { inline static T& call(T& n) { return n; } }; }}}} #endif