File indexing completed on 2025-04-19 08:19:40
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, 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
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
0092
0093
0094
0095
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
0146 while (next != last && *next == '0')
0147 {
0148 ++next;
0149 }
0150
0151
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
0173 constexpr std::size_t significand_buffer_size = limits<Unsigned_Integer>::max_chars10 - 1;
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
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
0220
0221
0222
0223
0224
0225
0226
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
0252
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
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
0313
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
0329
0330
0331
0332
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
0358 constexpr std::size_t exponent_buffer_size = 6;
0359 char exponent_buffer[exponent_buffer_size] {};
0360 const auto significand_digits = i;
0361 i = 0;
0362
0363
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
0376 while (next != last && *next == '0')
0377 {
0378 ++next;
0379 }
0380
0381
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
0390 if (next != last && i == exponent_buffer_size)
0391 {
0392 return {next, std::errc::result_out_of_range};
0393 }
0394
0395
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
0424
0425 if (fmt == chars_format::hex)
0426 {
0427
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 }}}
0445
0446 #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
0447 # pragma GCC diagnostic pop
0448 #endif
0449
0450 #endif