Merge pull request #297 from cobyj33/cobyj33-more-descriptive-errors

More descriptive parse_number errors
This commit is contained in:
Pranav 2023-10-28 06:23:51 -05:00 committed by GitHub
commit e4d4f67a44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -214,13 +214,13 @@ inline auto do_from_chars(std::string_view s) -> T {
if (ptr == last) { if (ptr == last) {
return x; return x;
} }
throw std::invalid_argument{"pattern does not match to the end"}; throw std::invalid_argument{"pattern '" + std::string(s) + "' does not match to the end"};
} }
if (ec == std::errc::invalid_argument) { if (ec == std::errc::invalid_argument) {
throw std::invalid_argument{"pattern not found"}; throw std::invalid_argument{"pattern '" + std::string(s) + "' not found"};
} }
if (ec == std::errc::result_out_of_range) { if (ec == std::errc::result_out_of_range) {
throw std::range_error{"not representable"}; throw std::range_error{"'" + std::string(s) + "' not representable"};
} }
return x; // unreachable return x; // unreachable
} }
@ -235,14 +235,27 @@ template <class T> struct parse_number<T, radix_16> {
auto operator()(std::string_view s) -> T { auto operator()(std::string_view s) -> T {
if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) {
if (auto [ok, rest] = consume_hex_prefix(s); ok) { if (auto [ok, rest] = consume_hex_prefix(s); ok) {
return do_from_chars<T, radix_16>(rest); try {
return do_from_chars<T, radix_16>(rest);
} catch (const std::invalid_argument& err) {
throw std::invalid_argument("Failed to parse '" + std::string(s) + "' as hexadecimal: " + err.what());
} catch (const std::range_error& err) {
throw std::range_error("Failed to parse '" + std::string(s) + "' as hexadecimal: " + err.what());
}
} }
} else { } else {
// Allow passing hex numbers without prefix // Allow passing hex numbers without prefix
// Shape 'x' already has to be specified // Shape 'x' already has to be specified
return do_from_chars<T, radix_16>(s); try {
return do_from_chars<T, radix_16>(s);
} catch (const std::invalid_argument& err) {
throw std::invalid_argument("Failed to parse '" + std::string(s) + "' as hexadecimal: " + err.what());
} catch (const std::range_error& err) {
throw std::range_error("Failed to parse '" + std::string(s) + "' as hexadecimal: " + err.what());
}
} }
throw std::invalid_argument{"pattern not found"};
throw std::invalid_argument{"pattern '" + std::string(s) + "' not identified as hexadecimal"};
} }
}; };
@ -250,12 +263,32 @@ template <class T> struct parse_number<T> {
auto operator()(std::string_view s) -> T { auto operator()(std::string_view s) -> T {
auto [ok, rest] = consume_hex_prefix(s); auto [ok, rest] = consume_hex_prefix(s);
if (ok) { if (ok) {
return do_from_chars<T, radix_16>(rest); try {
return do_from_chars<T, radix_16>(rest);
} catch (const std::invalid_argument& err) {
throw std::invalid_argument("Failed to parse '" + std::string(s) + "' as hexadecimal: " + err.what());
} catch (const std::range_error& err) {
throw std::range_error("Failed to parse '" + std::string(s) + "' as hexadecimal: " + err.what());
}
} }
if (starts_with("0"sv, s)) { if (starts_with("0"sv, s)) {
return do_from_chars<T, radix_8>(rest); try {
return do_from_chars<T, radix_8>(rest);
} catch (const std::invalid_argument& err) {
throw std::invalid_argument("Failed to parse '" + std::string(s) + "' as octal: " + err.what());
} catch (const std::range_error& err) {
throw std::range_error("Failed to parse '" + std::string(s) + "' as octal: " + err.what());
}
}
try {
return do_from_chars<T, radix_10>(rest);
} catch (const std::invalid_argument& err) {
throw std::invalid_argument("Failed to parse '" + std::string(s) + "' as decimal integer: " + err.what());
} catch (const std::range_error& err) {
throw std::range_error("Failed to parse '" + std::string(s) + "' as decimal integer: " + err.what());
} }
return do_from_chars<T, radix_10>(rest);
} }
}; };
@ -270,7 +303,7 @@ template <> inline const auto generic_strtod<long double> = strtold;
template <class T> inline auto do_strtod(std::string const &s) -> T { template <class T> inline auto do_strtod(std::string const &s) -> T {
if (isspace(static_cast<unsigned char>(s[0])) || s[0] == '+') { if (isspace(static_cast<unsigned char>(s[0])) || s[0] == '+') {
throw std::invalid_argument{"pattern not found"}; throw std::invalid_argument{"pattern '" + s + "' not found"};
} }
auto [first, last] = pointer_range(s); auto [first, last] = pointer_range(s);
@ -282,10 +315,10 @@ template <class T> inline auto do_strtod(std::string const &s) -> T {
if (ptr == last) { if (ptr == last) {
return x; return x;
} }
throw std::invalid_argument{"pattern does not match to the end"}; throw std::invalid_argument{"pattern '" + s + "' does not match to the end"};
} }
if (errno == ERANGE) { if (errno == ERANGE) {
throw std::range_error{"not representable"}; throw std::range_error{"'" + s + "' not representable"};
} }
return x; // unreachable return x; // unreachable
} }
@ -297,7 +330,13 @@ template <class T> struct parse_number<T, chars_format::general> {
"chars_format::general does not parse hexfloat"}; "chars_format::general does not parse hexfloat"};
} }
return do_strtod<T>(s); try {
return do_strtod<T>(s);
} catch (const std::invalid_argument& err) {
throw std::invalid_argument("Failed to parse '" + s + "' as number: " + err.what());
} catch (const std::range_error& err) {
throw std::range_error("Failed to parse '" + s + "' as number: " + err.what());
}
} }
}; };
@ -307,7 +346,13 @@ template <class T> struct parse_number<T, chars_format::hex> {
throw std::invalid_argument{"chars_format::hex parses hexfloat"}; throw std::invalid_argument{"chars_format::hex parses hexfloat"};
} }
return do_strtod<T>(s); try {
return do_strtod<T>(s);
} catch (const std::invalid_argument& err) {
throw std::invalid_argument("Failed to parse '" + s + "' as hexadecimal: " + err.what());
} catch (const std::range_error& err) {
throw std::range_error("Failed to parse '" + s + "' as hexadecimal: " + err.what());
}
} }
}; };
@ -322,7 +367,13 @@ template <class T> struct parse_number<T, chars_format::scientific> {
"chars_format::scientific requires exponent part"}; "chars_format::scientific requires exponent part"};
} }
return do_strtod<T>(s); try {
return do_strtod<T>(s);
} catch (const std::invalid_argument& err) {
throw std::invalid_argument("Failed to parse '" + s + "' as scientific notation: " + err.what());
} catch (const std::range_error& err) {
throw std::range_error("Failed to parse '" + s + "' as scientific notation: " + err.what());
}
} }
}; };
@ -337,7 +388,13 @@ template <class T> struct parse_number<T, chars_format::fixed> {
"chars_format::fixed does not parse exponent part"}; "chars_format::fixed does not parse exponent part"};
} }
return do_strtod<T>(s); try {
return do_strtod<T>(s);
} catch (const std::invalid_argument& err) {
throw std::invalid_argument("Failed to parse '" + s + "' as fixed notation: " + err.what());
} catch (const std::range_error& err) {
throw std::range_error("Failed to parse '" + s + "' as fixed notation: " + err.what());
}
} }
}; };