Merge get_number()/get_integer() + changes suggested by @gregmarr
This commit is contained in:
parent
21a00fccc8
commit
e9517958a3
103
src/json.hpp
103
src/json.hpp
@ -5974,12 +5974,12 @@ class basic_json
|
|||||||
// Remove '+' sign from the exponent if necessary
|
// Remove '+' sign from the exponent if necessary
|
||||||
if (!m_type.bits.exp_plus)
|
if (!m_type.bits.exp_plus)
|
||||||
{
|
{
|
||||||
if (static_cast<size_t>(len) > sizeof(buf)) len = sizeof(buf);
|
if (len > static_cast<int>(sizeof(buf))) len = sizeof(buf);
|
||||||
for (size_t i = 0; i < static_cast<size_t>(len); i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
if (buf[i] == '+')
|
if (buf[i] == '+')
|
||||||
{
|
{
|
||||||
for (; i + 1 < static_cast<size_t>(len); i++) buf[i] = buf[i + 1];
|
for (; i + 1 < len; i++) buf[i] = buf[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5992,14 +5992,16 @@ class basic_json
|
|||||||
}
|
}
|
||||||
else if (m_value.number_float == 0)
|
else if (m_value.number_float == 0)
|
||||||
{
|
{
|
||||||
// Special case for zero - use fixed precision to get "0.0"
|
// Special case for zero to get "0.0"/"-0.0"
|
||||||
snprintf(buf, sizeof(buf), "%#.1f", m_value.number_float);
|
if (std::signbit(m_value.number_float)) o << "-0.0";
|
||||||
|
else o << "0.0";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Otherwise 15 digits of precision allows round-trip IEEE 754
|
// Otherwise 6, 15 or 16 digits of precision allows round-trip IEEE 754
|
||||||
// string->double->string; to be safe, we read this value from
|
// string->float->string, string->double->string or string->long double->string;
|
||||||
// std::numeric_limits<number_float_t>::digits10
|
// to be safe, we read this value from std::numeric_limits<number_float_t>::digits10
|
||||||
snprintf(buf, sizeof(buf), "%.*g", std::numeric_limits<double>::digits10, m_value.number_float);
|
snprintf(buf, sizeof(buf), "%.*g", std::numeric_limits<double>::digits10, m_value.number_float);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7814,23 +7816,35 @@ basic_json_parser_64:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief attempt to parse an integer, otherwise get the floating point representation
|
@brief return number value for number tokens
|
||||||
|
|
||||||
This function parses the integer component up to the radix point or exponent.
|
This function translates the last token into the most appropriate number
|
||||||
It also collects information about the floating point representation, which
|
type (either integer, unsigned integer or floating point), which is
|
||||||
|
passed back to the caller via the result parameter.
|
||||||
|
|
||||||
|
This function parses the integer component up to the radix point or exponent
|
||||||
|
while collecting information about the 'floating point representation', which
|
||||||
it stores in the result parameter. If there is no radix point or exponent,
|
it stores in the result parameter. If there is no radix point or exponent,
|
||||||
and the number can fit into a @ref number_integer_t or @ref number_unsigned_t
|
and the number can fit into a @ref number_integer_t or @ref number_unsigned_t
|
||||||
then it sets the result parameter accordingly. The 'floating point
|
then it sets the result parameter accordingly.
|
||||||
representation' includes the number of significant figures after the radix
|
|
||||||
point, whether the number is in exponential or decimal form, the
|
The 'floating point representation' includes the number of significant figures
|
||||||
capitalization of the exponent marker, and if the optional '+' is present in
|
after the radix point, whether the number is in exponential or decimal form,
|
||||||
the exponent. This information is necessary to perform accurate round trips
|
the capitalization of the exponent marker, and if the optional '+' is present
|
||||||
|
in the exponent. This information is necessary to perform accurate round trips
|
||||||
of floating point numbers.
|
of floating point numbers.
|
||||||
|
|
||||||
@param[out] result @ref basic_json object to receive the result.
|
If the number is a floating point number the number is then parsed using
|
||||||
|
@a std:strtod (or @a std:strtof or @a std::strtold).
|
||||||
|
|
||||||
|
@param[out] result @ref basic_json object to receive the number, or NAN if the
|
||||||
|
conversion read past the current token. The latter case needs to be
|
||||||
|
treated by the caller function.
|
||||||
*/
|
*/
|
||||||
value_t get_integer(basic_json& result) const
|
void get_number(basic_json& result) const
|
||||||
{
|
{
|
||||||
|
assert(m_start != nullptr);
|
||||||
|
|
||||||
const lexer::lexer_char_t *curptr = m_start;
|
const lexer::lexer_char_t *curptr = m_start;
|
||||||
result.m_type.bits.parsed = true;
|
result.m_type.bits.parsed = true;
|
||||||
|
|
||||||
@ -7844,7 +7858,7 @@ basic_json_parser_64:
|
|||||||
number_unsigned_t value = 0;
|
number_unsigned_t value = 0;
|
||||||
|
|
||||||
// Maximum absolute value of the relevant integer type
|
// Maximum absolute value of the relevant integer type
|
||||||
uint64_t max;
|
number_unsigned_t max;
|
||||||
|
|
||||||
// Temporarily store the type to avoid unecessary bitfield access
|
// Temporarily store the type to avoid unecessary bitfield access
|
||||||
value_t type;
|
value_t type;
|
||||||
@ -7917,49 +7931,18 @@ basic_json_parser_64:
|
|||||||
result.m_type.bits.precision = precision & found_radix_point;
|
result.m_type.bits.precision = precision & found_radix_point;
|
||||||
|
|
||||||
// Save the value (if not a float)
|
// Save the value (if not a float)
|
||||||
if (type == value_t::number_unsigned) result.m_value.number_unsigned = value;
|
if (type == value_t::number_unsigned)
|
||||||
else if (type == value_t::number_integer) result.m_value.number_integer = -static_cast<number_integer_t>(value);
|
{
|
||||||
|
result.m_value.number_unsigned = value;
|
||||||
// Return the type (don't save it yet)
|
}
|
||||||
return type;
|
else if (type == value_t::number_integer)
|
||||||
}
|
{
|
||||||
|
result.m_value.number_integer = -static_cast<number_integer_t>(value);
|
||||||
/*!
|
}
|
||||||
@brief return number value for number tokens
|
else
|
||||||
|
|
||||||
This function translates the last token into the most appropriate number
|
|
||||||
type (either integer, unsigned integer or floating point), which is
|
|
||||||
passed back to the caller via the result parameter.
|
|
||||||
|
|
||||||
First @ref guess_type() is called to attempt to parse as an integer
|
|
||||||
and to retrieve information about the floating point representation
|
|
||||||
(if applicable) that can be used to accurately render the number to a
|
|
||||||
string later.
|
|
||||||
|
|
||||||
If the number is a floating point number the number is then parsed using
|
|
||||||
@a std:strtod (or @a std:strtof or @a std::strtold), which sets @a endptr
|
|
||||||
to the first character past the converted number. If it is not the same as
|
|
||||||
@ref m_cursor a bad input is assumed and @a result parameter is set to NAN.
|
|
||||||
|
|
||||||
@param[out] result @ref basic_json object to receive the number, or NAN if the
|
|
||||||
conversion read past the current token. The latter case needs to be
|
|
||||||
treated by the caller function.
|
|
||||||
*/
|
|
||||||
void get_number(basic_json& result) const
|
|
||||||
{
|
|
||||||
assert(m_start != nullptr);
|
|
||||||
|
|
||||||
value_t type = get_integer(result);
|
|
||||||
|
|
||||||
if (type == value_t::number_float)
|
|
||||||
{
|
{
|
||||||
// Parse with strtod
|
// Parse with strtod
|
||||||
typename string_t::value_type* endptr;
|
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
|
||||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
|
|
||||||
|
|
||||||
// Anything after the number is an error
|
|
||||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor && *m_cursor != '.')
|
|
||||||
throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the type
|
// Save the type
|
||||||
|
|||||||
@ -5974,12 +5974,12 @@ class basic_json
|
|||||||
// Remove '+' sign from the exponent if necessary
|
// Remove '+' sign from the exponent if necessary
|
||||||
if (!m_type.bits.exp_plus)
|
if (!m_type.bits.exp_plus)
|
||||||
{
|
{
|
||||||
if (static_cast<size_t>(len) > sizeof(buf)) len = sizeof(buf);
|
if (len > static_cast<int>(sizeof(buf))) len = sizeof(buf);
|
||||||
for (size_t i = 0; i < static_cast<size_t>(len); i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
if (buf[i] == '+')
|
if (buf[i] == '+')
|
||||||
{
|
{
|
||||||
for (; i + 1 < static_cast<size_t>(len); i++) buf[i] = buf[i + 1];
|
for (; i + 1 < len; i++) buf[i] = buf[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5992,14 +5992,16 @@ class basic_json
|
|||||||
}
|
}
|
||||||
else if (m_value.number_float == 0)
|
else if (m_value.number_float == 0)
|
||||||
{
|
{
|
||||||
// Special case for zero - use fixed precision to get "0.0"
|
// Special case for zero to get "0.0"/"-0.0"
|
||||||
snprintf(buf, sizeof(buf), "%#.1f", m_value.number_float);
|
if (std::signbit(m_value.number_float)) o << "-0.0";
|
||||||
|
else o << "0.0";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Otherwise 15 digits of precision allows round-trip IEEE 754
|
// Otherwise 6, 15 or 16 digits of precision allows round-trip IEEE 754
|
||||||
// string->double->string; to be safe, we read this value from
|
// string->float->string, string->double->string or string->long double->string;
|
||||||
// std::numeric_limits<number_float_t>::digits10
|
// to be safe, we read this value from std::numeric_limits<number_float_t>::digits10
|
||||||
snprintf(buf, sizeof(buf), "%.*g", std::numeric_limits<double>::digits10, m_value.number_float);
|
snprintf(buf, sizeof(buf), "%.*g", std::numeric_limits<double>::digits10, m_value.number_float);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7496,23 +7498,35 @@ class basic_json
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief attempt to parse an integer, otherwise get the floating point representation
|
@brief return number value for number tokens
|
||||||
|
|
||||||
This function parses the integer component up to the radix point or exponent.
|
This function translates the last token into the most appropriate number
|
||||||
It also collects information about the floating point representation, which
|
type (either integer, unsigned integer or floating point), which is
|
||||||
|
passed back to the caller via the result parameter.
|
||||||
|
|
||||||
|
This function parses the integer component up to the radix point or exponent
|
||||||
|
while collecting information about the 'floating point representation', which
|
||||||
it stores in the result parameter. If there is no radix point or exponent,
|
it stores in the result parameter. If there is no radix point or exponent,
|
||||||
and the number can fit into a @ref number_integer_t or @ref number_unsigned_t
|
and the number can fit into a @ref number_integer_t or @ref number_unsigned_t
|
||||||
then it sets the result parameter accordingly. The 'floating point
|
then it sets the result parameter accordingly.
|
||||||
representation' includes the number of significant figures after the radix
|
|
||||||
point, whether the number is in exponential or decimal form, the
|
The 'floating point representation' includes the number of significant figures
|
||||||
capitalization of the exponent marker, and if the optional '+' is present in
|
after the radix point, whether the number is in exponential or decimal form,
|
||||||
the exponent. This information is necessary to perform accurate round trips
|
the capitalization of the exponent marker, and if the optional '+' is present
|
||||||
|
in the exponent. This information is necessary to perform accurate round trips
|
||||||
of floating point numbers.
|
of floating point numbers.
|
||||||
|
|
||||||
@param[out] result @ref basic_json object to receive the result.
|
If the number is a floating point number the number is then parsed using
|
||||||
|
@a std:strtod (or @a std:strtof or @a std::strtold).
|
||||||
|
|
||||||
|
@param[out] result @ref basic_json object to receive the number, or NAN if the
|
||||||
|
conversion read past the current token. The latter case needs to be
|
||||||
|
treated by the caller function.
|
||||||
*/
|
*/
|
||||||
value_t get_integer(basic_json& result) const
|
void get_number(basic_json& result) const
|
||||||
{
|
{
|
||||||
|
assert(m_start != nullptr);
|
||||||
|
|
||||||
const lexer::lexer_char_t *curptr = m_start;
|
const lexer::lexer_char_t *curptr = m_start;
|
||||||
result.m_type.bits.parsed = true;
|
result.m_type.bits.parsed = true;
|
||||||
|
|
||||||
@ -7526,7 +7540,7 @@ class basic_json
|
|||||||
number_unsigned_t value = 0;
|
number_unsigned_t value = 0;
|
||||||
|
|
||||||
// Maximum absolute value of the relevant integer type
|
// Maximum absolute value of the relevant integer type
|
||||||
uint64_t max;
|
number_unsigned_t max;
|
||||||
|
|
||||||
// Temporarily store the type to avoid unecessary bitfield access
|
// Temporarily store the type to avoid unecessary bitfield access
|
||||||
value_t type;
|
value_t type;
|
||||||
@ -7599,49 +7613,18 @@ class basic_json
|
|||||||
result.m_type.bits.precision = precision & found_radix_point;
|
result.m_type.bits.precision = precision & found_radix_point;
|
||||||
|
|
||||||
// Save the value (if not a float)
|
// Save the value (if not a float)
|
||||||
if (type == value_t::number_unsigned) result.m_value.number_unsigned = value;
|
if (type == value_t::number_unsigned)
|
||||||
else if (type == value_t::number_integer) result.m_value.number_integer = -static_cast<number_integer_t>(value);
|
{
|
||||||
|
result.m_value.number_unsigned = value;
|
||||||
// Return the type (don't save it yet)
|
}
|
||||||
return type;
|
else if (type == value_t::number_integer)
|
||||||
}
|
{
|
||||||
|
result.m_value.number_integer = -static_cast<number_integer_t>(value);
|
||||||
/*!
|
}
|
||||||
@brief return number value for number tokens
|
else
|
||||||
|
|
||||||
This function translates the last token into the most appropriate number
|
|
||||||
type (either integer, unsigned integer or floating point), which is
|
|
||||||
passed back to the caller via the result parameter.
|
|
||||||
|
|
||||||
First @ref guess_type() is called to attempt to parse as an integer
|
|
||||||
and to retrieve information about the floating point representation
|
|
||||||
(if applicable) that can be used to accurately render the number to a
|
|
||||||
string later.
|
|
||||||
|
|
||||||
If the number is a floating point number the number is then parsed using
|
|
||||||
@a std:strtod (or @a std:strtof or @a std::strtold), which sets @a endptr
|
|
||||||
to the first character past the converted number. If it is not the same as
|
|
||||||
@ref m_cursor a bad input is assumed and @a result parameter is set to NAN.
|
|
||||||
|
|
||||||
@param[out] result @ref basic_json object to receive the number, or NAN if the
|
|
||||||
conversion read past the current token. The latter case needs to be
|
|
||||||
treated by the caller function.
|
|
||||||
*/
|
|
||||||
void get_number(basic_json& result) const
|
|
||||||
{
|
|
||||||
assert(m_start != nullptr);
|
|
||||||
|
|
||||||
value_t type = get_integer(result);
|
|
||||||
|
|
||||||
if (type == value_t::number_float)
|
|
||||||
{
|
{
|
||||||
// Parse with strtod
|
// Parse with strtod
|
||||||
typename string_t::value_type* endptr;
|
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
|
||||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
|
|
||||||
|
|
||||||
// Anything after the number is an error
|
|
||||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor && *m_cursor != '.')
|
|
||||||
throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the type
|
// Save the type
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user