File indexing completed on 2025-09-17 08:40:27
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_PARSER_DETAIL_NUMERIC_HPP
0013 #define BOOST_PARSER_DETAIL_NUMERIC_HPP
0014
0015 #include <boost/parser/detail/text/unpack.hpp>
0016
0017 #if __has_include(<charconv>)
0018 #include <charconv>
0019 #endif
0020
0021 #if defined(__cpp_lib_to_chars)
0022 #define BOOST_PARSER_HAVE_STD_CHARCONV
0023 #define BOOST_PARSER_NUMERIC_NS std_charconv
0024 #elif __has_include(<boost/charconv.hpp>)
0025 #include <boost/charconv.hpp>
0026 #define BOOST_PARSER_HAVE_BOOST_CHARCONV
0027 #define BOOST_PARSER_NUMERIC_NS boost_charconv
0028 #else
0029 #define BOOST_PARSER_NUMERIC_NS spirit_parsers
0030 #endif
0031
0032 #include <type_traits>
0033 #include <cmath>
0034
0035 #if defined(BOOST_PARSER_HAVE_STD_CHARCONV) || \
0036 defined(BOOST_PARSER_HAVE_BOOST_CHARCONV)
0037 #define BOOST_PARSER_HAVE_CHARCONV
0038 #endif
0039
0040
0041 namespace boost::parser::detail_spirit_x3 {
0042
0043 struct unused_type
0044 {};
0045
0046
0047
0048
0049 template <typename TargetChar, typename SourceChar>
0050 TargetChar cast_char(SourceChar ch)
0051 {
0052 if (std::is_signed_v<TargetChar> != std::is_signed_v<SourceChar>)
0053 {
0054 if (std::is_signed<SourceChar>::value)
0055 {
0056
0057 typedef std::make_unsigned_t<SourceChar> USourceChar;
0058 return TargetChar(USourceChar(ch));
0059 }
0060 else
0061 {
0062
0063 typedef std::make_signed_t<SourceChar> SSourceChar;
0064 return TargetChar(SSourceChar(ch));
0065 }
0066 }
0067 else
0068 {
0069
0070 return TargetChar(ch);
0071 }
0072 }
0073
0074
0075
0076
0077
0078 inline constexpr int log2_table[] = {
0079 0, 0, 1000000, 1584960, 2000000, 2321920, 2584960, 2807350,
0080 3000000, 3169920, 3321920, 3459430, 3584960, 3700430, 3807350, 3906890,
0081 4000000, 4087460, 4169920, 4247920, 4321920, 4392310, 4459430, 4523560,
0082 4584960, 4643850, 4700430, 4754880, 4807350, 4857980, 4906890, 4954190,
0083 5000000, 5044390, 5087460, 5129280, 5169925};
0084
0085 template<typename T, unsigned Radix>
0086 struct digits_traits
0087 {
0088 static_assert(std::numeric_limits<T>::radix == 2, "");
0089 constexpr static int value =
0090 int((std::numeric_limits<T>::digits * 1000000) / log2_table[Radix]);
0091 };
0092
0093 template <typename T>
0094 struct digits_traits<T, 10>
0095 {
0096 static int constexpr value = std::numeric_limits<T>::digits10;
0097 };
0098
0099 template<unsigned Radix>
0100 struct radix_traits
0101 {
0102 template <typename Char>
0103 inline static bool is_valid(Char ch)
0104 {
0105 if (Radix <= 10)
0106 return (ch >= '0' && ch <= static_cast<Char>('0' + Radix -1));
0107 return (ch >= '0' && ch <= '9')
0108 || (ch >= 'a' && ch <= static_cast<Char>('a' + Radix -10 -1))
0109 || (ch >= 'A' && ch <= static_cast<Char>('A' + Radix -10 -1));
0110 }
0111
0112 template <typename Char>
0113 inline static unsigned digit(Char ch)
0114 {
0115 if (Radix <= 10 || (ch >= '0' && ch <= '9'))
0116 return ch - '0';
0117 return std::tolower(detail_spirit_x3::cast_char<char>(ch)) - 'a' + 10;
0118 }
0119 };
0120
0121
0122 template <unsigned Radix>
0123 struct positive_accumulator
0124 {
0125 template <typename T, typename Char>
0126 inline static void add(T& n, Char ch, std::false_type)
0127 {
0128 const int digit = radix_traits<Radix>::digit(ch);
0129 n = n * T(Radix) + T(digit);
0130 }
0131
0132 template <typename T, typename Char>
0133 inline static bool add(T& n, Char ch, std::true_type)
0134 {
0135
0136 T const max = (std::numeric_limits<T>::max)();
0137 T const val = max / Radix;
0138 if (n > val)
0139 return false;
0140
0141 T tmp = n * Radix;
0142
0143
0144 const int digit = radix_traits<Radix>::digit(ch);
0145 if (tmp > max - digit)
0146 return false;
0147
0148 n = tmp + static_cast<T>(digit);
0149 return true;
0150 }
0151 };
0152
0153 template <unsigned Radix>
0154 struct negative_accumulator
0155 {
0156 template <typename T, typename Char>
0157 inline static void add(T& n, Char ch, std::false_type)
0158 {
0159 const int digit = radix_traits<Radix>::digit(ch);
0160 n = n * T(Radix) - T(digit);
0161 }
0162
0163 template <typename T, typename Char>
0164 inline static bool add(T& n, Char ch, std::true_type)
0165 {
0166
0167 T const min = (std::numeric_limits<T>::min)();
0168 T const val = min / T(Radix);
0169 if (n < val)
0170 return false;
0171
0172 T tmp = n * Radix;
0173
0174
0175 int const digit = radix_traits<Radix>::digit(ch);
0176 if (tmp < min + digit)
0177 return false;
0178
0179 n = tmp - static_cast<T>(digit);
0180 return true;
0181 }
0182 };
0183
0184 template <unsigned Radix, typename Accumulator, int MaxDigits>
0185 struct int_extractor
0186 {
0187 template <typename Char, typename T>
0188 inline static bool
0189 call(Char ch, std::size_t count, T& n, std::true_type)
0190 {
0191 std::size_t constexpr
0192 overflow_free = digits_traits<T, Radix>::value - 1;
0193
0194 if (count < overflow_free)
0195 {
0196 Accumulator::add(n, ch, std::false_type{});
0197 }
0198 else
0199 {
0200 if (!Accumulator::add(n, ch, std::true_type{}))
0201 return false;
0202 }
0203 return true;
0204 }
0205
0206 template <typename Char, typename T>
0207 inline static bool
0208 call(Char ch, std::size_t , T& n, std::false_type)
0209 {
0210
0211 Accumulator::add(n, ch, std::false_type{});
0212 return true;
0213 }
0214
0215 template <typename Char>
0216 inline static bool
0217 call(Char , std::size_t , unused_type, std::false_type)
0218 {
0219 return true;
0220 }
0221
0222 template <typename Char, typename T>
0223 inline static bool
0224 call(Char ch, std::size_t count, T& n)
0225 {
0226 return call(ch, count, n
0227 , std::integral_constant<bool,
0228 ( (MaxDigits < 0)
0229 || (MaxDigits > digits_traits<T, Radix>::value)
0230 )
0231 && std::numeric_limits<T>::is_bounded
0232 >()
0233 );
0234 }
0235 };
0236
0237 template <int MaxDigits>
0238 struct check_max_digits
0239 {
0240 inline static bool
0241 call(std::size_t count)
0242 {
0243 return count < MaxDigits;
0244 }
0245 };
0246
0247 template <>
0248 struct check_max_digits<-1>
0249 {
0250 inline static bool
0251 call(std::size_t )
0252 {
0253 return true;
0254 }
0255 };
0256
0257 template <
0258 typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
0259 , typename Accumulator = positive_accumulator<Radix>
0260 , bool Accumulate = false
0261 >
0262 struct extract_int_impl
0263 {
0264 template <typename Iterator, typename Sentinel, typename Attribute>
0265 inline static bool
0266 parse_main(
0267 Iterator& first
0268 , Sentinel last
0269 , Attribute& attr)
0270 {
0271 typedef radix_traits<Radix> radix_check;
0272 typedef int_extractor<Radix, Accumulator, MaxDigits> extractor;
0273 typedef
0274 typename std::iterator_traits<Iterator>::value_type char_type;
0275
0276 Iterator it = first;
0277 std::size_t leading_zeros = 0;
0278 if (!Accumulate)
0279 {
0280
0281 while (it != last && *it == '0' && leading_zeros < MaxDigits)
0282 {
0283 ++it;
0284 ++leading_zeros;
0285 }
0286 }
0287
0288 typedef Attribute attribute_type;
0289
0290 attribute_type val = Accumulate ? attr : attribute_type(0);
0291 std::size_t count = 0;
0292 char_type ch;
0293
0294 while (true)
0295 {
0296 if (!check_max_digits<MaxDigits>::call(count + leading_zeros) ||
0297 it == last)
0298 break;
0299 ch = *it;
0300 if (!radix_check::is_valid(ch) ||
0301 !extractor::call(ch, count, val))
0302 break;
0303 ++it;
0304 ++count;
0305 if (!check_max_digits<MaxDigits>::call(count + leading_zeros) ||
0306 it == last)
0307 break;
0308 ch = *it;
0309 if (!radix_check::is_valid(ch) ||
0310 !extractor::call(ch, count, val))
0311 break;
0312 ++it;
0313 ++count;
0314 if (!check_max_digits<MaxDigits>::call(count + leading_zeros) ||
0315 it == last)
0316 break;
0317 ch = *it;
0318 if (!radix_check::is_valid(ch) ||
0319 !extractor::call(ch, count, val))
0320 break;
0321 ++it;
0322 ++count;
0323 }
0324
0325 if (count + leading_zeros >= MinDigits)
0326 {
0327 attr = val;
0328 first = it;
0329 return true;
0330 }
0331 return false;
0332 }
0333
0334 template <typename Iterator, typename Sentinel>
0335 inline static bool
0336 parse(
0337 Iterator& first
0338 , Sentinel last
0339 , unused_type)
0340 {
0341 T n = 0;
0342 return parse_main(first, last, n);
0343 }
0344
0345 template <typename Iterator, typename Sentinel, typename Attribute>
0346 inline static bool
0347 parse(
0348 Iterator& first
0349 , Sentinel last
0350 , Attribute& attr)
0351 {
0352 return parse_main(first, last, attr);
0353 }
0354 };
0355
0356 template <typename T, unsigned Radix, typename Accumulator, bool Accumulate>
0357 struct extract_int_impl<T, Radix, 1, -1, Accumulator, Accumulate>
0358 {
0359 template <typename Iterator, typename Sentinel, typename Attribute>
0360 inline static bool
0361 parse_main(
0362 Iterator& first
0363 , Sentinel last
0364 , Attribute& attr)
0365 {
0366 typedef radix_traits<Radix> radix_check;
0367 typedef int_extractor<Radix, Accumulator, -1> extractor;
0368 typedef
0369 typename std::iterator_traits<Iterator>::value_type char_type;
0370
0371 Iterator it = first;
0372 std::size_t count = 0;
0373 if (!Accumulate)
0374 {
0375
0376 while (it != last && *it == '0')
0377 {
0378 ++it;
0379 ++count;
0380 }
0381
0382 if (it == last)
0383 {
0384 if (count == 0)
0385 return false;
0386 attr = 0;
0387 first = it;
0388 return true;
0389 }
0390 }
0391
0392 typedef Attribute attribute_type;
0393
0394 attribute_type val = Accumulate ? attr : attribute_type(0);
0395 char_type ch = *it;
0396
0397 if (!radix_check::is_valid(ch) || !extractor::call(ch, 0, val))
0398 {
0399 if (count == 0)
0400 return false;
0401 attr = val;
0402 first = it;
0403 return true;
0404 }
0405
0406 count = 0;
0407 ++it;
0408 while (true)
0409 {
0410 if (it == last)
0411 break;
0412 ch = *it;
0413 if (!radix_check::is_valid(ch))
0414 break;
0415 if (!extractor::call(ch, count, val))
0416 return false;
0417 ++it;
0418 ++count;
0419 if (it == last)
0420 break;
0421 ch = *it;
0422 if (!radix_check::is_valid(ch))
0423 break;
0424 if (!extractor::call(ch, count, val))
0425 return false;
0426 ++it;
0427 ++count;
0428 if (it == last)
0429 break;
0430 ch = *it;
0431 if (!radix_check::is_valid(ch))
0432 break;
0433 if (!extractor::call(ch, count, val))
0434 return false;
0435 ++it;
0436 ++count;
0437 }
0438
0439 attr = val;
0440 first = it;
0441 return true;
0442 }
0443
0444 template <typename Iterator, typename Sentinel>
0445 inline static bool
0446 parse(
0447 Iterator& first
0448 , Sentinel last
0449 , unused_type)
0450 {
0451 T n = 0;
0452 return parse_main(first, last, n);
0453 }
0454
0455 template <typename Iterator, typename Sentinel, typename Attribute>
0456 inline static bool
0457 parse(
0458 Iterator& first
0459 , Sentinel last
0460 , Attribute& attr)
0461 {
0462 return parse_main(first, last, attr);
0463 }
0464 };
0465
0466
0467
0468
0469
0470
0471
0472
0473 template<typename Iterator, typename Sentinel>
0474 inline bool extract_sign(Iterator & first, Sentinel last)
0475 {
0476 (void)last;
0477 BOOST_PARSER_DEBUG_ASSERT(first != last);
0478
0479
0480 bool neg = *first == '-';
0481 if (neg || (*first == '+'))
0482 {
0483 ++first;
0484 return neg;
0485 }
0486 return false;
0487 }
0488
0489
0490
0491
0492 template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
0493 , bool Accumulate = false>
0494 struct extract_uint
0495 {
0496
0497 static_assert(
0498 (Radix >= 2 && Radix <= 36),
0499 "Error Unsupported Radix");
0500
0501 template <typename Iterator, typename Sentinel>
0502 inline static bool call(Iterator& first, Sentinel last, T& attr)
0503 {
0504 if (first == last)
0505 return false;
0506
0507 typedef extract_int_impl<
0508 T
0509 , Radix
0510 , MinDigits
0511 , MaxDigits
0512 , positive_accumulator<Radix>
0513 , Accumulate>
0514 extract_type;
0515
0516 Iterator save = first;
0517 if (!extract_type::parse(first, last, attr))
0518 {
0519 first = save;
0520 return false;
0521 }
0522 return true;
0523 }
0524 };
0525
0526
0527
0528
0529 template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits>
0530 struct extract_int
0531 {
0532
0533 static_assert(
0534 (Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16),
0535 "Error Unsupported Radix");
0536
0537 template <typename Iterator, typename Sentinel>
0538 inline static bool call(Iterator& first, Sentinel last, T& attr)
0539 {
0540 if (first == last)
0541 return false;
0542
0543 typedef extract_int_impl<
0544 T, Radix, MinDigits, MaxDigits>
0545 extract_pos_type;
0546
0547 typedef extract_int_impl<
0548 T, Radix, MinDigits, MaxDigits, negative_accumulator<Radix> >
0549 extract_neg_type;
0550
0551 Iterator save = first;
0552 bool hit = detail_spirit_x3::extract_sign(first, last);
0553 if (hit)
0554 hit = extract_neg_type::parse(first, last, attr);
0555 else
0556 hit = extract_pos_type::parse(first, last, attr);
0557
0558 if (!hit)
0559 {
0560 first = save;
0561 return false;
0562 }
0563 return true;
0564 }
0565 };
0566
0567
0568
0569
0570 template <typename T, typename Enable = void>
0571 struct pow10_helper
0572 {
0573 static T call(unsigned dim)
0574 {
0575 return std::pow(T(10), T(dim));
0576 }
0577 };
0578
0579 template <typename T>
0580 struct pow10_table
0581 {
0582 constexpr static std::size_t size =
0583 std::numeric_limits<T>::max_exponent10;
0584
0585 constexpr pow10_table()
0586 : exponents()
0587 {
0588 exponents[0] = T(1);
0589 for (auto i = 1; i != size; ++i)
0590 exponents[i] = exponents[i-1] * T(10);
0591 }
0592
0593 T exponents[size];
0594 };
0595
0596 template <typename T>
0597 struct native_pow10_helper
0598 {
0599 constexpr static auto table = pow10_table<T>();
0600 static T call(unsigned dim)
0601 {
0602 return table.exponents[dim];
0603 }
0604 };
0605
0606 template <>
0607 struct pow10_helper<float>
0608 : native_pow10_helper<float> {};
0609
0610 template <>
0611 struct pow10_helper<double>
0612 : native_pow10_helper<double> {};
0613
0614 template <>
0615 struct pow10_helper<long double>
0616 : native_pow10_helper<long double> {};
0617
0618 template <typename T>
0619 inline T pow10(unsigned dim)
0620 {
0621 return detail_spirit_x3::pow10_helper<T>::call(dim);
0622 }
0623
0624 template<typename T>
0625 inline bool scale(int exp, T & n)
0626 {
0627 constexpr auto max_exp = std::numeric_limits<T>::max_exponent10;
0628 constexpr auto min_exp = std::numeric_limits<T>::min_exponent10;
0629
0630 if (exp >= 0)
0631 {
0632
0633
0634 if (std::is_floating_point_v<T> && exp > max_exp)
0635 return false;
0636 n *= detail_spirit_x3::pow10<T>(exp);
0637 }
0638 else
0639 {
0640 if (exp < min_exp)
0641 {
0642 n /= detail_spirit_x3::pow10<T>(-min_exp);
0643
0644
0645
0646 exp += -min_exp;
0647 if (std::is_floating_point_v<T> && exp < min_exp)
0648 return false;
0649
0650 n /= detail_spirit_x3::pow10<T>(-exp);
0651 }
0652 else
0653 {
0654 n /= detail_spirit_x3::pow10<T>(-exp);
0655 }
0656 }
0657 return true;
0658 }
0659
0660 template<typename T>
0661 bool scale(int exp, int frac, T & n)
0662 {
0663 return detail_spirit_x3::scale(exp - frac, n);
0664 }
0665
0666 template<typename T>
0667 T negate(bool neg, T n)
0668 {
0669 return neg ? -n : n;
0670 }
0671
0672 template <typename T, typename RealPolicies>
0673 struct extract_real
0674 {
0675 template <typename Iterator, typename Sentinel, typename Attribute>
0676 static bool
0677 parse(Iterator& first, Sentinel last, Attribute& attr,
0678 RealPolicies const& p)
0679 {
0680 if (first == last)
0681 return false;
0682 Iterator save = first;
0683
0684
0685
0686 bool neg = p.parse_sign(first, last);
0687
0688
0689 T n = 0;
0690 bool got_a_number = p.parse_n(first, last, n);
0691
0692
0693
0694 if (!got_a_number)
0695 {
0696
0697 if (p.parse_nan(first, last, n) ||
0698 p.parse_inf(first, last, n))
0699 {
0700
0701 attr = detail_spirit_x3::negate(neg, n);
0702 return true;
0703 }
0704
0705
0706
0707 if (!p.allow_leading_dot)
0708 {
0709 first = save;
0710 return false;
0711 }
0712 }
0713
0714 bool e_hit = false;
0715 Iterator e_pos;
0716 int frac_digits = 0;
0717
0718
0719 if (p.parse_dot(first, last))
0720 {
0721
0722
0723
0724 Iterator savef = first;
0725 if (p.parse_frac_n(first, last, n))
0726 {
0727
0728
0729 if (!std::is_same_v<T, unused_type>)
0730 frac_digits =
0731 static_cast<int>(std::distance(savef, first));
0732 BOOST_PARSER_DEBUG_ASSERT(frac_digits >= 0);
0733 }
0734 else if (!got_a_number || !p.allow_trailing_dot)
0735 {
0736
0737
0738
0739 first = save;
0740 return false;
0741 }
0742
0743
0744 e_pos = first;
0745 e_hit = p.parse_exp(first, last);
0746 }
0747 else
0748 {
0749
0750 if (!got_a_number)
0751 {
0752 first = save;
0753 return false;
0754 }
0755
0756
0757
0758 e_pos = first;
0759 e_hit = p.parse_exp(first, last);
0760 if (p.expect_dot && !e_hit)
0761 {
0762 first = save;
0763 return false;
0764 }
0765 }
0766
0767 if (e_hit)
0768 {
0769
0770
0771 int exp = 0;
0772 if (p.parse_exp_n(first, last, exp))
0773 {
0774
0775
0776 if (!detail_spirit_x3::scale(exp, frac_digits, n))
0777 return false;
0778 }
0779 else
0780 {
0781
0782
0783 first = e_pos;
0784
0785
0786 if (!detail_spirit_x3::scale(-frac_digits, n))
0787 return false;
0788 }
0789 }
0790 else if (frac_digits)
0791 {
0792
0793 if (!detail_spirit_x3::scale(-frac_digits, n))
0794 return false;
0795 }
0796
0797
0798 attr = detail_spirit_x3::negate(neg, n);
0799
0800
0801 return true;
0802 }
0803 };
0804
0805
0806
0807
0808
0809 struct common_type_equal
0810 {
0811 template<typename T, typename U>
0812 bool operator()(T x, U y)
0813 {
0814 using common_t = std::common_type_t<decltype(x), decltype(y)>;
0815 return (common_t)x == (common_t)y;
0816 }
0817 };
0818
0819 template <typename Char, typename Iterator, typename Sentinel>
0820 inline bool string_parse(
0821 Char const* uc_i, Char const* lc_i
0822 , Iterator& first, Sentinel const& last)
0823 {
0824 Iterator i = first;
0825
0826 common_type_equal eq;
0827
0828 for (; *uc_i && *lc_i; ++uc_i, ++lc_i, ++i)
0829 if (i == last || (!eq(*uc_i, *i) && !eq(*lc_i, *i)))
0830 return false;
0831 first = i;
0832 return true;
0833 }
0834
0835
0836
0837
0838
0839
0840
0841
0842 template <typename T>
0843 struct ureal_policies
0844 {
0845
0846 static bool const allow_leading_dot = true;
0847 static bool const allow_trailing_dot = true;
0848 static bool const expect_dot = false;
0849
0850 template <typename Iterator, typename Sentinel>
0851 static bool
0852 parse_sign(Iterator& , Iterator const& )
0853 {
0854 return false;
0855 }
0856
0857 template <typename Iterator, typename Sentinel, typename Attribute>
0858 static bool
0859 parse_n(Iterator& first, Sentinel const& last, Attribute& attr_)
0860 {
0861 return extract_uint<T, 10, 1, -1>::call(first, last, attr_);
0862 }
0863
0864 template <typename Iterator, typename Sentinel>
0865 static bool
0866 parse_dot(Iterator& first, Sentinel const& last)
0867 {
0868 if (first == last || *first != '.')
0869 return false;
0870 ++first;
0871 return true;
0872 }
0873
0874 template <typename Iterator, typename Sentinel, typename Attribute>
0875 static bool
0876 parse_frac_n(Iterator& first, Sentinel const& last, Attribute& attr_)
0877 {
0878 return extract_uint<T, 10, 1, -1, true>::call(first, last, attr_);
0879 }
0880
0881 template <typename Iterator, typename Sentinel>
0882 static bool
0883 parse_exp(Iterator& first, Sentinel const& last)
0884 {
0885 if (first == last || (*first != 'e' && *first != 'E'))
0886 return false;
0887 ++first;
0888 return true;
0889 }
0890
0891 template <typename Iterator, typename Sentinel>
0892 static bool
0893 parse_exp_n(Iterator& first, Sentinel const& last, int& attr_)
0894 {
0895 return extract_int<int, 10, 1, -1>::call(first, last, attr_);
0896 }
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912 template <typename Iterator, typename Sentinel, typename Attribute>
0913 static bool
0914 parse_nan(Iterator& first, Sentinel const& last, Attribute& attr_)
0915 {
0916 if (first == last)
0917 return false;
0918
0919 if (*first != 'n' && *first != 'N')
0920 return false;
0921
0922
0923 if (detail_spirit_x3::string_parse("nan", "NAN", first, last))
0924 {
0925 if (first != last && *first == '(')
0926 {
0927
0928 Iterator i = first;
0929
0930 while (++i != last && *i != ')')
0931 ;
0932 if (i == last)
0933 return false;
0934
0935 first = ++i;
0936 }
0937 attr_ = std::numeric_limits<T>::quiet_NaN();
0938 return true;
0939 }
0940 return false;
0941 }
0942
0943 template <typename Iterator, typename Sentinel, typename Attribute>
0944 static bool
0945 parse_inf(Iterator& first, Sentinel const& last, Attribute& attr_)
0946 {
0947 if (first == last)
0948 return false;
0949
0950 if (*first != 'i' && *first != 'I')
0951 return false;
0952
0953
0954 if (detail_spirit_x3::string_parse("inf", "INF", first, last))
0955 {
0956
0957 detail_spirit_x3::string_parse("inity", "INITY", first, last);
0958 attr_ = std::numeric_limits<T>::infinity();
0959 return true;
0960 }
0961 return false;
0962 }
0963 };
0964
0965
0966
0967
0968 template <typename T>
0969 struct real_policies : ureal_policies<T>
0970 {
0971 template <typename Iterator, typename Sentinel>
0972 static bool
0973 parse_sign(Iterator& first, Sentinel const& last)
0974 {
0975 return detail_spirit_x3::extract_sign(first, last);
0976 }
0977 };
0978
0979 template <typename T>
0980 struct strict_ureal_policies : ureal_policies<T>
0981 {
0982 static bool const expect_dot = true;
0983 };
0984
0985 template <typename T>
0986 struct strict_real_policies : real_policies<T>
0987 {
0988 static bool const expect_dot = true;
0989 };
0990 }
0991
0992 namespace boost::parser::detail::numeric {
0993
0994 template<typename I, typename S>
0995 constexpr bool common_range = std::is_same_v<I, S>;
0996
0997 template<typename I, typename S>
0998 using unpacked_iter = decltype(text::unpack_iterator_and_sentinel(
0999 std::declval<I>(), std::declval<S>())
1000 .first);
1001
1002 template<typename I, typename S>
1003 constexpr bool unpacks_to_chars =
1004 std::is_pointer_v<unpacked_iter<I, S>> && std::is_same_v<
1005 std::remove_cv_t<std::remove_reference_t<
1006 std::remove_pointer_t<unpacked_iter<I, S>>>>,
1007 char>;
1008
1009 inline namespace BOOST_PARSER_NUMERIC_NS {
1010
1011 template<int MinDigits, int MaxDigits, typename I, typename S>
1012 #if defined(BOOST_PARSER_HAVE_CHARCONV)
1013 constexpr bool use_charconv_int =
1014 MinDigits == 1 && MaxDigits == -1 &&
1015 common_range<I, S> && unpacks_to_chars<I, S>;
1016 #else
1017 constexpr bool use_charconv_int = false;
1018 #endif
1019
1020 template<
1021 bool Signed,
1022 int Radix,
1023 int MinDigits,
1024 int MaxDigits,
1025 typename I,
1026 typename S,
1027 typename T>
1028 bool parse_int(I & first, S last, T & attr)
1029 {
1030 if constexpr (use_charconv_int<MinDigits, MaxDigits, I, S>) {
1031 #if defined(BOOST_PARSER_HAVE_CHARCONV)
1032 auto unpacked = text::unpack_iterator_and_sentinel(first, last);
1033 #if defined(BOOST_PARSER_HAVE_STD_CHARCONV)
1034 std::from_chars_result const result = std::from_chars(
1035 #else
1036 charconv::from_chars_result const result = charconv::from_chars(
1037 #endif
1038 unpacked.first, unpacked.last, attr, Radix);
1039 if (result.ec == std::errc()) {
1040 first = unpacked.repack(result.ptr);
1041 return true;
1042 }
1043 return false;
1044 #endif
1045 } else if constexpr (Signed) {
1046 using extract = detail_spirit_x3::
1047 extract_int<T, Radix, MinDigits, MaxDigits>;
1048 return extract::call(first, last, attr);
1049 } else {
1050 using extract = detail_spirit_x3::
1051 extract_uint<T, Radix, MinDigits, MaxDigits>;
1052 return extract::call(first, last, attr);
1053 }
1054 }
1055
1056 template<typename I, typename S>
1057 #if defined(BOOST_PARSER_HAVE_CHARCONV)
1058 constexpr bool use_charconv_real =
1059 common_range<I, S> && unpacks_to_chars<I, S>;
1060 #else
1061 constexpr bool use_charconv_real = false;
1062 #endif
1063
1064 template<typename I, typename S, typename T>
1065 bool parse_real(I & first, S last, T & attr)
1066 {
1067 if constexpr (use_charconv_real<I, S>) {
1068 #if defined(BOOST_PARSER_HAVE_CHARCONV)
1069 auto unpacked = text::unpack_iterator_and_sentinel(first, last);
1070 #if defined(BOOST_PARSER_HAVE_STD_CHARCONV)
1071 std::from_chars_result const result = std::from_chars(
1072 #else
1073 charconv::from_chars_result const result = charconv::from_chars(
1074 #endif
1075 unpacked.first, unpacked.last, attr);
1076 if (result.ec == std::errc()) {
1077 first = unpacked.repack(result.ptr);
1078 return true;
1079 }
1080 return false;
1081 #endif
1082 } else {
1083 detail_spirit_x3::real_policies<T> policies;
1084 using extract = detail_spirit_x3::
1085 extract_real<T, detail_spirit_x3::real_policies<T>>;
1086 return extract::parse(first, last, attr, policies);
1087 }
1088 }
1089 }
1090 }
1091
1092 #endif