Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-14 08:21:44

0001 // Copyright 2023 Matt Borland
0002 // Distributed under the Boost Software License, Version 1.0.
0003 // https://www.boost.org/LICENSE_1_0.txt
0004 
0005 #ifndef BOOST_CHARCONV_DETAIL_PARSER_HPP
0006 #define BOOST_CHARCONV_DETAIL_PARSER_HPP
0007 
0008 #include <boost/charconv/detail/config.hpp>
0009 #include <boost/charconv/detail/from_chars_result.hpp>
0010 #include <boost/charconv/detail/from_chars_integer_impl.hpp>
0011 #include <boost/charconv/detail/integer_search_trees.hpp>
0012 #include <boost/charconv/limits.hpp>
0013 #include <boost/charconv/chars_format.hpp>
0014 #include <system_error>
0015 #include <type_traits>
0016 #include <limits>
0017 #include <cerrno>
0018 #include <cstdint>
0019 #include <cstring>
0020 
0021 #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
0022 # pragma GCC diagnostic push
0023 # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
0024 #endif
0025 
0026 namespace boost { namespace charconv { namespace detail {
0027 
0028 inline bool is_integer_char(char c) noexcept
0029 {
0030     return (c >= '0') && (c <= '9');
0031 }
0032 
0033 inline bool is_hex_char(char c) noexcept
0034 {
0035     return is_integer_char(c) || (((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')));
0036 }
0037 
0038 inline bool is_delimiter(char c, chars_format fmt) noexcept
0039 {
0040     if (fmt != chars_format::hex)
0041     {
0042         return !is_integer_char(c) && c != 'e' && c != 'E';
0043     }
0044 
0045     return !is_hex_char(c) && c != 'p' && c != 'P';
0046 }
0047 
0048 inline from_chars_result from_chars_dispatch(const char* first, const char* last, std::uint64_t& value, int base) noexcept
0049 {
0050     return boost::charconv::detail::from_chars(first, last, value, base);
0051 }
0052 
0053 inline from_chars_result from_chars_dispatch(const char* first, const char* last, uint128& value, int base) noexcept
0054 {
0055     return boost::charconv::detail::from_chars128(first, last, value, base);
0056 }
0057 
0058 #ifdef BOOST_CHARCONV_HAS_INT128
0059 inline from_chars_result from_chars_dispatch(const char* first, const char* last, boost::uint128_type& value, int base) noexcept
0060 {
0061     return boost::charconv::detail::from_chars128(first, last, value, base);
0062 }
0063 #endif
0064 
0065 template<typename Unsigned_Integer>
0066 typename std::enable_if<std::is_unsigned<Unsigned_Integer>::value &&
0067                         std::numeric_limits<Unsigned_Integer>::is_integer &&
0068                         sizeof(Unsigned_Integer) < sizeof(std::uint64_t),
0069          from_chars_result>::type
0070     from_chars_dispatch(const char* first, const char* last, Unsigned_Integer& value, int base) noexcept
0071 {
0072     std::uint64_t tmp_value;
0073     auto result = boost::charconv::detail::from_chars(first, last, tmp_value, base);
0074     if (result) {
0075         if (tmp_value > (std::numeric_limits<Unsigned_Integer>::max)())
0076             result.ec = std::errc::result_out_of_range;
0077         else
0078             value = static_cast<Unsigned_Integer>(tmp_value);
0079     }
0080     return result;
0081 }
0082 
0083 template <typename Unsigned_Integer, typename Integer>
0084 inline from_chars_result parser(const char* first, const char* last, bool& sign, Unsigned_Integer& significand, Integer& exponent, chars_format fmt = chars_format::general) noexcept
0085 {
0086     if (first > last)
0087     {
0088         return {first, std::errc::invalid_argument};
0089     }
0090 
0091     auto next = first;
0092     bool all_zeros = true;
0093 
0094     // First extract the sign
0095     if (*next == '-')
0096     {
0097         sign = true;
0098         ++next;
0099     }
0100     else if (*next == '+')
0101     {
0102         return {next, std::errc::invalid_argument};
0103     }
0104     else
0105     {
0106         sign = false;
0107     }
0108 
0109     // Handle non-finite values
0110     // Stl allows for string like "iNf" to return inf
0111     //
0112     // This is nested ifs rather than a big one-liner to ensure that once we hit an invalid character
0113     // or an end of buffer we return the correct value of next
0114     if (next != last && (*next == 'i' || *next == 'I'))
0115     {
0116         ++next;
0117         if (next != last && (*next == 'n' || *next == 'N'))
0118         {
0119             ++next;
0120             if (next != last && (*next == 'f' || *next == 'F'))
0121             {
0122                 significand = 0;
0123                 return {next, std::errc::value_too_large};
0124             }
0125         }
0126 
0127         return {next, std::errc::invalid_argument};
0128     }
0129     else if (next != last && (*next == 'n' || *next == 'N'))
0130     {
0131         ++next;
0132         if (next != last && (*next == 'a' || *next == 'A'))
0133         {
0134             ++next;
0135             if (next != last && (*next == 'n' || *next == 'N'))
0136             {
0137                 ++next;
0138                 if (next != last && (*next == '('))
0139                 {
0140                     ++next;
0141                     if (next != last && (*next == 's' || *next == 'S'))
0142                     {
0143                         significand = 1;
0144                         return {next, std::errc::not_supported};
0145                     }
0146                     else if (next != last && (*next == 'i' || *next == 'I'))
0147                     {
0148                         significand = 0;
0149                         return {next, std::errc::not_supported};
0150                     }
0151                 }
0152                 else
0153                 {
0154                     significand = 0;
0155                     return {next, std::errc::not_supported};
0156                 }
0157             }
0158         }
0159 
0160         return {next, std::errc::invalid_argument};
0161     }
0162 
0163     // Ignore leading zeros (e.g. 00005 or -002.3e+5)
0164     while (next != last && *next == '0')
0165     {
0166         ++next;
0167     }
0168 
0169     // If the number is 0 we can abort now
0170     char exp_char;
0171     char capital_exp_char;
0172     if (fmt != chars_format::hex)
0173     {
0174         exp_char = 'e';
0175         capital_exp_char = 'E';
0176     }
0177     else
0178     {
0179         exp_char = 'p';
0180         capital_exp_char = 'P';
0181     }
0182 
0183     if (next == last || *next == exp_char || *next == -capital_exp_char)
0184     {
0185         significand = 0;
0186         exponent = 0;
0187         return {next, std::errc()};
0188     }
0189 
0190     // Next we get the significand
0191     constexpr std::size_t significand_buffer_size = limits<Unsigned_Integer>::max_chars10; // Base 10 or 16
0192     char significand_buffer[significand_buffer_size] {};
0193     std::size_t i = 0;
0194     std::size_t dot_position = 0;
0195     Integer extra_zeros = 0;
0196     Integer leading_zero_powers = 0;
0197     const auto char_validation_func = (fmt != boost::charconv::chars_format::hex) ? is_integer_char : is_hex_char;
0198     const int base = (fmt != boost::charconv::chars_format::hex) ? 10 : 16;
0199 
0200     while (next != last && char_validation_func(*next) && i < significand_buffer_size)
0201     {
0202         all_zeros = false;
0203         significand_buffer[i] = *next;
0204         ++next;
0205         ++i;
0206     }
0207 
0208     bool fractional = false;
0209     if (next == last)
0210     {
0211         // if fmt is chars_format::scientific the e is required
0212         if (fmt == chars_format::scientific)
0213         {
0214             return {first, std::errc::invalid_argument};
0215         }
0216         
0217         exponent = 0;
0218         std::size_t offset = i;
0219 
0220         from_chars_result r = from_chars_dispatch(significand_buffer, significand_buffer + offset, significand, base);
0221         switch (r.ec)
0222         {
0223             case std::errc::invalid_argument:
0224                 return {first, std::errc::invalid_argument};
0225             case std::errc::result_out_of_range:
0226                 return {next, std::errc::result_out_of_range};
0227             default:
0228                 return {next, std::errc()};
0229         }
0230     }
0231     else if (*next == '.')
0232     {
0233         ++next;
0234         fractional = true;
0235         dot_position = i;
0236 
0237         // Process the fractional part if we have it
0238         //
0239         // if fmt is chars_format::scientific the e is required
0240         // if fmt is chars_format::fixed and not scientific the e is disallowed
0241         // if fmt is chars_format::general (which is scientific and fixed) the e is optional
0242 
0243         // If we have the value 0.00001 we can continue to chop zeros and adjust the exponent
0244         // so that we get the useful parts of the fraction
0245         if (all_zeros)
0246         {
0247             while (next != last && *next == '0')
0248             {
0249                 ++next;
0250                 --leading_zero_powers;
0251             }
0252 
0253             if (next == last)
0254             {
0255                 significand = 0;
0256                 exponent = 0;
0257                 return {last, std::errc()};
0258             }
0259         }
0260 
0261         while (next != last && char_validation_func(*next) && i < significand_buffer_size)
0262         {
0263             significand_buffer[i] = *next;
0264             ++next;
0265             ++i;
0266         }
0267     }
0268     
0269     if (i == significand_buffer_size)
0270     {
0271         // We can not process any more significant figures into the significand so skip to the end
0272         // or the exponent part and capture the additional orders of magnitude for the exponent
0273         bool found_dot = false;
0274         while (next != last && (char_validation_func(*next) || *next == '.'))
0275         {
0276             ++next;
0277             if (!fractional && !found_dot)
0278             {
0279                 ++extra_zeros;
0280             }
0281             if (next != last && *next == '.')
0282             {
0283                 found_dot = true;
0284             }
0285         }
0286     }
0287 
0288     if (next == last || is_delimiter(*next, fmt))
0289     {
0290         if (fmt == chars_format::scientific)
0291         {
0292             return {first, std::errc::invalid_argument};
0293         }
0294         if (dot_position != 0 || fractional)
0295         {
0296             exponent = static_cast<Integer>(dot_position) - static_cast<Integer>(i) + extra_zeros + leading_zero_powers;
0297         }
0298         else
0299         {
0300             exponent = extra_zeros + leading_zero_powers;
0301         }
0302         std::size_t offset = i;
0303         
0304         from_chars_result r = from_chars_dispatch(significand_buffer, significand_buffer + offset, significand, base);
0305         switch (r.ec)
0306         {
0307             case std::errc::invalid_argument:
0308                 return {first, std::errc::invalid_argument};
0309             case std::errc::result_out_of_range:
0310                 return {next, std::errc::result_out_of_range};
0311             default:
0312                 return {next, std::errc()};
0313         }
0314     }
0315     else if (*next == exp_char || *next == capital_exp_char)
0316     {
0317         // Would be a number without a significand e.g. e+03
0318         if (next == first)
0319         {
0320             return {next, std::errc::invalid_argument};
0321         }
0322 
0323         ++next;
0324         if (fmt == chars_format::fixed)
0325         {
0326             return {first, std::errc::invalid_argument};
0327         }
0328 
0329         std::size_t offset = i;
0330         bool round = false;
0331         // If more digits are present than representable in the significand of the target type
0332         // we set the maximum
0333         if (offset > significand_buffer_size)
0334         {
0335             offset = significand_buffer_size - 1;
0336             i = significand_buffer_size;
0337             if (significand_buffer[offset] == '5' ||
0338                 significand_buffer[offset] == '6' ||
0339                 significand_buffer[offset] == '7' ||
0340                 significand_buffer[offset] == '8' ||
0341                 significand_buffer[offset] == '9')
0342             {
0343                 round = true;
0344             }
0345         }
0346         
0347         // If the significand is 0 from chars will return std::errc::invalid_argument because there is nothing in the buffer,
0348         // but it is a valid value. We need to continue parsing to get the correct value of ptr even
0349         // though we know we could bail now.
0350         //
0351         // See GitHub issue #29: https://github.com/cppalliance/charconv/issues/29
0352         if (offset != 0)
0353         {
0354             from_chars_result r = from_chars_dispatch(significand_buffer, significand_buffer + offset, significand, base);
0355             switch (r.ec)
0356             {
0357                 case std::errc::invalid_argument:
0358                     return {first, std::errc::invalid_argument};
0359                 case std::errc::result_out_of_range:
0360                     return {next, std::errc::result_out_of_range};
0361                 default:
0362                     break;
0363             }
0364 
0365             if (round)
0366             {
0367                 significand = static_cast<Unsigned_Integer>(significand + 1u);
0368             }
0369         }
0370         else
0371             significand = 0;
0372     }
0373     else
0374     {
0375         return {first, std::errc::invalid_argument};
0376     }
0377 
0378     // Finally we get the exponent
0379     constexpr std::size_t exponent_buffer_size = 6; // Float128 min exp is −16382
0380     char exponent_buffer[exponent_buffer_size] {};
0381     const auto significand_digits = i;
0382     i = 0;
0383 
0384     // Get the sign first
0385     if (next != last && *next == '-')
0386     {
0387         exponent_buffer[i] = *next;
0388         ++next;
0389         ++i;
0390     }
0391     else if (next != last && *next == '+')
0392     {
0393         ++next;
0394     }
0395 
0396     // Next strip any leading zeros
0397     while (next != last && *next == '0')
0398     {
0399         ++next;
0400     }
0401 
0402     // Process the significant values
0403     while (next != last && is_integer_char(*next) && i < exponent_buffer_size)
0404     {
0405         exponent_buffer[i] = *next;
0406         ++next;
0407         ++i;
0408     }
0409 
0410     // If the exponent can't fit in the buffer the number is not representable
0411     if (next != last && i == exponent_buffer_size)
0412     {
0413         return {next, std::errc::result_out_of_range};
0414     }
0415 
0416     // If the exponent was e+00 or e-00
0417     if (i == 0 || (i == 1 && exponent_buffer[0] == '-'))
0418     {
0419         if (fractional)
0420         {
0421             exponent = static_cast<Integer>(dot_position - significand_digits);
0422         }
0423         else
0424         {
0425             exponent = extra_zeros;
0426         }
0427 
0428         return {next, std::errc()};
0429     }
0430 
0431     const auto r = from_chars(exponent_buffer, exponent_buffer + i, exponent);
0432 
0433     exponent += leading_zero_powers;
0434 
0435     switch (r.ec)
0436     {
0437         case std::errc::invalid_argument:
0438             return {first, std::errc::invalid_argument};
0439         case std::errc::result_out_of_range:
0440             return {next, std::errc::result_out_of_range};
0441         default:
0442             if (fractional)
0443             {
0444                 // Need to take the offset from 1.xxx because compute_floatXXX assumes the significand is an integer
0445                 // so the exponent is off by the number of digits in the significand - 1
0446                 if (fmt == chars_format::hex)
0447                 {
0448                     // In hex the number of digits parsed is possibly less than the number of digits in base10
0449                     exponent -= num_digits(significand) - static_cast<Integer>(dot_position);
0450                 }
0451                 else
0452                 {
0453                     exponent -= static_cast<Integer>(significand_digits - dot_position);
0454                 }
0455             }
0456             else
0457             {
0458                 exponent += extra_zeros;
0459             }
0460 
0461             return {next, std::errc()};
0462     }
0463 }
0464 
0465 }}} // Namespaces
0466 
0467 #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
0468 # pragma GCC diagnostic pop
0469 #endif
0470 
0471 #endif // BOOST_CHARCONV_DETAIL_PARSER_HPP