Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 08:19:40

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