Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:40:27

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     Copyright (c) 2019 T. Zachary Laine
0008 
0009     Distributed under the Boost Software License, Version 1.0. (See accompanying
0010     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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     // Copied from boost/spirit/home/support/char_class.hpp (Boost 1.71), and
0047     // modified not to use Boost.TypeTraits.
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                 // source is signed, target is unsigned
0057                 typedef std::make_unsigned_t<SourceChar> USourceChar;
0058                 return TargetChar(USourceChar(ch));
0059             }
0060             else
0061             {
0062                 // source is unsigned, target is signed
0063                 typedef std::make_signed_t<SourceChar> SSourceChar;
0064                 return TargetChar(SSourceChar(ch));
0065             }
0066         }
0067         else
0068         {
0069             // source and target has same signedness
0070             return TargetChar(ch); // just cast
0071         }
0072     }
0073 
0074     // Copied from
0075     // boost/spirit/home/x3/support/numeric_utils/detail/extract_int.hpp
0076     // (Boost 1.67), and modified not to use Boost.MPL or Boost.PP.
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) // unchecked add
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) // checked add
0134         {
0135             // Ensure n *= Radix will not overflow
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             // Ensure n += digit will not overflow
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) // unchecked subtract
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) // checked subtract
0165         {
0166             // Ensure n *= Radix will not underflow
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             // Ensure n -= digit will not underflow
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; //  over/underflow!
0202             }
0203             return true;
0204         }
0205 
0206         template <typename Char, typename T>
0207         inline static bool
0208         call(Char ch, std::size_t /*count*/, T& n, std::false_type)
0209         {
0210             // no need to check for overflow
0211             Accumulator::add(n, ch, std::false_type{});
0212             return true;
0213         }
0214 
0215         template <typename Char>
0216         inline static bool
0217         call(Char /*ch*/, std::size_t /*count*/, 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; // bounded
0244         }
0245     };
0246 
0247     template <>
0248     struct check_max_digits<-1>
0249     {
0250         inline static bool
0251         call(std::size_t /*count*/)
0252         {
0253             return true; // unbounded
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                 // skip leading zeros
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; // must calculate value to detect over/underflow
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                 // skip leading zeros
0376                 while (it != last && *it == '0')
0377                 {
0378                     ++it;
0379                     ++count;
0380                 }
0381 
0382                 if (it == last)
0383                 {
0384                     if (count == 0) // must have at least one digit
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) // must have at least one digit
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; // must calculate value to detect over/underflow
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     // Copied from boost/spirit/home/x3/support/numeric_utils/extract_int.hpp
0468     // (Boost 1.67), and modified for use with iterator, sentinel pairs:
0469 
0470     ///////////////////////////////////////////////////////////////////////////
0471     //  Extract the prefix sign (- or +), return true if a '-' was found
0472     ///////////////////////////////////////////////////////////////////////////
0473     template<typename Iterator, typename Sentinel>
0474     inline bool extract_sign(Iterator & first, Sentinel last)
0475     {
0476         (void)last;                  // silence unused warnings
0477         BOOST_PARSER_DEBUG_ASSERT(first != last); // precondition
0478 
0479         // Extract the sign
0480         bool neg = *first == '-';
0481         if (neg || (*first == '+'))
0482         {
0483             ++first;
0484             return neg;
0485         }
0486         return false;
0487     }
0488 
0489     ///////////////////////////////////////////////////////////////////////////
0490     // Low level unsigned integer parser
0491     ///////////////////////////////////////////////////////////////////////////
0492     template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
0493       , bool Accumulate = false>
0494     struct extract_uint
0495     {
0496         // check template parameter 'Radix' for validity
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     // Low level signed integer parser
0528     ///////////////////////////////////////////////////////////////////////////
0529     template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits>
0530     struct extract_int
0531     {
0532         // check template parameter 'Radix' for validity
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     // Copied from boost/spirit/home/x3/support/numeric_utils/extract_real.hpp
0568     // (Boost 1.71), and modified for use with iterator, sentinel pairs:
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             // return false if exp exceeds the max_exp
0633             // do this check only for primitive types!
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                 // return false if exp still exceeds the min_exp
0645                 // do this check only for primitive types!
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             // Start by parsing the sign. neg will be true if
0685             // we got a "-" sign, false otherwise.
0686             bool neg = p.parse_sign(first, last);
0687 
0688             // Now attempt to parse an integer
0689             T n = 0;
0690             bool got_a_number = p.parse_n(first, last, n);
0691 
0692             // If we did not get a number it might be a NaN, Inf or a leading
0693             // dot.
0694             if (!got_a_number)
0695             {
0696                 // Check whether the number to parse is a NaN or Inf
0697                 if (p.parse_nan(first, last, n) ||
0698                     p.parse_inf(first, last, n))
0699                 {
0700                     // If we got a negative sign, negate the number
0701                     attr = detail_spirit_x3::negate(neg, n);
0702                     return true;    // got a NaN or Inf, return early
0703                 }
0704 
0705                 // If we did not get a number and our policies do not
0706                 // allow a leading dot, fail and return early (no-match)
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             // Try to parse the dot ('.' decimal point)
0719             if (p.parse_dot(first, last))
0720             {
0721                 // We got the decimal point. Now we will try to parse
0722                 // the fraction if it is there. If not, it defaults
0723                 // to zero (0) only if we already got a number.
0724                 Iterator savef = first;
0725                 if (p.parse_frac_n(first, last, n))
0726                 {
0727                     // Optimization note: don't compute frac_digits if T is
0728                     // an unused_type. This should be optimized away by the compiler.
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                     // We did not get a fraction. If we still haven't got a
0737                     // number and our policies do not allow a trailing dot,
0738                     // return no-match.
0739                     first = save;
0740                     return false;
0741                 }
0742 
0743                 // Now, let's see if we can parse the exponent prefix
0744                 e_pos = first;
0745                 e_hit = p.parse_exp(first, last);
0746             }
0747             else
0748             {
0749                 // No dot and no number! Return no-match.
0750                 if (!got_a_number)
0751                 {
0752                     first = save;
0753                     return false;
0754                 }
0755 
0756                 // If we must expect a dot and we didn't see an exponent
0757                 // prefix, return no-match.
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                 // We got the exponent prefix. Now we will try to parse the
0770                 // actual exponent. It is an error if it is not there.
0771                 int exp = 0;
0772                 if (p.parse_exp_n(first, last, exp))
0773                 {
0774                     // Got the exponent value. Scale the number by
0775                     // exp-frac_digits.
0776                     if (!detail_spirit_x3::scale(exp, frac_digits, n))
0777                         return false;
0778                 }
0779                 else
0780                 {
0781                     // If there is no number, disregard the exponent altogether.
0782                     // by resetting 'first' prior to the exponent prefix (e|E)
0783                     first = e_pos;
0784 
0785                     // Scale the number by -frac_digits.
0786                     if (!detail_spirit_x3::scale(-frac_digits, n))
0787                         return false;
0788                 }
0789             }
0790             else if (frac_digits)
0791             {
0792                 // No exponent found. Scale the number by -frac_digits.
0793                 if (!detail_spirit_x3::scale(-frac_digits, n))
0794                     return false;
0795             }
0796 
0797             // If we got a negative sign, negate the number
0798             attr = detail_spirit_x3::negate(neg, n);
0799 
0800             // Success!!!
0801             return true;
0802         }
0803     };
0804 
0805     // Copied from
0806     // boost/spirit/home/x3/string/detail/string_parse.hpp
0807     // (Boost 1.47),and modified for use with iterator, sentinel pairs:
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     // Copied from
0836     // boost/spirit/home/x3/numeric/real_policies.hpp
0837     // (Boost 1.47),and modified for use with iterator, sentinel pairs:
0838 
0839     ///////////////////////////////////////////////////////////////////////////
0840     //  Default (unsigned) real number policies
0841     ///////////////////////////////////////////////////////////////////////////
0842     template <typename T>
0843     struct ureal_policies
0844     {
0845         // trailing dot policy suggested by Gustavo Guerra
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& /*first*/, Iterator const& /*last*/)
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         //  The parse_nan() and parse_inf() functions get called whenever
0900         //  a number to parse does not start with a digit (after having
0901         //  successfully parsed an optional sign).
0902         //
0903         //  The functions should return true if a Nan or Inf has been found. In
0904         //  this case the attr should be set to the matched value (NaN or
0905         //  Inf). The optional sign will be automatically applied afterwards.
0906         //
0907         //  The default implementation below recognizes representations of NaN
0908         //  and Inf as mandated by the C99 Standard and as proposed for
0909         //  inclusion into the C++0x Standard: nan, nan(...), inf and infinity
0910         //  (the matching is performed case-insensitively).
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;   // end of input reached
0918 
0919             if (*first != 'n' && *first != 'N')
0920                 return false;   // not "nan"
0921 
0922             // nan[(...)] ?
0923             if (detail_spirit_x3::string_parse("nan", "NAN", first, last))
0924             {
0925                 if (first != last && *first == '(')
0926                 {
0927                     // skip trailing (...) part
0928                     Iterator i = first;
0929 
0930                     while (++i != last && *i != ')')
0931                         ;
0932                     if (i == last)
0933                         return false;     // no trailing ')' found, give up
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;   // end of input reached
0949 
0950             if (*first != 'i' && *first != 'I')
0951                 return false;   // not "inf"
0952 
0953             // inf or infinity ?
0954             if (detail_spirit_x3::string_parse("inf", "INF", first, last))
0955             {
0956                 // skip allowed 'inity' part of infinity
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     //  Default (signed) real number policies
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