From e776e4136167715884bee25201020fc204ba8f7b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 12 May 2023 12:18:48 +0200 Subject: [PATCH 1/4] Add test values reported in issue --- test/test_boost_json_values.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/test_boost_json_values.cpp b/test/test_boost_json_values.cpp index d416b49..10e8ec4 100644 --- a/test/test_boost_json_values.cpp +++ b/test/test_boost_json_values.cpp @@ -363,5 +363,15 @@ int main() "00000000000000000000000000000000000000000000000000" // 500 zeroes ); + // Reported in issue #29 + // https://github.com/cppalliance/charconv/issues/29 + + fc("0E0"); + fc("0E01"); + fc("0.0e0"); + fc("-0E0"); + fc("-0E01"); + fc("-0.0e0"); + return boost::report_errors(); } From 49be94043b4c22e2d14d120906638ad703827578 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 12 May 2023 12:38:27 +0200 Subject: [PATCH 2/4] Fix handling of a significand equal to 0 --- include/boost/charconv/detail/parser.hpp | 42 ++++++++++++++---------- include/boost/charconv/from_chars.hpp | 4 +-- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/include/boost/charconv/detail/parser.hpp b/include/boost/charconv/detail/parser.hpp index 4b12169..12098c0 100644 --- a/include/boost/charconv/detail/parser.hpp +++ b/include/boost/charconv/detail/parser.hpp @@ -243,25 +243,33 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign, } from_chars_result r {}; - if (fmt == chars_format::hex) - { - r = from_chars(significand_buffer, significand_buffer + offset, significand, 16); - } - else - { - r = from_chars(significand_buffer, significand_buffer + offset, significand); - } - switch (r.ec) - { - case EINVAL: - return {first, EINVAL}; - case ERANGE: - return {next, ERANGE}; - } - if (round) + // If the significand is 0 from chars will return EINVAL because there is nothing in the buffer, + // but it is a valid value. We need to continue parsing to get the correct value of ptr even + // though we know we could bail now. + // + // See GitHub issue #29: https://github.com/cppalliance/charconv/issues/29 + if (offset != 0) { - significand += 1; + if (fmt == chars_format::hex) + { + r = from_chars(significand_buffer, significand_buffer + offset, significand, 16); + } else + { + r = from_chars(significand_buffer, significand_buffer + offset, significand); + } + switch (r.ec) + { + case EINVAL: + return {first, EINVAL}; + case ERANGE: + return {next, ERANGE}; + } + + if (round) + { + significand += 1; + } } } diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 8b95a2e..1b63c00 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -137,9 +137,9 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T& std::int64_t exponent {}; auto r = boost::charconv::detail::parser(first, last, sign, significand, exponent, fmt); - if (r.ec != 0) + if (r.ec != 0 || significand == 0) { - value = 0; + value = sign ? static_cast(-0.0L) : static_cast(0.0L); return r; } From e4ab9c5b579c05493d8c2a2ed98a2345466fb2e8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 12 May 2023 12:56:29 +0200 Subject: [PATCH 3/4] Add value without significand handling and test --- include/boost/charconv/detail/parser.hpp | 6 ++++++ test/from_chars_float.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/include/boost/charconv/detail/parser.hpp b/include/boost/charconv/detail/parser.hpp index 12098c0..5cd9b7d 100644 --- a/include/boost/charconv/detail/parser.hpp +++ b/include/boost/charconv/detail/parser.hpp @@ -217,6 +217,12 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign, } else if (*next == exp_char || *next == capital_exp_char) { + // Would be a number without a significand e.g. e+03 + if (next == first) + { + return {next, EINVAL}; + } + ++next; if (fmt == chars_format::fixed) { diff --git a/test/from_chars_float.cpp b/test/from_chars_float.cpp index dbcbed2..5bc5c25 100644 --- a/test/from_chars_float.cpp +++ b/test/from_chars_float.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include template @@ -167,6 +168,10 @@ void odd_strings_test() BOOST_TEST_EQ(r5.ec, 0); BOOST_TEST_EQ(v5, static_cast(1.23456789123456789123456789123456789123456789e-5L)); + const char* buffer6 = "E01"; + T v6 = 0; + auto r6 = boost::charconv::from_chars(buffer6, buffer6 + std::strlen(buffer6), v6); + BOOST_TEST_EQ(r6.ec, EINVAL); } template From dc7f2cd04b1a7b09e11eb5f5d854324451369c41 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 12 May 2023 13:00:03 +0200 Subject: [PATCH 4/4] If value is EINVAL it should be returned unmodified --- include/boost/charconv/from_chars.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 1b63c00..678d9f3 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -137,7 +137,11 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T& std::int64_t exponent {}; auto r = boost::charconv::detail::parser(first, last, sign, significand, exponent, fmt); - if (r.ec != 0 || significand == 0) + if (r.ec != 0) + { + return r; + } + else if (significand == 0) { value = sign ? static_cast(-0.0L) : static_cast(0.0L); return r;