File indexing completed on 2025-01-31 10:02:37
0001
0002
0003
0004
0005
0006
0007
0008
0009
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
0047
0048
0049
0050
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
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
0098
0099
0100
0101
0102
0103
0104
0105
0106
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
0131
0132
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_)
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_)
0146 {
0147
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
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_)
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_)
0177 {
0178
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
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
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;
0217 }
0218 return true;
0219 }
0220
0221 template <typename Char, typename T>
0222 inline static bool
0223 call(Char ch, std::size_t , T& n, mpl::false_)
0224 {
0225
0226 Accumulator::add(n, ch, mpl::false_());
0227 return true;
0228 }
0229
0230 template <typename Char>
0231 inline static bool
0232 call(Char , std::size_t , 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
0254
0255
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;
0264 }
0265 };
0266
0267 template <>
0268 struct check_max_digits<-1>
0269 {
0270 inline static bool
0271 call(std::size_t )
0272 {
0273 return true;
0274 }
0275 };
0276
0277
0278
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)
0301 # pragma warning(disable: 4459)
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
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;
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
0380
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)
0400 # pragma warning(disable: 4459)
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
0420 while (it != last && *it == '0')
0421 {
0422 ++it;
0423 ++count;
0424 }
0425
0426 if (it == last)
0427 {
0428 if (count == 0)
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)
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;
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