Merge pull request #36 from mborland/29

Fix parsing of 0 or empty significand
This commit is contained in:
Matt Borland
2023-05-12 13:43:09 +02:00
committed by GitHub
4 changed files with 51 additions and 18 deletions

View File

@@ -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)
{
@@ -243,25 +249,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;
}
}
}

View File

@@ -139,7 +139,11 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T&
auto r = boost::charconv::detail::parser(first, last, sign, significand, exponent, fmt);
if (r.ec != 0)
{
value = 0;
return r;
}
else if (significand == 0)
{
value = sign ? static_cast<T>(-0.0L) : static_cast<T>(0.0L);
return r;
}

View File

@@ -9,6 +9,7 @@
#include <string>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <cmath>
template <typename T>
@@ -167,6 +168,10 @@ void odd_strings_test()
BOOST_TEST_EQ(r5.ec, 0);
BOOST_TEST_EQ(v5, static_cast<T>(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 <typename T>

View File

@@ -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();
}