File indexing completed on 2025-10-14 08:21:44
0001
0002
0003
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
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
0110
0111
0112
0113
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
0164 while (next != last && *next == '0')
0165 {
0166 ++next;
0167 }
0168
0169
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
0191 constexpr std::size_t significand_buffer_size = limits<Unsigned_Integer>::max_chars10;
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
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
0238
0239
0240
0241
0242
0243
0244
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
0272
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
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
0332
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
0348
0349
0350
0351
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
0379 constexpr std::size_t exponent_buffer_size = 6;
0380 char exponent_buffer[exponent_buffer_size] {};
0381 const auto significand_digits = i;
0382 i = 0;
0383
0384
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
0397 while (next != last && *next == '0')
0398 {
0399 ++next;
0400 }
0401
0402
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
0411 if (next != last && i == exponent_buffer_size)
0412 {
0413 return {next, std::errc::result_out_of_range};
0414 }
0415
0416
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
0445
0446 if (fmt == chars_format::hex)
0447 {
0448
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 }}}
0466
0467 #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
0468 # pragma GCC diagnostic pop
0469 #endif
0470
0471 #endif