This commit is contained in:
Marius Elvert 2023-02-10 17:20:32 +08:00 committed by GitHub
commit 5484d3c872
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 152 additions and 18 deletions

View File

@ -109,6 +109,46 @@ 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<typename PrettyPrintPredicate>
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 +160,7 @@ class serializer
return;
}
if (pretty_print)
if (pretty_print(val, static_cast<int>(current_indent)))
{
o->write_characters("{\n", 2);
@ -139,7 +179,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 +190,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 +233,7 @@ class serializer
return;
}
if (pretty_print)
if (pretty_print(val, static_cast<int>(current_indent)))
{
o->write_characters("[\n", 2);
@ -206,17 +246,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 +295,7 @@ class serializer
case value_t::binary:
{
if (pretty_print)
if (pretty_print(val, static_cast<int>(current_indent)))
{
o->write_characters("{\n", 2);

View File

@ -1266,13 +1266,32 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const char indent_char = ' ',
const bool ensure_ascii = false,
const error_handler_t error_handler = error_handler_t::strict) const
{
return dump(indent, indent_char, ensure_ascii, error_handler, [](basic_json const&, int)
{
return true;
});
}
/// @name object inspection
/// Functions to inspect the type of a JSON value.
/// @{
/// @brief serialization
/// @sa https://json.nlohmann.me/api/basic_json/dump/
template <typename PrettyPrintPredicate>
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<char, string_t>(result), indent_char, error_handler);
if (indent >= 0)
{
s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
s.dump_configured(*this, ensure_ascii, static_cast<unsigned int>(indent), 0, pretty_print);
}
else
{

View File

@ -18031,6 +18031,46 @@ 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<typename PrettyPrintPredicate>
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)
{
@ -18042,7 +18082,7 @@ class serializer
return;
}
if (pretty_print)
if (pretty_print(val, static_cast<int>(current_indent)))
{
o->write_characters("{\n", 2);
@ -18061,7 +18101,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);
}
@ -18072,7 +18112,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);
@ -18115,7 +18155,7 @@ class serializer
return;
}
if (pretty_print)
if (pretty_print(val, static_cast<int>(current_indent)))
{
o->write_characters("[\n", 2);
@ -18128,17 +18168,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);
@ -18176,7 +18217,7 @@ class serializer
case value_t::binary:
{
if (pretty_print)
if (pretty_print(val, static_cast<int>(current_indent)))
{
o->write_characters("{\n", 2);
@ -20482,13 +20523,32 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
const char indent_char = ' ',
const bool ensure_ascii = false,
const error_handler_t error_handler = error_handler_t::strict) const
{
return dump(indent, indent_char, ensure_ascii, error_handler, [](basic_json const&, int)
{
return true;
});
}
/// @name object inspection
/// Functions to inspect the type of a JSON value.
/// @{
/// @brief serialization
/// @sa https://json.nlohmann.me/api/basic_json/dump/
template <typename PrettyPrintPredicate>
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<char, string_t>(result), indent_char, error_handler);
if (indent >= 0)
{
s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
s.dump_configured(*this, ensure_ascii, static_cast<unsigned int>(indent), 0, pretty_print);
}
else
{

View File

@ -79,6 +79,20 @@ 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ü";