Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-31 10:02:37

0001 /*=============================================================================
0002     Copyright (c) 2001-2014 Joel de Guzman
0003     Copyright (c) 2001-2011 Hartmut Kaiser
0004     Copyright (c) 2011 Jan Frederick Eick
0005     Copyright (c) 2011 Christopher Jefferson
0006     Copyright (c) 2006 Stephen Nutt
0007 
0008     Distributed under the Boost Software License, Version 1.0. (See accompanying
0009     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0010 =============================================================================*/
0011 #if !defined(BOOST_SPIRIT_X3_DETAIL_EXTRACT_INT_APRIL_17_2006_0816AM)
0012 #define BOOST_SPIRIT_X3_DETAIL_EXTRACT_INT_APRIL_17_2006_0816AM
0013 
0014 #include <boost/spirit/home/x3/support/unused.hpp>
0015 #include <boost/spirit/home/x3/support/traits/attribute_type.hpp>
0016 #include <boost/spirit/home/x3/support/traits/move_to.hpp>
0017 #include <boost/spirit/home/x3/support/traits/numeric_traits.hpp>
0018 #include <boost/spirit/home/support/char_encoding/ascii.hpp>
0019 
0020 #include <boost/preprocessor/repetition/repeat.hpp>
0021 #include <boost/preprocessor/iteration/local.hpp>
0022 #include <boost/preprocessor/comparison/less.hpp>
0023 #include <boost/preprocessor/control/if.hpp>
0024 #include <boost/preprocessor/seq/elem.hpp>
0025 
0026 #include <boost/utility/enable_if.hpp>
0027 
0028 #include <boost/type_traits/is_integral.hpp>
0029 #include <boost/type_traits/is_signed.hpp>
0030 #include <boost/type_traits/make_unsigned.hpp>
0031 
0032 #include <boost/mpl/bool.hpp>
0033 #include <boost/mpl/and.hpp>
0034 #include <boost/limits.hpp>
0035 
0036 #include <iterator> // for std::iterator_traits
0037 
0038 #if !defined(SPIRIT_NUMERICS_LOOP_UNROLL)
0039 # define SPIRIT_NUMERICS_LOOP_UNROLL 3
0040 #endif
0041 
0042 namespace boost { namespace spirit { namespace x3 { namespace detail
0043 {
0044     ///////////////////////////////////////////////////////////////////////////
0045     //
0046     //  The maximum radix digits that can be represented without
0047     //  overflow:
0048     //
0049     //          template<typename T, unsigned Radix>
0050     //          struct digits_traits::value;
0051     //
0052     ///////////////////////////////////////////////////////////////////////////
0053     template <typename T, unsigned Radix>
0054     struct digits_traits;
0055 
0056     template <int Digits, unsigned Radix>
0057     struct digits2_to_n;
0058 
0059 // lookup table for log2(x) : 2 <= x <= 36
0060 #define BOOST_SPIRIT_X3_LOG2 (#error)(#error)                                   \
0061         (1000000)(1584960)(2000000)(2321920)(2584960)(2807350)                  \
0062         (3000000)(3169920)(3321920)(3459430)(3584960)(3700430)                  \
0063         (3807350)(3906890)(4000000)(4087460)(4169920)(4247920)                  \
0064         (4321920)(4392310)(4459430)(4523560)(4584960)(4643850)                  \
0065         (4700430)(4754880)(4807350)(4857980)(4906890)(4954190)                  \
0066         (5000000)(5044390)(5087460)(5129280)(5169925)                           \
0067     /***/
0068 
0069 #define BOOST_PP_LOCAL_MACRO(Radix)                                             \
0070     template <int Digits> struct digits2_to_n<Digits, Radix>                    \
0071     {                                                                           \
0072         BOOST_STATIC_CONSTANT(int, value = static_cast<int>(                    \
0073             (Digits * 1000000) /                                                \
0074                 BOOST_PP_SEQ_ELEM(Radix, BOOST_SPIRIT_X3_LOG2)));               \
0075     };                                                                          \
0076     /***/
0077 
0078 #define BOOST_PP_LOCAL_LIMITS (2, 36)
0079 #include BOOST_PP_LOCAL_ITERATE()
0080 
0081 #undef BOOST_SPIRIT_X3_LOG2
0082 
0083     template <typename T, unsigned Radix>
0084     struct digits_traits : digits2_to_n<std::numeric_limits<T>::digits, Radix>
0085     {
0086         static_assert(std::numeric_limits<T>::radix == 2, "");
0087     };
0088 
0089     template <typename T>
0090     struct digits_traits<T, 10>
0091     {
0092         static int constexpr value = std::numeric_limits<T>::digits10;
0093     };
0094 
0095     ///////////////////////////////////////////////////////////////////////////
0096     //
0097     //  Traits class for radix specific number conversion
0098     //
0099     //      Test the validity of a single character:
0100     //
0101     //          template<typename Char> static bool is_valid(Char ch);
0102     //
0103     //      Convert a digit from character representation to binary
0104     //      representation:
0105     //
0106     //          template<typename Char> static int digit(Char ch);
0107     //
0108     ///////////////////////////////////////////////////////////////////////////
0109     template <unsigned Radix>
0110     struct radix_traits
0111     {
0112         template <typename Char>
0113         inline static bool is_valid(Char ch)
0114         {
0115             return (ch >= '0' && ch <= (Radix > 10 ? '9' : static_cast<Char>('0' + Radix -1)))
0116                 || (Radix > 10 && ch >= 'a' && ch <= static_cast<Char>('a' + Radix -10 -1))
0117                 || (Radix > 10 && ch >= 'A' && ch <= static_cast<Char>('A' + Radix -10 -1));
0118         }
0119 
0120         template <typename Char>
0121         inline static unsigned digit(Char ch)
0122         {
0123             return (Radix <= 10 || (ch >= '0' && ch <= '9'))
0124                 ? ch - '0'
0125                 : char_encoding::ascii::tolower(ch) - 'a' + 10;
0126         }
0127     };
0128 
0129     ///////////////////////////////////////////////////////////////////////////
0130     //  positive_accumulator/negative_accumulator: Accumulator policies for
0131     //  extracting integers. Use positive_accumulator if number is positive.
0132     //  Use negative_accumulator if number is negative.
0133     ///////////////////////////////////////////////////////////////////////////
0134     template <unsigned Radix>
0135     struct positive_accumulator
0136     {
0137         template <typename T, typename Char>
0138         inline static void add(T& n, Char ch, mpl::false_) // unchecked add
0139         {
0140             const int digit = radix_traits<Radix>::digit(ch);
0141             n = n * T(Radix) + T(digit);
0142         }
0143 
0144         template <typename T, typename Char>
0145         inline static bool add(T& n, Char ch, mpl::true_) // checked add
0146         {
0147             // Ensure n *= Radix will not overflow
0148             T const max = (std::numeric_limits<T>::max)();
0149             T const val = max / Radix;
0150             if (n > val)
0151                 return false;
0152 
0153             T tmp = n * Radix;
0154 
0155             // Ensure n += digit will not overflow
0156             const int digit = radix_traits<Radix>::digit(ch);
0157             if (tmp > max - digit)
0158                 return false;
0159 
0160             n = tmp + static_cast<T>(digit);
0161             return true;
0162         }
0163     };
0164 
0165     template <unsigned Radix>
0166     struct negative_accumulator
0167     {
0168         template <typename T, typename Char>
0169         inline static void add(T& n, Char ch, mpl::false_) // unchecked subtract
0170         {
0171             const int digit = radix_traits<Radix>::digit(ch);
0172             n = n * T(Radix) - T(digit);
0173         }
0174 
0175         template <typename T, typename Char>
0176         inline static bool add(T& n, Char ch, mpl::true_) // checked subtract
0177         {
0178             // Ensure n *= Radix will not underflow
0179             T const min = (std::numeric_limits<T>::min)();
0180             T const val = min / T(Radix);
0181             if (n < val)
0182                 return false;
0183 
0184             T tmp = n * Radix;
0185 
0186             // Ensure n -= digit will not underflow
0187             int const digit = radix_traits<Radix>::digit(ch);
0188             if (tmp < min + digit)
0189                 return false;
0190 
0191             n = tmp - static_cast<T>(digit);
0192             return true;
0193         }
0194     };
0195 
0196     ///////////////////////////////////////////////////////////////////////////
0197     //  Common code for extract_int::parse specializations
0198     ///////////////////////////////////////////////////////////////////////////
0199     template <unsigned Radix, typename Accumulator, int MaxDigits>
0200     struct int_extractor
0201     {
0202         template <typename Char, typename T>
0203         inline static bool
0204         call(Char ch, std::size_t count, T& n, mpl::true_)
0205         {
0206             std::size_t constexpr
0207                 overflow_free = digits_traits<T, Radix>::value - 1;
0208 
0209             if (count < overflow_free)
0210             {
0211                 Accumulator::add(n, ch, mpl::false_());
0212             }
0213             else
0214             {
0215                 if (!Accumulator::add(n, ch, mpl::true_()))
0216                     return false; //  over/underflow!
0217             }
0218             return true;
0219         }
0220 
0221         template <typename Char, typename T>
0222         inline static bool
0223         call(Char ch, std::size_t /*count*/, T& n, mpl::false_)
0224         {
0225             // no need to check for overflow
0226             Accumulator::add(n, ch, mpl::false_());
0227             return true;
0228         }
0229 
0230         template <typename Char>
0231         inline static bool
0232         call(Char /*ch*/, std::size_t /*count*/, unused_type, mpl::false_)
0233         {
0234             return true;
0235         }
0236 
0237         template <typename Char, typename T>
0238         inline static bool
0239         call(Char ch, std::size_t count, T& n)
0240         {
0241             return call(ch, count, n
0242               , mpl::bool_<
0243                     (   (MaxDigits < 0)
0244                     ||  (MaxDigits > digits_traits<T, Radix>::value)
0245                     )
0246                   && traits::check_overflow<T>::value
0247                 >()
0248             );
0249         }
0250     };
0251 
0252     ///////////////////////////////////////////////////////////////////////////
0253     //  End of loop checking: check if the number of digits
0254     //  being parsed exceeds MaxDigits. Note: if MaxDigits == -1
0255     //  we don't do any checking.
0256     ///////////////////////////////////////////////////////////////////////////
0257     template <int MaxDigits>
0258     struct check_max_digits
0259     {
0260         inline static bool
0261         call(std::size_t count)
0262         {
0263             return count < MaxDigits; // bounded
0264         }
0265     };
0266 
0267     template <>
0268     struct check_max_digits<-1>
0269     {
0270         inline static bool
0271         call(std::size_t /*count*/)
0272         {
0273             return true; // unbounded
0274         }
0275     };
0276 
0277     ///////////////////////////////////////////////////////////////////////////
0278     //  extract_int: main code for extracting integers
0279     ///////////////////////////////////////////////////////////////////////////
0280 #define SPIRIT_NUMERIC_INNER_LOOP(z, x, data)                                   \
0281         if (!check_max_digits<MaxDigits>::call(count + leading_zeros)           \
0282             || it == last)                                                      \
0283             break;                                                              \
0284         ch = *it;                                                               \
0285         if (!radix_check::is_valid(ch) || !extractor::call(ch, count, val))     \
0286             break;                                                              \
0287         ++it;                                                                   \
0288         ++count;                                                                \
0289     /**/
0290 
0291     template <
0292         typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
0293       , typename Accumulator = positive_accumulator<Radix>
0294       , bool Accumulate = false
0295     >
0296     struct extract_int
0297     {
0298 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0299 # pragma warning(push)
0300 # pragma warning(disable: 4127)   // conditional expression is constant
0301 # pragma warning(disable: 4459)   // declaration hides global declaration
0302 #endif
0303         template <typename Iterator, typename Attribute>
0304         inline static bool
0305         parse_main(
0306             Iterator& first
0307           , Iterator const& last
0308           , Attribute& attr)
0309         {
0310             typedef radix_traits<Radix> radix_check;
0311             typedef int_extractor<Radix, Accumulator, MaxDigits> extractor;
0312             typedef typename
0313                 std::iterator_traits<Iterator>::value_type
0314             char_type;
0315 
0316             Iterator it = first;
0317             std::size_t leading_zeros = 0;
0318             if (!Accumulate)
0319             {
0320                 // skip leading zeros
0321                 while (it != last && *it == '0' && leading_zeros < MaxDigits)
0322                 {
0323                     ++it;
0324                     ++leading_zeros;
0325                 }
0326             }
0327 
0328             typedef typename
0329                 traits::attribute_type<Attribute>::type
0330             attribute_type;
0331 
0332             attribute_type val = Accumulate ? attr : attribute_type(0);
0333             std::size_t count = 0;
0334             char_type ch;
0335 
0336             while (true)
0337             {
0338                 BOOST_PP_REPEAT(
0339                     SPIRIT_NUMERICS_LOOP_UNROLL
0340                   , SPIRIT_NUMERIC_INNER_LOOP, _)
0341             }
0342 
0343             if (count + leading_zeros >= MinDigits)
0344             {
0345                 traits::move_to(val, attr);
0346                 first = it;
0347                 return true;
0348             }
0349             return false;
0350         }
0351 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0352 # pragma warning(pop)
0353 #endif
0354 
0355         template <typename Iterator>
0356         inline static bool
0357         parse(
0358             Iterator& first
0359           , Iterator const& last
0360           , unused_type)
0361         {
0362             T n = 0; // must calculate value to detect over/underflow
0363             return parse_main(first, last, n);
0364         }
0365 
0366         template <typename Iterator, typename Attribute>
0367         inline static bool
0368         parse(
0369             Iterator& first
0370           , Iterator const& last
0371           , Attribute& attr)
0372         {
0373             return parse_main(first, last, attr);
0374         }
0375     };
0376 #undef SPIRIT_NUMERIC_INNER_LOOP
0377 
0378     ///////////////////////////////////////////////////////////////////////////
0379     //  extract_int: main code for extracting integers
0380     //  common case where MinDigits == 1 and MaxDigits = -1
0381     ///////////////////////////////////////////////////////////////////////////
0382 #define SPIRIT_NUMERIC_INNER_LOOP(z, x, data)                                   \
0383         if (it == last)                                                         \
0384             break;                                                              \
0385         ch = *it;                                                               \
0386         if (!radix_check::is_valid(ch))                                         \
0387             break;                                                              \
0388         if (!extractor::call(ch, count, val))                                   \
0389             return false;                                                       \
0390         ++it;                                                                   \
0391         ++count;                                                                \
0392     /**/
0393 
0394     template <typename T, unsigned Radix, typename Accumulator, bool Accumulate>
0395     struct extract_int<T, Radix, 1, -1, Accumulator, Accumulate>
0396     {
0397 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0398 # pragma warning(push)
0399 # pragma warning(disable: 4127)   // conditional expression is constant
0400 # pragma warning(disable: 4459)   // declaration hides global declaration
0401 #endif
0402         template <typename Iterator, typename Attribute>
0403         inline static bool
0404         parse_main(
0405             Iterator& first
0406           , Iterator const& last
0407           , Attribute& attr)
0408         {
0409             typedef radix_traits<Radix> radix_check;
0410             typedef int_extractor<Radix, Accumulator, -1> extractor;
0411             typedef typename
0412                 std::iterator_traits<Iterator>::value_type
0413             char_type;
0414 
0415             Iterator it = first;
0416             std::size_t count = 0;
0417             if (!Accumulate)
0418             {
0419                 // skip leading zeros
0420                 while (it != last && *it == '0')
0421                 {
0422                     ++it;
0423                     ++count;
0424                 }
0425 
0426                 if (it == last)
0427                 {
0428                     if (count == 0) // must have at least one digit
0429                         return false;
0430                     attr = 0;
0431                     first = it;
0432                     return true;
0433                 }
0434             }
0435 
0436             typedef typename
0437                 traits::attribute_type<Attribute>::type
0438             attribute_type;
0439 
0440             attribute_type val = Accumulate ? attr : attribute_type(0);
0441             char_type ch = *it;
0442 
0443             if (!radix_check::is_valid(ch) || !extractor::call(ch, 0, val))
0444             {
0445                 if (count == 0) // must have at least one digit
0446                     return false;
0447                 traits::move_to(val, attr);
0448                 first = it;
0449                 return true;
0450             }
0451 
0452             count = 0;
0453             ++it;
0454             while (true)
0455             {
0456                 BOOST_PP_REPEAT(
0457                     SPIRIT_NUMERICS_LOOP_UNROLL
0458                   , SPIRIT_NUMERIC_INNER_LOOP, _)
0459             }
0460 
0461             traits::move_to(val, attr);
0462             first = it;
0463             return true;
0464         }
0465 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0466 # pragma warning(pop)
0467 #endif
0468 
0469         template <typename Iterator>
0470         inline static bool
0471         parse(
0472             Iterator& first
0473           , Iterator const& last
0474           , unused_type)
0475         {
0476             T n = 0; // must calculate value to detect over/underflow
0477             return parse_main(first, last, n);
0478         }
0479 
0480         template <typename Iterator, typename Attribute>
0481         inline static bool
0482         parse(
0483             Iterator& first
0484           , Iterator const& last
0485           , Attribute& attr)
0486         {
0487             return parse_main(first, last, attr);
0488         }
0489     };
0490 
0491 #undef SPIRIT_NUMERIC_INNER_LOOP
0492 }}}}
0493 
0494 #endif