diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index a7dab5cd6..f88278f8e 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -109,6 +109,43 @@ class serializer const bool ensure_ascii, const unsigned int indent_step, const unsigned int current_indent = 0) + { + auto predicate = [pretty_print](const BasicJsonType&, int) { return pretty_print; }; + dump_configured(val, ensure_ascii, indent_step, current_indent, predicate); + } + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. If uses a predicate to decide whether to avoid pretty + printing a subtree. If the predicate returns false, pretty printing is + avoided for the whole tree, otherwise the current value is pretty printed + and the function is reevaluated for nested values. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + - binary values are serialized as objects containing the subtype and the + byte array + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed based + on the value and current identation + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + template + void dump_configured(const BasicJsonType& val, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent, + const PrettyPrintPredicate& pretty_print) { switch (val.m_type) { @@ -120,7 +157,7 @@ class serializer return; } - if (pretty_print) + if (pretty_print(val, current_indent)) { o->write_characters("{\n", 2); @@ -139,7 +176,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); + dump_configured(i->second, ensure_ascii, indent_step, new_indent, pretty_print); o->write_characters(",\n", 2); } @@ -150,7 +187,7 @@ class serializer o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\": ", 3); - dump(i->second, true, ensure_ascii, indent_step, new_indent); + dump_configured(i->second, ensure_ascii, indent_step, new_indent, pretty_print); o->write_character('\n'); o->write_characters(indent_string.c_str(), current_indent); @@ -193,7 +230,7 @@ class serializer return; } - if (pretty_print) + if (pretty_print(val, current_indent)) { o->write_characters("[\n", 2); @@ -206,17 +243,18 @@ class serializer // first n-1 elements for (auto i = val.m_value.array->cbegin(); - i != val.m_value.array->cend() - 1; ++i) + i != val.m_value.array->cend() - 1; + ++i) { o->write_characters(indent_string.c_str(), new_indent); - dump(*i, true, ensure_ascii, indent_step, new_indent); + dump_configured(*i, ensure_ascii, indent_step, new_indent, pretty_print); o->write_characters(",\n", 2); } // last element JSON_ASSERT(!val.m_value.array->empty()); o->write_characters(indent_string.c_str(), new_indent); - dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + dump_configured(val.m_value.array->back(), ensure_ascii, indent_step, new_indent, pretty_print); o->write_character('\n'); o->write_characters(indent_string.c_str(), current_indent); @@ -254,7 +292,7 @@ class serializer case value_t::binary: { - if (pretty_print) + if (pretty_print(val, current_indent)) { o->write_characters("{\n", 2); diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index b1c23f7d7..413ba2ac6 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1282,6 +1282,28 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return result; } + template + string_t dump(const int indent, + const char indent_char, + const bool ensure_ascii, + const error_handler_t error_handler, + const PrettyPrintPredicate& pretty_print) const + { + string_t result; + serializer s(detail::output_adapter(result), indent_char, error_handler); + + if (indent >= 0) + { + s.dump_configured(*this, ensure_ascii, static_cast(indent), 0, pretty_print); + } + else + { + s.dump(*this, false, ensure_ascii, 0); + } + + return result; + } + /// @brief return the type of the JSON value (explicit) /// @sa https://json.nlohmann.me/api/basic_json/type/ constexpr value_t type() const noexcept diff --git a/tests/src/unit-serialization.cpp b/tests/src/unit-serialization.cpp index 01e5bdfea..dc54d73b6 100644 --- a/tests/src/unit-serialization.cpp +++ b/tests/src/unit-serialization.cpp @@ -79,6 +79,17 @@ TEST_CASE("serialization") SECTION("dump") { + SECTION("no pretty primitive arrays") + { + auto pretty_print = [](json const& x, int) + { + return !x.is_array() || std::any_of(x.cbegin(), x.cend(), [](json const& e) { return !e.is_primitive(); }); + }; + + const json j = {{"foo", {1, 2, 3}}}; + CHECK(j.dump(1, ' ', false, json::error_handler_t::strict, pretty_print) == "{\n \"foo\": [1,2,3]\n}"); + } + SECTION("invalid character") { const json j = "ä\xA9ü";