Commit ad5d1dab by Niels

Merge pull request #191 from twelsby/issue186

Fixed Issue #186 - add strto(f|d|ld) overload wrappers, "-0.0" special case and FP trailing zero
parents 9584a99a 81b70792
...@@ -5604,10 +5604,16 @@ class basic_json ...@@ -5604,10 +5604,16 @@ class basic_json
case value_t::number_float: case value_t::number_float:
{ {
// 15 digits of precision allows round-trip IEEE 754 // If the number is an integer then output as a fixed with with precision 1
// string->double->string; to be safe, we read this value from // to output "0.0", "1.0" etc as expected for some round trip tests otherwise
// std::numeric_limits<number_float_t>::digits10 // 15 digits of precision allows round-trip IEEE 754 string->double->string;
o << std::setprecision(std::numeric_limits<number_float_t>::digits10) << m_value.number_float; // to be safe, we read this value from std::numeric_limits<number_float_t>::digits10
if (std::fmod(m_value.number_float, 1) == 0) o << std::fixed << std::setprecision(1);
else {
o.unsetf(std::ios_base::floatfield); // std::defaultfloat not supported in gcc version < 5
o << std::setprecision(std::numeric_limits<double>::digits10);
}
o << m_value.number_float;
return; return;
} }
...@@ -6812,789 +6818,386 @@ class basic_json ...@@ -6812,789 +6818,386 @@ class basic_json
m_start = m_cursor; m_start = m_cursor;
assert(m_start != nullptr); assert(m_start != nullptr);
{ {
lexer_char_t yych; lexer_char_t yych;
unsigned int yyaccept = 0; unsigned int yyaccept = 0;
static const unsigned char yybm[] = static const unsigned char yybm[] = {
{ 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 0, 0, 32, 0, 0,
0, 32, 32, 0, 0, 32, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 96, 64, 0, 64, 64, 64, 64, 64,
96, 64, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 64, 64, 64, 64, 64, 64,
192, 192, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 64,
64, 64, 64, 64, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, };
}; if ((m_limit - m_cursor) < 5) yyfill(); // LCOV_EXCL_LINE;
if ((m_limit - m_cursor) < 5) yych = *m_cursor;
{ if (yych <= ':') {
yyfill(); // LCOV_EXCL_LINE; if (yych <= ' ') {
} if (yych <= '\n') {
yych = *m_cursor; if (yych <= 0x00) goto basic_json_parser_28;
if (yych <= ':') if (yych <= 0x08) goto basic_json_parser_30;
{ if (yych >= '\n') goto basic_json_parser_4;
if (yych <= ' ') } else {
{ if (yych == '\r') goto basic_json_parser_2;
if (yych <= '\n') if (yych <= 0x1F) goto basic_json_parser_30;
{ }
if (yych <= 0x00) } else {
{ if (yych <= ',') {
goto basic_json_parser_28; if (yych == '"') goto basic_json_parser_27;
} if (yych <= '+') goto basic_json_parser_30;
if (yych <= 0x08) goto basic_json_parser_16;
{ } else {
goto basic_json_parser_30; if (yych <= '/') {
} if (yych <= '-') goto basic_json_parser_23;
if (yych >= '\n') goto basic_json_parser_30;
{ } else {
goto basic_json_parser_4; if (yych <= '0') goto basic_json_parser_24;
} if (yych <= '9') goto basic_json_parser_26;
} goto basic_json_parser_18;
else
{
if (yych == '\r')
{
goto basic_json_parser_2;
}
if (yych <= 0x1F)
{
goto basic_json_parser_30;
}
}
}
else
{
if (yych <= ',')
{
if (yych == '"')
{
goto basic_json_parser_27;
}
if (yych <= '+')
{
goto basic_json_parser_30;
}
goto basic_json_parser_16;
}
else
{
if (yych <= '/')
{
if (yych <= '-')
{
goto basic_json_parser_23;
}
goto basic_json_parser_30;
}
else
{
if (yych <= '0')
{
goto basic_json_parser_24;
}
if (yych <= '9')
{
goto basic_json_parser_26;
}
goto basic_json_parser_18;
}
}
} }
} }
else }
{ } else {
if (yych <= 'n') if (yych <= 'n') {
{ if (yych <= ']') {
if (yych <= ']') if (yych == '[') goto basic_json_parser_8;
{ if (yych <= '\\') goto basic_json_parser_30;
if (yych == '[') goto basic_json_parser_10;
{ } else {
goto basic_json_parser_8; if (yych == 'f') goto basic_json_parser_22;
} if (yych <= 'm') goto basic_json_parser_30;
if (yych <= '\\') goto basic_json_parser_20;
{ }
goto basic_json_parser_30; } else {
} if (yych <= '{') {
goto basic_json_parser_10; if (yych == 't') goto basic_json_parser_21;
} if (yych <= 'z') goto basic_json_parser_30;
else goto basic_json_parser_12;
{ } else {
if (yych == 'f') if (yych <= '}') {
{ if (yych <= '|') goto basic_json_parser_30;
goto basic_json_parser_22; goto basic_json_parser_14;
} } else {
if (yych <= 'm') if (yych == 0xEF) goto basic_json_parser_6;
{ goto basic_json_parser_30;
goto basic_json_parser_30;
}
goto basic_json_parser_20;
}
}
else
{
if (yych <= '{')
{
if (yych == 't')
{
goto basic_json_parser_21;
}
if (yych <= 'z')
{
goto basic_json_parser_30;
}
goto basic_json_parser_12;
}
else
{
if (yych <= '}')
{
if (yych <= '|')
{
goto basic_json_parser_30;
}
goto basic_json_parser_14;
}
else
{
if (yych == 0xEF)
{
goto basic_json_parser_6;
}
goto basic_json_parser_30;
}
}
} }
} }
}
}
basic_json_parser_2: basic_json_parser_2:
++m_cursor; ++m_cursor;
yych = *m_cursor; yych = *m_cursor;
goto basic_json_parser_5; goto basic_json_parser_5;
basic_json_parser_3: basic_json_parser_3:
{ { return scan(); }
return scan();
}
basic_json_parser_4: basic_json_parser_4:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
basic_json_parser_5: basic_json_parser_5:
if (yybm[0 + yych] & 32) if (yybm[0+yych] & 32) {
{ goto basic_json_parser_4;
goto basic_json_parser_4; }
} goto basic_json_parser_3;
goto basic_json_parser_3;
basic_json_parser_6: basic_json_parser_6:
yyaccept = 0; yyaccept = 0;
yych = *(m_marker = ++m_cursor); yych = *(m_marker = ++m_cursor);
if (yych == 0xBB) if (yych == 0xBB) goto basic_json_parser_64;
{
goto basic_json_parser_64;
}
basic_json_parser_7: basic_json_parser_7:
{ { return token_type::parse_error; }
return token_type::parse_error;
}
basic_json_parser_8: basic_json_parser_8:
++m_cursor; ++m_cursor;
{ { return token_type::begin_array; }
return token_type::begin_array;
}
basic_json_parser_10: basic_json_parser_10:
++m_cursor; ++m_cursor;
{ { return token_type::end_array; }
return token_type::end_array;
}
basic_json_parser_12: basic_json_parser_12:
++m_cursor; ++m_cursor;
{ { return token_type::begin_object; }
return token_type::begin_object;
}
basic_json_parser_14: basic_json_parser_14:
++m_cursor; ++m_cursor;
{ { return token_type::end_object; }
return token_type::end_object;
}
basic_json_parser_16: basic_json_parser_16:
++m_cursor; ++m_cursor;
{ { return token_type::value_separator; }
return token_type::value_separator;
}
basic_json_parser_18: basic_json_parser_18:
++m_cursor; ++m_cursor;
{ { return token_type::name_separator; }
return token_type::name_separator;
}
basic_json_parser_20: basic_json_parser_20:
yyaccept = 0; yyaccept = 0;
yych = *(m_marker = ++m_cursor); yych = *(m_marker = ++m_cursor);
if (yych == 'u') if (yych == 'u') goto basic_json_parser_60;
{ goto basic_json_parser_7;
goto basic_json_parser_60;
}
goto basic_json_parser_7;
basic_json_parser_21: basic_json_parser_21:
yyaccept = 0; yyaccept = 0;
yych = *(m_marker = ++m_cursor); yych = *(m_marker = ++m_cursor);
if (yych == 'r') if (yych == 'r') goto basic_json_parser_56;
{ goto basic_json_parser_7;
goto basic_json_parser_56;
}
goto basic_json_parser_7;
basic_json_parser_22: basic_json_parser_22:
yyaccept = 0; yyaccept = 0;
yych = *(m_marker = ++m_cursor); yych = *(m_marker = ++m_cursor);
if (yych == 'a') if (yych == 'a') goto basic_json_parser_51;
{ goto basic_json_parser_7;
goto basic_json_parser_51;
}
goto basic_json_parser_7;
basic_json_parser_23: basic_json_parser_23:
yych = *++m_cursor; yych = *++m_cursor;
if (yych <= '/') if (yych <= '/') goto basic_json_parser_7;
{ if (yych <= '0') goto basic_json_parser_50;
goto basic_json_parser_7; if (yych <= '9') goto basic_json_parser_41;
} goto basic_json_parser_7;
if (yych <= '0')
{
goto basic_json_parser_50;
}
if (yych <= '9')
{
goto basic_json_parser_41;
}
goto basic_json_parser_7;
basic_json_parser_24: basic_json_parser_24:
yyaccept = 1; yyaccept = 1;
yych = *(m_marker = ++m_cursor); yych = *(m_marker = ++m_cursor);
if (yych <= 'D') if (yych <= 'D') {
{ if (yych == '.') goto basic_json_parser_43;
if (yych == '.') } else {
{ if (yych <= 'E') goto basic_json_parser_44;
goto basic_json_parser_43; if (yych == 'e') goto basic_json_parser_44;
} }
}
else
{
if (yych <= 'E')
{
goto basic_json_parser_44;
}
if (yych == 'e')
{
goto basic_json_parser_44;
}
}
basic_json_parser_25: basic_json_parser_25:
{ { return token_type::value_number; }
return token_type::value_number;
}
basic_json_parser_26: basic_json_parser_26:
yyaccept = 1; yyaccept = 1;
yych = *(m_marker = ++m_cursor); yych = *(m_marker = ++m_cursor);
goto basic_json_parser_42; goto basic_json_parser_42;
basic_json_parser_27: basic_json_parser_27:
yyaccept = 0; yyaccept = 0;
yych = *(m_marker = ++m_cursor); yych = *(m_marker = ++m_cursor);
if (yych <= 0x0F) if (yych <= 0x0F) goto basic_json_parser_7;
{ goto basic_json_parser_32;
goto basic_json_parser_7;
}
goto basic_json_parser_32;
basic_json_parser_28: basic_json_parser_28:
++m_cursor; ++m_cursor;
{ { return token_type::end_of_input; }
return token_type::end_of_input;
}
basic_json_parser_30: basic_json_parser_30:
yych = *++m_cursor; yych = *++m_cursor;
goto basic_json_parser_7; goto basic_json_parser_7;
basic_json_parser_31: basic_json_parser_31:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
basic_json_parser_32: basic_json_parser_32:
if (yybm[0 + yych] & 64) if (yybm[0+yych] & 64) {
{ goto basic_json_parser_31;
goto basic_json_parser_31; }
} if (yych <= 0x0F) goto basic_json_parser_33;
if (yych <= 0x0F) if (yych <= '"') goto basic_json_parser_35;
{ goto basic_json_parser_34;
goto basic_json_parser_33;
}
if (yych <= '"')
{
goto basic_json_parser_35;
}
goto basic_json_parser_34;
basic_json_parser_33: basic_json_parser_33:
m_cursor = m_marker; m_cursor = m_marker;
if (yyaccept == 0) if (yyaccept == 0) {
{ goto basic_json_parser_7;
goto basic_json_parser_7; } else {
} goto basic_json_parser_25;
else }
{
goto basic_json_parser_25;
}
basic_json_parser_34: basic_json_parser_34:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE; if (yych <= 'e') {
} if (yych <= '/') {
yych = *m_cursor; if (yych == '"') goto basic_json_parser_31;
if (yych <= 'e') if (yych <= '.') goto basic_json_parser_33;
{ goto basic_json_parser_31;
if (yych <= '/') } else {
{ if (yych <= '\\') {
if (yych == '"') if (yych <= '[') goto basic_json_parser_33;
{ goto basic_json_parser_31;
goto basic_json_parser_31; } else {
} if (yych == 'b') goto basic_json_parser_31;
if (yych <= '.') goto basic_json_parser_33;
{
goto basic_json_parser_33;
}
goto basic_json_parser_31;
}
else
{
if (yych <= '\\')
{
if (yych <= '[')
{
goto basic_json_parser_33;
}
goto basic_json_parser_31;
}
else
{
if (yych == 'b')
{
goto basic_json_parser_31;
}
goto basic_json_parser_33;
}
}
} }
else }
{ } else {
if (yych <= 'q') if (yych <= 'q') {
{ if (yych <= 'f') goto basic_json_parser_31;
if (yych <= 'f') if (yych == 'n') goto basic_json_parser_31;
{ goto basic_json_parser_33;
goto basic_json_parser_31; } else {
} if (yych <= 's') {
if (yych == 'n') if (yych <= 'r') goto basic_json_parser_31;
{ goto basic_json_parser_33;
goto basic_json_parser_31; } else {
} if (yych <= 't') goto basic_json_parser_31;
goto basic_json_parser_33; if (yych <= 'u') goto basic_json_parser_37;
} goto basic_json_parser_33;
else
{
if (yych <= 's')
{
if (yych <= 'r')
{
goto basic_json_parser_31;
}
goto basic_json_parser_33;
}
else
{
if (yych <= 't')
{
goto basic_json_parser_31;
}
if (yych <= 'u')
{
goto basic_json_parser_37;
}
goto basic_json_parser_33;
}
}
} }
}
}
basic_json_parser_35: basic_json_parser_35:
++m_cursor; ++m_cursor;
{ { return token_type::value_string; }
return token_type::value_string;
}
basic_json_parser_37: basic_json_parser_37:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE; if (yych <= '@') {
} if (yych <= '/') goto basic_json_parser_33;
yych = *m_cursor; if (yych >= ':') goto basic_json_parser_33;
if (yych <= '@') } else {
{ if (yych <= 'F') goto basic_json_parser_38;
if (yych <= '/') if (yych <= '`') goto basic_json_parser_33;
{ if (yych >= 'g') goto basic_json_parser_33;
goto basic_json_parser_33; }
}
if (yych >= ':')
{
goto basic_json_parser_33;
}
}
else
{
if (yych <= 'F')
{
goto basic_json_parser_38;
}
if (yych <= '`')
{
goto basic_json_parser_33;
}
if (yych >= 'g')
{
goto basic_json_parser_33;
}
}
basic_json_parser_38: basic_json_parser_38:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE; if (yych <= '@') {
} if (yych <= '/') goto basic_json_parser_33;
yych = *m_cursor; if (yych >= ':') goto basic_json_parser_33;
if (yych <= '@') } else {
{ if (yych <= 'F') goto basic_json_parser_39;
if (yych <= '/') if (yych <= '`') goto basic_json_parser_33;
{ if (yych >= 'g') goto basic_json_parser_33;
goto basic_json_parser_33; }
}
if (yych >= ':')
{
goto basic_json_parser_33;
}
}
else
{
if (yych <= 'F')
{
goto basic_json_parser_39;
}
if (yych <= '`')
{
goto basic_json_parser_33;
}
if (yych >= 'g')
{
goto basic_json_parser_33;
}
}
basic_json_parser_39: basic_json_parser_39:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE; if (yych <= '@') {
} if (yych <= '/') goto basic_json_parser_33;
yych = *m_cursor; if (yych >= ':') goto basic_json_parser_33;
if (yych <= '@') } else {
{ if (yych <= 'F') goto basic_json_parser_40;
if (yych <= '/') if (yych <= '`') goto basic_json_parser_33;
{ if (yych >= 'g') goto basic_json_parser_33;
goto basic_json_parser_33; }
}
if (yych >= ':')
{
goto basic_json_parser_33;
}
}
else
{
if (yych <= 'F')
{
goto basic_json_parser_40;
}
if (yych <= '`')
{
goto basic_json_parser_33;
}
if (yych >= 'g')
{
goto basic_json_parser_33;
}
}
basic_json_parser_40: basic_json_parser_40:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE; if (yych <= '@') {
} if (yych <= '/') goto basic_json_parser_33;
yych = *m_cursor; if (yych <= '9') goto basic_json_parser_31;
if (yych <= '@') goto basic_json_parser_33;
{ } else {
if (yych <= '/') if (yych <= 'F') goto basic_json_parser_31;
{ if (yych <= '`') goto basic_json_parser_33;
goto basic_json_parser_33; if (yych <= 'f') goto basic_json_parser_31;
} goto basic_json_parser_33;
if (yych <= '9') }
{
goto basic_json_parser_31;
}
goto basic_json_parser_33;
}
else
{
if (yych <= 'F')
{
goto basic_json_parser_31;
}
if (yych <= '`')
{
goto basic_json_parser_33;
}
if (yych <= 'f')
{
goto basic_json_parser_31;
}
goto basic_json_parser_33;
}
basic_json_parser_41: basic_json_parser_41:
yyaccept = 1; yyaccept = 1;
m_marker = ++m_cursor; m_marker = ++m_cursor;
if ((m_limit - m_cursor) < 3) if ((m_limit - m_cursor) < 3) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
basic_json_parser_42: basic_json_parser_42:
if (yybm[0 + yych] & 128) if (yybm[0+yych] & 128) {
{ goto basic_json_parser_41;
goto basic_json_parser_41; }
} if (yych <= 'D') {
if (yych <= 'D') if (yych != '.') goto basic_json_parser_25;
{ } else {
if (yych != '.') if (yych <= 'E') goto basic_json_parser_44;
{ if (yych == 'e') goto basic_json_parser_44;
goto basic_json_parser_25; goto basic_json_parser_25;
} }
}
else
{
if (yych <= 'E')
{
goto basic_json_parser_44;
}
if (yych == 'e')
{
goto basic_json_parser_44;
}
goto basic_json_parser_25;
}
basic_json_parser_43: basic_json_parser_43:
yych = *++m_cursor; yych = *++m_cursor;
if (yych <= '/') if (yych <= '/') goto basic_json_parser_33;
{ if (yych <= '9') goto basic_json_parser_48;
goto basic_json_parser_33; goto basic_json_parser_33;
}
if (yych <= '9')
{
goto basic_json_parser_48;
}
goto basic_json_parser_33;
basic_json_parser_44: basic_json_parser_44:
yych = *++m_cursor; yych = *++m_cursor;
if (yych <= ',') if (yych <= ',') {
{ if (yych != '+') goto basic_json_parser_33;
if (yych != '+') } else {
{ if (yych <= '-') goto basic_json_parser_45;
goto basic_json_parser_33; if (yych <= '/') goto basic_json_parser_33;
} if (yych <= '9') goto basic_json_parser_46;
} goto basic_json_parser_33;
else }
{
if (yych <= '-')
{
goto basic_json_parser_45;
}
if (yych <= '/')
{
goto basic_json_parser_33;
}
if (yych <= '9')
{
goto basic_json_parser_46;
}
goto basic_json_parser_33;
}
basic_json_parser_45: basic_json_parser_45:
yych = *++m_cursor; yych = *++m_cursor;
if (yych <= '/') if (yych <= '/') goto basic_json_parser_33;
{ if (yych >= ':') goto basic_json_parser_33;
goto basic_json_parser_33;
}
if (yych >= ':')
{
goto basic_json_parser_33;
}
basic_json_parser_46: basic_json_parser_46:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE; if (yych <= '/') goto basic_json_parser_25;
} if (yych <= '9') goto basic_json_parser_46;
yych = *m_cursor; goto basic_json_parser_25;
if (yych <= '/')
{
goto basic_json_parser_25;
}
if (yych <= '9')
{
goto basic_json_parser_46;
}
goto basic_json_parser_25;
basic_json_parser_48: basic_json_parser_48:
yyaccept = 1; yyaccept = 1;
m_marker = ++m_cursor; m_marker = ++m_cursor;
if ((m_limit - m_cursor) < 3) if ((m_limit - m_cursor) < 3) yyfill(); // LCOV_EXCL_LINE;
{ yych = *m_cursor;
yyfill(); // LCOV_EXCL_LINE; if (yych <= 'D') {
} if (yych <= '/') goto basic_json_parser_25;
yych = *m_cursor; if (yych <= '9') goto basic_json_parser_48;
if (yych <= 'D') goto basic_json_parser_25;
{ } else {
if (yych <= '/') if (yych <= 'E') goto basic_json_parser_44;
{ if (yych == 'e') goto basic_json_parser_44;
goto basic_json_parser_25; goto basic_json_parser_25;
} }
if (yych <= '9')
{
goto basic_json_parser_48;
}
goto basic_json_parser_25;
}
else
{
if (yych <= 'E')
{
goto basic_json_parser_44;
}
if (yych == 'e')
{
goto basic_json_parser_44;
}
goto basic_json_parser_25;
}
basic_json_parser_50: basic_json_parser_50:
yyaccept = 1; yyaccept = 1;
yych = *(m_marker = ++m_cursor); yych = *(m_marker = ++m_cursor);
if (yych <= 'D') if (yych <= 'D') {
{ if (yych == '.') goto basic_json_parser_43;
if (yych == '.') goto basic_json_parser_25;
{ } else {
goto basic_json_parser_43; if (yych <= 'E') goto basic_json_parser_44;
} if (yych == 'e') goto basic_json_parser_44;
goto basic_json_parser_25; goto basic_json_parser_25;
} }
else
{
if (yych <= 'E')
{
goto basic_json_parser_44;
}
if (yych == 'e')
{
goto basic_json_parser_44;
}
goto basic_json_parser_25;
}
basic_json_parser_51: basic_json_parser_51:
yych = *++m_cursor; yych = *++m_cursor;
if (yych != 'l') if (yych != 'l') goto basic_json_parser_33;
{ yych = *++m_cursor;
goto basic_json_parser_33; if (yych != 's') goto basic_json_parser_33;
} yych = *++m_cursor;
yych = *++m_cursor; if (yych != 'e') goto basic_json_parser_33;
if (yych != 's') ++m_cursor;
{ { return token_type::literal_false; }
goto basic_json_parser_33;
}
yych = *++m_cursor;
if (yych != 'e')
{
goto basic_json_parser_33;
}
++m_cursor;
{
return token_type::literal_false;
}
basic_json_parser_56: basic_json_parser_56:
yych = *++m_cursor; yych = *++m_cursor;
if (yych != 'u') if (yych != 'u') goto basic_json_parser_33;
{ yych = *++m_cursor;
goto basic_json_parser_33; if (yych != 'e') goto basic_json_parser_33;
} ++m_cursor;
yych = *++m_cursor; { return token_type::literal_true; }
if (yych != 'e')
{
goto basic_json_parser_33;
}
++m_cursor;
{
return token_type::literal_true;
}
basic_json_parser_60: basic_json_parser_60:
yych = *++m_cursor; yych = *++m_cursor;
if (yych != 'l') if (yych != 'l') goto basic_json_parser_33;
{ yych = *++m_cursor;
goto basic_json_parser_33; if (yych != 'l') goto basic_json_parser_33;
} ++m_cursor;
yych = *++m_cursor; { return token_type::literal_null; }
if (yych != 'l')
{
goto basic_json_parser_33;
}
++m_cursor;
{
return token_type::literal_null;
}
basic_json_parser_64: basic_json_parser_64:
yych = *++m_cursor; yych = *++m_cursor;
if (yych != 0xBF) if (yych != 0xBF) goto basic_json_parser_33;
{ ++m_cursor;
goto basic_json_parser_33; { return scan(); }
} }
++m_cursor;
{
return scan();
}
}
} }
...@@ -7758,6 +7361,63 @@ basic_json_parser_64: ...@@ -7758,6 +7361,63 @@ basic_json_parser_64:
} }
/*! /*!
@brief parse floating point number
This function (and its overloads) serves to select the most approprate
standard floating point number parsing function based on the type
supplied via the first parameter. Set this to
@a static_cast<number_float_t>(nullptr).
@param type the @ref number_float_t in use
@param endptr recieves a pointer to the first character after the number
@return the floating point number
*/
long double str_to_float_t(long double* /* type */, char** endptr) const
{
return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
/*!
@brief parse floating point number
This function (and its overloads) serves to select the most approprate
standard floating point number parsing function based on the type
supplied via the first parameter. Set this to
@a static_cast<number_float_t>(nullptr).
@param type the @ref number_float_t in use
@param endptr recieves a pointer to the first character after the number
@return the floating point number
*/
double str_to_float_t(double* /* type */, char** endptr) const
{
return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
/*!
@brief parse floating point number
This function (and its overloads) serves to select the most approprate
standard floating point number parsing function based on the type
supplied via the first parameter. Set this to
@a static_cast<number_float_t>(nullptr).
@param type the @ref number_float_t in use
@param endptr recieves a pointer to the first character after the number
@return the floating point number
*/
float str_to_float_t(float* /* type */, char** endptr) const
{
return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
/*!
@brief return number value for number tokens @brief return number value for number tokens
This function translates the last token into a floating point number. This function translates the last token into a floating point number.
...@@ -7774,13 +7434,12 @@ basic_json_parser_64: ...@@ -7774,13 +7434,12 @@ basic_json_parser_64:
@throw std::range_error if passed value is out of range @throw std::range_error if passed value is out of range
*/ */
long double get_number() const number_float_t get_number() const
{ {
// conversion // conversion
typename string_t::value_type* endptr; typename string_t::value_type* endptr;
assert(m_start != nullptr); assert(m_start != nullptr);
const auto float_val = std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), number_float_t float_val = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
&endptr);
// return float_val if the whole number was translated and NAN // return float_val if the whole number was translated and NAN
// otherwise // otherwise
...@@ -8014,11 +7673,11 @@ basic_json_parser_64: ...@@ -8014,11 +7673,11 @@ basic_json_parser_64:
case lexer::token_type::value_number: case lexer::token_type::value_number:
{ {
auto float_val = m_lexer.get_number(); result.m_value = m_lexer.get_number();
// NAN is returned if token could not be translated // NAN is returned if token could not be translated
// completely // completely
if (std::isnan(float_val)) if (std::isnan(result.m_value.number_float))
{ {
throw std::invalid_argument(std::string("parse error - ") + throw std::invalid_argument(std::string("parse error - ") +
m_lexer.get_token() + " is not a number"); m_lexer.get_token() + " is not a number");
...@@ -8026,9 +7685,10 @@ basic_json_parser_64: ...@@ -8026,9 +7685,10 @@ basic_json_parser_64:
get_token(); get_token();
// check if conversion loses precision // check if conversion loses precision (special case -0.0 always loses precision)
const auto int_val = static_cast<number_integer_t>(float_val); const auto int_val = static_cast<number_integer_t>(result.m_value.number_float);
if (float_val == static_cast<long double>(int_val)) if (result.m_value.number_float == static_cast<number_float_t>(int_val) &&
result.m_value.number_integer != json_value(-0.0f).number_integer)
{ {
// we would not lose precision -> return int // we would not lose precision -> return int
result.m_type = value_t::number_integer; result.m_type = value_t::number_integer;
...@@ -8038,7 +7698,6 @@ basic_json_parser_64: ...@@ -8038,7 +7698,6 @@ basic_json_parser_64:
{ {
// we would lose precision -> return float // we would lose precision -> return float
result.m_type = value_t::number_float; result.m_type = value_t::number_float;
result.m_value = static_cast<number_float_t>(float_val);
} }
break; break;
} }
......
...@@ -5604,10 +5604,16 @@ class basic_json ...@@ -5604,10 +5604,16 @@ class basic_json
case value_t::number_float: case value_t::number_float:
{ {
// 15 digits of precision allows round-trip IEEE 754 // If the number is an integer then output as a fixed with with precision 1
// string->double->string; to be safe, we read this value from // to output "0.0", "1.0" etc as expected for some round trip tests otherwise
// std::numeric_limits<number_float_t>::digits10 // 15 digits of precision allows round-trip IEEE 754 string->double->string;
o << std::setprecision(std::numeric_limits<number_float_t>::digits10) << m_value.number_float; // to be safe, we read this value from std::numeric_limits<number_float_t>::digits10
if (std::fmod(m_value.number_float, 1) == 0) o << std::fixed << std::setprecision(1);
else {
o.unsetf(std::ios_base::floatfield); // std::defaultfloat not supported in gcc version < 5
o << std::setprecision(std::numeric_limits<double>::digits10);
}
o << m_value.number_float;
return; return;
} }
...@@ -7037,6 +7043,63 @@ class basic_json ...@@ -7037,6 +7043,63 @@ class basic_json
} }
/*! /*!
@brief parse floating point number
This function (and its overloads) serves to select the most approprate
standard floating point number parsing function based on the type
supplied via the first parameter. Set this to
@a static_cast<number_float_t>(nullptr).
@param type the @ref number_float_t in use
@param endptr recieves a pointer to the first character after the number
@return the floating point number
*/
long double str_to_float_t(long double* /* type */, char** endptr) const
{
return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
/*!
@brief parse floating point number
This function (and its overloads) serves to select the most approprate
standard floating point number parsing function based on the type
supplied via the first parameter. Set this to
@a static_cast<number_float_t>(nullptr).
@param type the @ref number_float_t in use
@param endptr recieves a pointer to the first character after the number
@return the floating point number
*/
double str_to_float_t(double* /* type */, char** endptr) const
{
return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
/*!
@brief parse floating point number
This function (and its overloads) serves to select the most approprate
standard floating point number parsing function based on the type
supplied via the first parameter. Set this to
@a static_cast<number_float_t>(nullptr).
@param type the @ref number_float_t in use
@param endptr recieves a pointer to the first character after the number
@return the floating point number
*/
float str_to_float_t(float* /* type */, char** endptr) const
{
return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
/*!
@brief return number value for number tokens @brief return number value for number tokens
This function translates the last token into a floating point number. This function translates the last token into a floating point number.
...@@ -7053,13 +7116,12 @@ class basic_json ...@@ -7053,13 +7116,12 @@ class basic_json
@throw std::range_error if passed value is out of range @throw std::range_error if passed value is out of range
*/ */
long double get_number() const number_float_t get_number() const
{ {
// conversion // conversion
typename string_t::value_type* endptr; typename string_t::value_type* endptr;
assert(m_start != nullptr); assert(m_start != nullptr);
const auto float_val = std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), number_float_t float_val = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
&endptr);
// return float_val if the whole number was translated and NAN // return float_val if the whole number was translated and NAN
// otherwise // otherwise
...@@ -7293,11 +7355,11 @@ class basic_json ...@@ -7293,11 +7355,11 @@ class basic_json
case lexer::token_type::value_number: case lexer::token_type::value_number:
{ {
auto float_val = m_lexer.get_number(); result.m_value = m_lexer.get_number();
// NAN is returned if token could not be translated // NAN is returned if token could not be translated
// completely // completely
if (std::isnan(float_val)) if (std::isnan(result.m_value.number_float))
{ {
throw std::invalid_argument(std::string("parse error - ") + throw std::invalid_argument(std::string("parse error - ") +
m_lexer.get_token() + " is not a number"); m_lexer.get_token() + " is not a number");
...@@ -7305,9 +7367,10 @@ class basic_json ...@@ -7305,9 +7367,10 @@ class basic_json
get_token(); get_token();
// check if conversion loses precision // check if conversion loses precision (special case -0.0 always loses precision)
const auto int_val = static_cast<number_integer_t>(float_val); const auto int_val = static_cast<number_integer_t>(result.m_value.number_float);
if (float_val == static_cast<long double>(int_val)) if (result.m_value.number_float == static_cast<number_float_t>(int_val) &&
result.m_value.number_integer != json_value(-0.0f).number_integer)
{ {
// we would not lose precision -> return int // we would not lose precision -> return int
result.m_type = value_t::number_integer; result.m_type = value_t::number_integer;
...@@ -7317,7 +7380,6 @@ class basic_json ...@@ -7317,7 +7380,6 @@ class basic_json
{ {
// we would lose precision -> return float // we would lose precision -> return float
result.m_type = value_t::number_float; result.m_type = value_t::number_float;
result.m_value = static_cast<number_float_t>(float_val);
} }
break; break;
} }
......
...@@ -11090,7 +11090,7 @@ TEST_CASE("compliance tests from nativejson-benchmark") ...@@ -11090,7 +11090,7 @@ TEST_CASE("compliance tests from nativejson-benchmark")
//"test/json_roundtrip/roundtrip18.json", //"test/json_roundtrip/roundtrip18.json",
//"test/json_roundtrip/roundtrip19.json", //"test/json_roundtrip/roundtrip19.json",
//"test/json_roundtrip/roundtrip20.json", //"test/json_roundtrip/roundtrip20.json",
//"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",
...@@ -11407,7 +11407,8 @@ TEST_CASE("regression tests") ...@@ -11407,7 +11407,8 @@ TEST_CASE("regression tests")
SECTION("issue #89 - nonstandard integer type") SECTION("issue #89 - nonstandard integer type")
{ {
// create JSON class with nonstandard integer number type // create JSON class with nonstandard integer number type
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, float> j; using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, float>;
custom_json j;
j["int_1"] = 1; j["int_1"] = 1;
// we need to cast to int to compile with Catch - the value is int32_t // we need to cast to int to compile with Catch - the value is int32_t
CHECK(static_cast<int>(j["int_1"]) == 1); CHECK(static_cast<int>(j["int_1"]) == 1);
...@@ -11557,4 +11558,51 @@ TEST_CASE("regression tests") ...@@ -11557,4 +11558,51 @@ TEST_CASE("regression tests")
// Const access with key as "static constexpr const char *" // Const access with key as "static constexpr const char *"
CHECK(j_const[constexpr_ptr_key] == json(5)); CHECK(j_const[constexpr_ptr_key] == json(5));
} }
SECTION("issue #186 miloyip/nativejson-benchmark: floating-point parsing")
{
json j;
j = json::parse("-0.0");
CHECK(j.get<double>() == -0.0);
j = json::parse("2.22507385850720113605740979670913197593481954635164564e-308");
CHECK(j.get<double>() == 2.2250738585072009e-308);
j = json::parse("0.999999999999999944488848768742172978818416595458984374");
CHECK(j.get<double>() == 0.99999999999999989);
// Test fails under GCC/clang due to strtod() error (may originate in libstdc++
// but seems to have been fixed in the most current versions - just not on Travis)
#if !defined(__clang__) && !defined(__GNUC__) && !defined(__GNUG__)
j = json::parse("1.00000000000000011102230246251565404236316680908203126");
CHECK(j.get<double>() == 1.00000000000000022);
#endif
j = json::parse("7205759403792793199999e-5");
CHECK(j.get<double>() == 72057594037927928.0);
j = json::parse("922337203685477529599999e-5");
CHECK(j.get<double>() == 9223372036854774784.0);
j = json::parse("1014120480182583464902367222169599999e-5");
CHECK(j.get<double>() == 10141204801825834086073718800384.0);
j = json::parse("5708990770823839207320493820740630171355185151999e-3");
CHECK(j.get<double>() == 5708990770823838890407843763683279797179383808.0);
// create JSON class with nonstandard float number type
// float
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, float> j_float = 1.23e25f;
CHECK(j_float.get<float>() == 1.23e25f);
// double
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, double> j_double = 1.23e45;
CHECK(j_double.get<double>() == 1.23e45);
// long double
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, long double> j_long_double = 1.23e45L;
CHECK(j_long_double.get<long double>() == 1.23e45L);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment