mirror of
https://github.com/nlohmann/json.git
synced 2026-10-22 05:58:12 +00:00
Address the review of json_view dump() and comparisons
From gregmarr's review of #5624: - The output buffer takes string literals without a length. - write_float() names the IEEE single/double condition once, as the library's serializer does. - equal() checks the types first and compares with !=; the reference to the top frame is noted as dangling after pop_back(). - dump.md: one paragraph per case in the notes. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
3 files changed
+38
-24
No files matched your search
@@ -60,11 +60,13 @@ Linear in the size of the output text.
|
|||||||
The walk over the subtree is iterative, so the nesting depth it can write is limited by available memory only, not by
|
The walk over the subtree is iterative, so the nesting depth it can write is limited by available memory only, not by
|
||||||
the call stack -- as for [`materialize()`](materialize.md).
|
the call stack -- as for [`materialize()`](materialize.md).
|
||||||
|
|
||||||
Strings are escaped by the same rules as [`BasicJsonType::dump`](../basic_json/dump.md). With
|
Strings are escaped by the same rules as [`BasicJsonType::dump`](../basic_json/dump.md).
|
||||||
`#!cpp numbers == number_format::shortest`, floats are written with the library's shortest round-trip conversion,
|
|
||||||
|
With `#!cpp numbers == number_format::shortest`, floats are written with the library's shortest round-trip conversion,
|
||||||
exactly as [`BasicJsonType::dump`](../basic_json/dump.md) would (e.g. `#!cpp 1.5`, `#!cpp 100.0`, `#!cpp 1e+100`), and
|
exactly as [`BasicJsonType::dump`](../basic_json/dump.md) would (e.g. `#!cpp 1.5`, `#!cpp 100.0`, `#!cpp 1e+100`), and
|
||||||
integers are copied from the source text -- already canonical in JSON, so this matches their shortest form too --
|
integers are copied from the source text -- already canonical in JSON, so this matches their shortest form too --
|
||||||
except that `#!cpp -0` is written as `#!cpp 0`, the way [`BasicJsonType::parse()`](../basic_json/parse.md) reads it.
|
except that `#!cpp -0` is written as `#!cpp 0`, the way [`BasicJsonType::parse()`](../basic_json/parse.md) reads it.
|
||||||
|
|
||||||
`#!cpp number_format::source` copies every number exactly as written in the source text instead, with no exception
|
`#!cpp number_format::source` copies every number exactly as written in the source text instead, with no exception
|
||||||
for `#!cpp -0` -- `#!cpp 1.50`, `#!cpp 1E2`, `#!cpp -0.0`, `#!cpp -0`, or all digits of an integer literal with more
|
for `#!cpp -0` -- `#!cpp 1.50`, `#!cpp 1E2`, `#!cpp -0.0`, `#!cpp -0`, or all digits of an integer literal with more
|
||||||
digits than any number type holds (such a literal is itself classified as a float, see
|
digits than any number type holds (such a literal is itself classified as a float, see
|
||||||
|
|||||||
@@ -201,6 +201,11 @@ class json_side
|
|||||||
const BasicJsonType* m_json;
|
const BasicJsonType* m_json;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool is_number(value_t t) noexcept
|
||||||
|
{
|
||||||
|
return t == value_t::number_integer || t == value_t::number_unsigned || t == value_t::number_float;
|
||||||
|
}
|
||||||
|
|
||||||
/// whether two sides are equal; iterative, so that the nesting depth is
|
/// whether two sides are equal; iterative, so that the nesting depth is
|
||||||
/// limited by memory only
|
/// limited by memory only
|
||||||
template<typename BasicJsonType, typename A, typename B>
|
template<typename BasicJsonType, typename A, typename B>
|
||||||
@@ -225,8 +230,6 @@ bool equal(const A& a0, const B& b0)
|
|||||||
{
|
{
|
||||||
const value_t ta = a.type();
|
const value_t ta = a.type();
|
||||||
const value_t tb = b.type();
|
const value_t tb = b.type();
|
||||||
const bool numbers = (ta == value_t::number_integer || ta == value_t::number_unsigned || ta == value_t::number_float)
|
|
||||||
&& (tb == value_t::number_integer || tb == value_t::number_unsigned || tb == value_t::number_float);
|
|
||||||
if (ta == value_t::discarded || tb == value_t::discarded)
|
if (ta == value_t::discarded || tb == value_t::discarded)
|
||||||
{
|
{
|
||||||
// basic_json decides (JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
|
// basic_json decides (JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
|
||||||
@@ -237,13 +240,13 @@ bool equal(const A& a0, const B& b0)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!numbers && ta != tb)
|
if (ta != tb && !(is_number(ta) && is_number(tb))) // numbers of different types can be equal
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ta == value_t::string)
|
if (ta == value_t::string)
|
||||||
{
|
{
|
||||||
if (!(a.string() == b.string()))
|
if (a.string() != b.string())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -272,7 +275,7 @@ bool equal(const A& a0, const B& b0)
|
|||||||
}
|
}
|
||||||
stack.push_back(std::move(f));
|
stack.push_back(std::move(f));
|
||||||
}
|
}
|
||||||
else if (!(a.scalar() == b.scalar())) // numbers (also of different types), null, boolean
|
else if (a.scalar() != b.scalar()) // numbers (also of different types), null, boolean
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -289,7 +292,7 @@ bool equal(const A& a0, const B& b0)
|
|||||||
const std::size_t count = f.object ? f.members_a.size() : f.elements_a.size();
|
const std::size_t count = f.object ? f.members_a.size() : f.elements_a.size();
|
||||||
if (f.next == count)
|
if (f.next == count)
|
||||||
{
|
{
|
||||||
stack.pop_back();
|
stack.pop_back(); // (f dangles now, and is bound again after continue)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (f.object)
|
if (f.object)
|
||||||
|
|||||||
@@ -69,6 +69,13 @@ class output_buffer
|
|||||||
m_pos += n;
|
m_pos += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// a string literal, without its terminating NUL
|
||||||
|
template<std::size_t N>
|
||||||
|
NLOHMANN_VIEW_ALWAYS_INLINE void put(const char (&s)[N])
|
||||||
|
{
|
||||||
|
put(s, N - 1);
|
||||||
|
}
|
||||||
|
|
||||||
void put_repeated(char c, std::size_t n)
|
void put_repeated(char c, std::size_t n)
|
||||||
{
|
{
|
||||||
reserve(n);
|
reserve(n);
|
||||||
@@ -170,7 +177,7 @@ class view_serializer
|
|||||||
frame& f = stack.back();
|
frame& f = stack.back();
|
||||||
if (f.pos == f.end)
|
if (f.pos == f.end)
|
||||||
{
|
{
|
||||||
const bool object = f.object;
|
const bool object = f.object; // (f dangles after pop_back)
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
newline(stack.size());
|
newline(stack.size());
|
||||||
m_out.put(object ? '}' : ']');
|
m_out.put(object ? '}' : ']');
|
||||||
@@ -187,7 +194,7 @@ class view_serializer
|
|||||||
write_string(*f.pos);
|
write_string(*f.pos);
|
||||||
if (m_style.pretty)
|
if (m_style.pretty)
|
||||||
{
|
{
|
||||||
m_out.put(": ", 2);
|
m_out.put(": ");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -220,16 +227,16 @@ class view_serializer
|
|||||||
switch (static_cast<value_t>(n.kind))
|
switch (static_cast<value_t>(n.kind))
|
||||||
{
|
{
|
||||||
case value_t::null:
|
case value_t::null:
|
||||||
m_out.put("null", 4);
|
m_out.put("null");
|
||||||
break;
|
break;
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
if ((n.flags & node_flags::is_true) != 0)
|
if ((n.flags & node_flags::is_true) != 0)
|
||||||
{
|
{
|
||||||
m_out.put("true", 4);
|
m_out.put("true");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_out.put("false", 5);
|
m_out.put("false");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
@@ -274,12 +281,14 @@ class view_serializer
|
|||||||
{
|
{
|
||||||
if (!std::isfinite(x))
|
if (!std::isfinite(x))
|
||||||
{
|
{
|
||||||
m_out.put("null", 4);
|
m_out.put("null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
write_float(x, std::integral_constant < bool,
|
static constexpr bool is_ieee_single_or_double
|
||||||
(std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128)
|
= std::numeric_limits<number_float_t>::is_iec559
|
||||||
|| (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024) > {});
|
&& ((std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128)
|
||||||
|
|| (std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024));
|
||||||
|
write_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
|
void write_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
|
||||||
@@ -364,25 +373,25 @@ class view_serializer
|
|||||||
switch (codepoint)
|
switch (codepoint)
|
||||||
{
|
{
|
||||||
case 0x08:
|
case 0x08:
|
||||||
m_out.put("\\b", 2);
|
m_out.put("\\b");
|
||||||
return;
|
return;
|
||||||
case 0x09:
|
case 0x09:
|
||||||
m_out.put("\\t", 2);
|
m_out.put("\\t");
|
||||||
return;
|
return;
|
||||||
case 0x0A:
|
case 0x0A:
|
||||||
m_out.put("\\n", 2);
|
m_out.put("\\n");
|
||||||
return;
|
return;
|
||||||
case 0x0C:
|
case 0x0C:
|
||||||
m_out.put("\\f", 2);
|
m_out.put("\\f");
|
||||||
return;
|
return;
|
||||||
case 0x0D:
|
case 0x0D:
|
||||||
m_out.put("\\r", 2);
|
m_out.put("\\r");
|
||||||
return;
|
return;
|
||||||
case 0x22:
|
case 0x22:
|
||||||
m_out.put("\\\"", 2);
|
m_out.put("\\\"");
|
||||||
return;
|
return;
|
||||||
case 0x5C:
|
case 0x5C:
|
||||||
m_out.put("\\\\", 2);
|
m_out.put("\\\\");
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in new issue
Block a user