Change parse to record float precision
This commit is contained in:
parent
0f28c69499
commit
f35f60c844
117
src/json.hpp
117
src/json.hpp
@ -694,7 +694,7 @@ class basic_json
|
|||||||
|
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
enum class value_t : uint8_t
|
enum class value_t : uint16_t
|
||||||
{
|
{
|
||||||
null, ///< null value
|
null, ///< null value
|
||||||
object, ///< object (unordered set of name/value pairs)
|
object, ///< object (unordered set of name/value pairs)
|
||||||
@ -704,7 +704,8 @@ class basic_json
|
|||||||
number_integer, ///< number value (integer)
|
number_integer, ///< number value (integer)
|
||||||
number_unsigned,///< number value (unsigned integer)
|
number_unsigned,///< number value (unsigned integer)
|
||||||
number_float, ///< number value (floating-point)
|
number_float, ///< number value (floating-point)
|
||||||
discarded ///< discarded by the the parser callback function
|
discarded, ///< discarded by the the parser callback function
|
||||||
|
precision_mask = 0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1746,7 +1747,7 @@ class basic_json
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if iterator range is complete for primitive values
|
// check if iterator range is complete for primitive values
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
@ -1767,7 +1768,7 @@ class basic_json
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::number_integer:
|
case value_t::number_integer:
|
||||||
{
|
{
|
||||||
@ -1851,7 +1852,7 @@ class basic_json
|
|||||||
basic_json(const basic_json& other)
|
basic_json(const basic_json& other)
|
||||||
: m_type(other.m_type)
|
: m_type(other.m_type)
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
@ -2081,7 +2082,7 @@ class basic_json
|
|||||||
*/
|
*/
|
||||||
value_t type() const noexcept
|
value_t type() const noexcept
|
||||||
{
|
{
|
||||||
return m_type;
|
return static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -2257,7 +2258,7 @@ class basic_json
|
|||||||
*/
|
*/
|
||||||
bool is_number_float() const noexcept
|
bool is_number_float() const noexcept
|
||||||
{
|
{
|
||||||
return m_type == value_t::number_float;
|
return (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask))) == value_t::number_float;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -2358,7 +2359,7 @@ class basic_json
|
|||||||
*/
|
*/
|
||||||
operator value_t() const noexcept
|
operator value_t() const noexcept
|
||||||
{
|
{
|
||||||
return m_type;
|
return (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
@ -2513,7 +2514,7 @@ class basic_json
|
|||||||
, int>::type = 0>
|
, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T*) const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::number_integer:
|
case value_t::number_integer:
|
||||||
{
|
{
|
||||||
@ -3645,7 +3646,7 @@ class basic_json
|
|||||||
|
|
||||||
InteratorType result = end();
|
InteratorType result = end();
|
||||||
|
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
@ -3751,7 +3752,7 @@ class basic_json
|
|||||||
|
|
||||||
InteratorType result = end();
|
InteratorType result = end();
|
||||||
|
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
@ -5762,7 +5763,7 @@ class basic_json
|
|||||||
// variable to hold indentation for recursive calls
|
// variable to hold indentation for recursive calls
|
||||||
unsigned int new_indent = current_indent;
|
unsigned int new_indent = current_indent;
|
||||||
|
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
@ -5873,22 +5874,24 @@ class basic_json
|
|||||||
|
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
{
|
{
|
||||||
// If the number is an integer then output as a fixed with with
|
// If the number was parsed from a string use the same precision
|
||||||
// precision 1 to output "0.0", "1.0" etc as expected for some
|
// otherwise 15 digits of precision allows round-trip IEEE 754
|
||||||
// round trip tests otherwise 15 digits of precision allows
|
// string->double->string; to be safe, we read this value from
|
||||||
// round-trip IEEE 754 string->double->string; to be safe, we
|
|
||||||
// read this value from
|
|
||||||
// std::numeric_limits<number_float_t>::digits10
|
// std::numeric_limits<number_float_t>::digits10
|
||||||
if (std::fmod(m_value.number_float, 1) == 0)
|
int precision = static_cast<int>(m_type) >> 8;
|
||||||
{
|
if (!precision) precision = std::numeric_limits<double>::digits10;
|
||||||
o << std::fixed << std::setprecision(1);
|
|
||||||
}
|
// Special case for zero - use fixed precision to get "0.0"
|
||||||
else
|
if (m_value.number_float == 0)
|
||||||
{
|
{
|
||||||
// std::defaultfloat not supported in gcc version < 5
|
o << std::fixed << std::setprecision(1);
|
||||||
o.unsetf(std::ios_base::floatfield);
|
}
|
||||||
o << std::setprecision(std::numeric_limits<double>::digits10);
|
else
|
||||||
}
|
{
|
||||||
|
// std::defaultfloat not supported in gcc version < 5
|
||||||
|
o.unsetf(std::ios_base::floatfield);
|
||||||
|
o << std::setprecision(precision);
|
||||||
|
}
|
||||||
o << m_value.number_float;
|
o << m_value.number_float;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -7755,39 +7758,73 @@ basic_json_parser_64:
|
|||||||
*/
|
*/
|
||||||
void get_number(basic_json& result) const
|
void get_number(basic_json& result) const
|
||||||
{
|
{
|
||||||
typename string_t::value_type* endptr;
|
|
||||||
assert(m_start != nullptr);
|
assert(m_start != nullptr);
|
||||||
|
|
||||||
|
// Count the significant figures
|
||||||
|
int precision = 0;
|
||||||
|
{
|
||||||
|
const lexer::lexer_char_t *curptr;
|
||||||
|
|
||||||
|
// Assume unsigned integer for now
|
||||||
|
result.m_type = value_t::number_unsigned;
|
||||||
|
for (curptr = m_start; curptr < m_cursor; curptr++) {
|
||||||
|
switch (*curptr) {
|
||||||
|
case '-':
|
||||||
|
// Found minus sign: change to integer
|
||||||
|
result.m_type = value_t::number_integer;
|
||||||
|
case '.':
|
||||||
|
// Don't count either '.' or '-'
|
||||||
|
continue;
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
// Found exponent: change to float and stop counting
|
||||||
|
result.m_type = value_t::number_float;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Found a signficant figure
|
||||||
|
precision++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Characters after number - shouldn't happen, but try parsing as float
|
||||||
|
if (curptr != m_cursor) result.m_type = value_t::number_float;
|
||||||
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
typename string_t::value_type* endptr = 0;
|
||||||
|
|
||||||
// Attempt to parse it as an integer - first checking for a negative number
|
// Attempt to parse it as an integer - first checking for a negative number
|
||||||
if (*reinterpret_cast<typename string_t::const_pointer>(m_start) != '-')
|
if (result.m_type == value_t::number_unsigned)
|
||||||
{
|
{
|
||||||
// Positive, parse with strtoull and attempt cast to number_unsigned_t
|
// Positive, parse with strtoull and attempt cast to number_unsigned_t
|
||||||
if (attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
if (!attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||||
result.m_type = value_t::number_unsigned;
|
result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
||||||
else result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
|
||||||
}
|
}
|
||||||
else
|
else if (result.m_type == value_t::number_integer)
|
||||||
{
|
{
|
||||||
// Negative, parse with strtoll and attempt cast to number_integer_t
|
// Negative, parse with strtoll and attempt cast to number_integer_t
|
||||||
if (attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
if (!attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||||
result.m_type = value_t::number_integer;
|
result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
||||||
else result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the end of the number was reached and no range error occurred
|
// Check the end of the number was reached and no range error occurred
|
||||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE) result.m_type = value_t::number_float;
|
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE) result.m_type = value_t::number_float;
|
||||||
|
|
||||||
if (result.m_type == value_t::number_float)
|
if (result.m_type == value_t::number_float)
|
||||||
{
|
{
|
||||||
// Either the number won't fit in an integer (range error from strtoull/strtoll or overflow on cast) or there was
|
// Either the number won't fit in an integer (range error from strtoull/strtoll or overflow on cast) or there was
|
||||||
// something else after the number, which could be an exponent
|
// something else after the number, which could be an exponent
|
||||||
|
|
||||||
// Parse with strtod
|
// Parse with strtod
|
||||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
|
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
|
||||||
|
|
||||||
|
// Add the precision bits
|
||||||
|
result.m_type = static_cast<value_t>(static_cast<int>(result.m_type) | (precision << 8));
|
||||||
|
|
||||||
// Anything after the number is an error
|
// Anything after the number is an error
|
||||||
if(reinterpret_cast<lexer_char_t*>(endptr) != m_cursor)
|
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");
|
throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -694,7 +694,7 @@ class basic_json
|
|||||||
|
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
enum class value_t : uint8_t
|
enum class value_t : uint16_t
|
||||||
{
|
{
|
||||||
null, ///< null value
|
null, ///< null value
|
||||||
object, ///< object (unordered set of name/value pairs)
|
object, ///< object (unordered set of name/value pairs)
|
||||||
@ -704,7 +704,8 @@ class basic_json
|
|||||||
number_integer, ///< number value (integer)
|
number_integer, ///< number value (integer)
|
||||||
number_unsigned,///< number value (unsigned integer)
|
number_unsigned,///< number value (unsigned integer)
|
||||||
number_float, ///< number value (floating-point)
|
number_float, ///< number value (floating-point)
|
||||||
discarded ///< discarded by the the parser callback function
|
discarded, ///< discarded by the the parser callback function
|
||||||
|
precision_mask = 0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1746,7 +1747,7 @@ class basic_json
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if iterator range is complete for primitive values
|
// check if iterator range is complete for primitive values
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
@ -1767,7 +1768,7 @@ class basic_json
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::number_integer:
|
case value_t::number_integer:
|
||||||
{
|
{
|
||||||
@ -1851,7 +1852,7 @@ class basic_json
|
|||||||
basic_json(const basic_json& other)
|
basic_json(const basic_json& other)
|
||||||
: m_type(other.m_type)
|
: m_type(other.m_type)
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
@ -2081,7 +2082,7 @@ class basic_json
|
|||||||
*/
|
*/
|
||||||
value_t type() const noexcept
|
value_t type() const noexcept
|
||||||
{
|
{
|
||||||
return m_type;
|
return static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -2257,7 +2258,7 @@ class basic_json
|
|||||||
*/
|
*/
|
||||||
bool is_number_float() const noexcept
|
bool is_number_float() const noexcept
|
||||||
{
|
{
|
||||||
return m_type == value_t::number_float;
|
return (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask))) == value_t::number_float;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -2358,7 +2359,7 @@ class basic_json
|
|||||||
*/
|
*/
|
||||||
operator value_t() const noexcept
|
operator value_t() const noexcept
|
||||||
{
|
{
|
||||||
return m_type;
|
return (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
@ -2513,7 +2514,7 @@ class basic_json
|
|||||||
, int>::type = 0>
|
, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T*) const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::number_integer:
|
case value_t::number_integer:
|
||||||
{
|
{
|
||||||
@ -3645,7 +3646,7 @@ class basic_json
|
|||||||
|
|
||||||
InteratorType result = end();
|
InteratorType result = end();
|
||||||
|
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
@ -3751,7 +3752,7 @@ class basic_json
|
|||||||
|
|
||||||
InteratorType result = end();
|
InteratorType result = end();
|
||||||
|
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
@ -5762,7 +5763,7 @@ class basic_json
|
|||||||
// variable to hold indentation for recursive calls
|
// variable to hold indentation for recursive calls
|
||||||
unsigned int new_indent = current_indent;
|
unsigned int new_indent = current_indent;
|
||||||
|
|
||||||
switch (m_type)
|
switch (static_cast<value_t>(static_cast<int>(m_type) & static_cast<int>(value_t::precision_mask)))
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
@ -5873,22 +5874,24 @@ class basic_json
|
|||||||
|
|
||||||
case value_t::number_float:
|
case value_t::number_float:
|
||||||
{
|
{
|
||||||
// If the number is an integer then output as a fixed with with
|
// If the number was parsed from a string use the same precision
|
||||||
// precision 1 to output "0.0", "1.0" etc as expected for some
|
// otherwise 15 digits of precision allows round-trip IEEE 754
|
||||||
// round trip tests otherwise 15 digits of precision allows
|
// string->double->string; to be safe, we read this value from
|
||||||
// round-trip IEEE 754 string->double->string; to be safe, we
|
|
||||||
// read this value from
|
|
||||||
// std::numeric_limits<number_float_t>::digits10
|
// std::numeric_limits<number_float_t>::digits10
|
||||||
if (std::fmod(m_value.number_float, 1) == 0)
|
int precision = static_cast<int>(m_type) >> 8;
|
||||||
{
|
if (!precision) precision = std::numeric_limits<double>::digits10;
|
||||||
o << std::fixed << std::setprecision(1);
|
|
||||||
}
|
// Special case for zero - use fixed precision to get "0.0"
|
||||||
else
|
if (m_value.number_float == 0)
|
||||||
{
|
{
|
||||||
// std::defaultfloat not supported in gcc version < 5
|
o << std::fixed << std::setprecision(1);
|
||||||
o.unsetf(std::ios_base::floatfield);
|
}
|
||||||
o << std::setprecision(std::numeric_limits<double>::digits10);
|
else
|
||||||
}
|
{
|
||||||
|
// std::defaultfloat not supported in gcc version < 5
|
||||||
|
o.unsetf(std::ios_base::floatfield);
|
||||||
|
o << std::setprecision(precision);
|
||||||
|
}
|
||||||
o << m_value.number_float;
|
o << m_value.number_float;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -7437,39 +7440,73 @@ class basic_json
|
|||||||
*/
|
*/
|
||||||
void get_number(basic_json& result) const
|
void get_number(basic_json& result) const
|
||||||
{
|
{
|
||||||
typename string_t::value_type* endptr;
|
|
||||||
assert(m_start != nullptr);
|
assert(m_start != nullptr);
|
||||||
|
|
||||||
|
// Count the significant figures
|
||||||
|
int precision = 0;
|
||||||
|
{
|
||||||
|
const lexer::lexer_char_t *curptr;
|
||||||
|
|
||||||
|
// Assume unsigned integer for now
|
||||||
|
result.m_type = value_t::number_unsigned;
|
||||||
|
for (curptr = m_start; curptr < m_cursor; curptr++) {
|
||||||
|
switch (*curptr) {
|
||||||
|
case '-':
|
||||||
|
// Found minus sign: change to integer
|
||||||
|
result.m_type = value_t::number_integer;
|
||||||
|
case '.':
|
||||||
|
// Don't count either '.' or '-'
|
||||||
|
continue;
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
// Found exponent: change to float and stop counting
|
||||||
|
result.m_type = value_t::number_float;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Found a signficant figure
|
||||||
|
precision++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Characters after number - shouldn't happen, but try parsing as float
|
||||||
|
if (curptr != m_cursor) result.m_type = value_t::number_float;
|
||||||
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
typename string_t::value_type* endptr = 0;
|
||||||
|
|
||||||
// Attempt to parse it as an integer - first checking for a negative number
|
// Attempt to parse it as an integer - first checking for a negative number
|
||||||
if (*reinterpret_cast<typename string_t::const_pointer>(m_start) != '-')
|
if (result.m_type == value_t::number_unsigned)
|
||||||
{
|
{
|
||||||
// Positive, parse with strtoull and attempt cast to number_unsigned_t
|
// Positive, parse with strtoull and attempt cast to number_unsigned_t
|
||||||
if (attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
if (!attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||||
result.m_type = value_t::number_unsigned;
|
result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
||||||
else result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
|
||||||
}
|
}
|
||||||
else
|
else if (result.m_type == value_t::number_integer)
|
||||||
{
|
{
|
||||||
// Negative, parse with strtoll and attempt cast to number_integer_t
|
// Negative, parse with strtoll and attempt cast to number_integer_t
|
||||||
if (attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
if (!attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||||
result.m_type = value_t::number_integer;
|
result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
||||||
else result.m_type = value_t::number_float; // Cast failed due to overflow - store as float
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the end of the number was reached and no range error occurred
|
// Check the end of the number was reached and no range error occurred
|
||||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE) result.m_type = value_t::number_float;
|
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE) result.m_type = value_t::number_float;
|
||||||
|
|
||||||
if (result.m_type == value_t::number_float)
|
if (result.m_type == value_t::number_float)
|
||||||
{
|
{
|
||||||
// Either the number won't fit in an integer (range error from strtoull/strtoll or overflow on cast) or there was
|
// Either the number won't fit in an integer (range error from strtoull/strtoll or overflow on cast) or there was
|
||||||
// something else after the number, which could be an exponent
|
// something else after the number, which could be an exponent
|
||||||
|
|
||||||
// Parse with strtod
|
// Parse with strtod
|
||||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
|
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
|
||||||
|
|
||||||
|
// Add the precision bits
|
||||||
|
result.m_type = static_cast<value_t>(static_cast<int>(result.m_type) | (precision << 8));
|
||||||
|
|
||||||
// Anything after the number is an error
|
// Anything after the number is an error
|
||||||
if(reinterpret_cast<lexer_char_t*>(endptr) != m_cursor)
|
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");
|
throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11762,10 +11762,10 @@ TEST_CASE("compliance tests from nativejson-benchmark")
|
|||||||
"test/json_roundtrip/roundtrip21.json",
|
"test/json_roundtrip/roundtrip21.json",
|
||||||
"test/json_roundtrip/roundtrip22.json",
|
"test/json_roundtrip/roundtrip22.json",
|
||||||
"test/json_roundtrip/roundtrip23.json",
|
"test/json_roundtrip/roundtrip23.json",
|
||||||
//"test/json_roundtrip/roundtrip24.json",
|
"test/json_roundtrip/roundtrip24.json",
|
||||||
//"test/json_roundtrip/roundtrip25.json",
|
"test/json_roundtrip/roundtrip25.json",
|
||||||
//"test/json_roundtrip/roundtrip26.json",
|
"test/json_roundtrip/roundtrip26.json",
|
||||||
//"test/json_roundtrip/roundtrip27.json"
|
"test/json_roundtrip/roundtrip27.json"
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
CAPTURE(filename);
|
CAPTURE(filename);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user