diff --git a/docs/mkdocs/docs/api/basic_json_view/dump.md b/docs/mkdocs/docs/api/basic_json_view/dump.md index 7cc0b6b38..aa9a023bb 100644 --- a/docs/mkdocs/docs/api/basic_json_view/dump.md +++ b/docs/mkdocs/docs/api/basic_json_view/dump.md @@ -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 call stack -- as for [`materialize()`](materialize.md). -Strings are escaped by the same rules as [`BasicJsonType::dump`](../basic_json/dump.md). With -`#!cpp numbers == number_format::shortest`, floats are written with the library's shortest round-trip conversion, +Strings are escaped by the same rules as [`BasicJsonType::dump`](../basic_json/dump.md). + +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 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. + `#!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 digits than any number type holds (such a literal is itself classified as a float, see diff --git a/include/nlohmann/detail/view/compare.hpp b/include/nlohmann/detail/view/compare.hpp index 9a50590a3..8ca6058f0 100644 --- a/include/nlohmann/detail/view/compare.hpp +++ b/include/nlohmann/detail/view/compare.hpp @@ -201,6 +201,11 @@ class json_side 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 /// limited by memory only template @@ -225,8 +230,6 @@ bool equal(const A& a0, const B& b0) { const value_t ta = a.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) { // basic_json decides (JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON) @@ -237,13 +240,13 @@ bool equal(const A& a0, const B& b0) } else { - if (!numbers && ta != tb) + if (ta != tb && !(is_number(ta) && is_number(tb))) // numbers of different types can be equal { return false; } if (ta == value_t::string) { - if (!(a.string() == b.string())) + if (a.string() != b.string()) { return false; } @@ -272,7 +275,7 @@ bool equal(const A& a0, const B& b0) } 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; } @@ -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(); if (f.next == count) { - stack.pop_back(); + stack.pop_back(); // (f dangles now, and is bound again after continue) continue; } if (f.object) diff --git a/include/nlohmann/detail/view/serializer.hpp b/include/nlohmann/detail/view/serializer.hpp index bde8797c5..4ec902421 100644 --- a/include/nlohmann/detail/view/serializer.hpp +++ b/include/nlohmann/detail/view/serializer.hpp @@ -69,6 +69,13 @@ class output_buffer m_pos += n; } + /// a string literal, without its terminating NUL + template + NLOHMANN_VIEW_ALWAYS_INLINE void put(const char (&s)[N]) + { + put(s, N - 1); + } + void put_repeated(char c, std::size_t n) { reserve(n); @@ -170,7 +177,7 @@ class view_serializer frame& f = stack.back(); if (f.pos == f.end) { - const bool object = f.object; + const bool object = f.object; // (f dangles after pop_back) stack.pop_back(); newline(stack.size()); m_out.put(object ? '}' : ']'); @@ -187,7 +194,7 @@ class view_serializer write_string(*f.pos); if (m_style.pretty) { - m_out.put(": ", 2); + m_out.put(": "); } else { @@ -220,16 +227,16 @@ class view_serializer switch (static_cast(n.kind)) { case value_t::null: - m_out.put("null", 4); + m_out.put("null"); break; case value_t::boolean: if ((n.flags & node_flags::is_true) != 0) { - m_out.put("true", 4); + m_out.put("true"); } else { - m_out.put("false", 5); + m_out.put("false"); } break; case value_t::string: @@ -274,12 +281,14 @@ class view_serializer { if (!std::isfinite(x)) { - m_out.put("null", 4); + m_out.put("null"); return; } - write_float(x, std::integral_constant < bool, - (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 24 && std::numeric_limits::max_exponent == 128) - || (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 53 && std::numeric_limits::max_exponent == 1024) > {}); + static constexpr bool is_ieee_single_or_double + = std::numeric_limits::is_iec559 + && ((std::numeric_limits::digits == 24 && std::numeric_limits::max_exponent == 128) + || (std::numeric_limits::digits == 53 && std::numeric_limits::max_exponent == 1024)); + write_float(x, std::integral_constant()); } void write_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) @@ -364,25 +373,25 @@ class view_serializer switch (codepoint) { case 0x08: - m_out.put("\\b", 2); + m_out.put("\\b"); return; case 0x09: - m_out.put("\\t", 2); + m_out.put("\\t"); return; case 0x0A: - m_out.put("\\n", 2); + m_out.put("\\n"); return; case 0x0C: - m_out.put("\\f", 2); + m_out.put("\\f"); return; case 0x0D: - m_out.put("\\r", 2); + m_out.put("\\r"); return; case 0x22: - m_out.put("\\\"", 2); + m_out.put("\\\""); return; case 0x5C: - m_out.put("\\\\", 2); + m_out.put("\\\\"); return; default: break;