Introduce fancy_serializer_style

This commit is contained in:
Evan Driscoll 2018-06-02 01:18:55 -05:00
parent e38b4e8031
commit 003f3e298b
3 changed files with 69 additions and 46 deletions

View File

@ -23,6 +23,13 @@
namespace nlohmann namespace nlohmann
{ {
struct fancy_serializer_style
{
unsigned int indent_step = 0;
char indent_char = ' ';
};
namespace detail namespace detail
{ {
/////////////////// ///////////////////
@ -45,8 +52,9 @@ class fancy_serializer
@param[in] s output stream to serialize to @param[in] s output stream to serialize to
@param[in] ichar indentation character to use @param[in] ichar indentation character to use
*/ */
fancy_serializer(output_adapter_t<char> s, const char ichar) fancy_serializer(output_adapter_t<char> s,
: o(std::move(s)), indent_char(ichar), indent_string(512, indent_char) const fancy_serializer_style& st)
: o(std::move(s)), indent_string(512, st.indent_char), style(st)
{} {}
// delete because of pointer members // delete because of pointer members
@ -70,9 +78,8 @@ class fancy_serializer
@param[in] indent_step the indent level @param[in] indent_step the indent level
@param[in] current_indent the current indent level (only used internally) @param[in] current_indent the current indent level (only used internally)
*/ */
void dump(const BasicJsonType& val, const bool pretty_print, void dump(const BasicJsonType& val,
const bool ensure_ascii, const bool ensure_ascii,
const unsigned int indent_step,
const unsigned int current_indent = 0) const unsigned int current_indent = 0)
{ {
switch (val.m_type) switch (val.m_type)
@ -85,12 +92,12 @@ class fancy_serializer
return; return;
} }
if (pretty_print) if (style.indent_step > 0)
{ {
o->write_characters("{\n", 2); o->write_characters("{\n", 2);
// variable to hold indentation for recursive calls // variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step; const auto new_indent = current_indent + style.indent_step;
if (JSON_UNLIKELY(indent_string.size() < new_indent)) if (JSON_UNLIKELY(indent_string.size() < new_indent))
{ {
indent_string.resize(indent_string.size() * 2, ' '); indent_string.resize(indent_string.size() * 2, ' ');
@ -104,7 +111,7 @@ class fancy_serializer
o->write_character('\"'); o->write_character('\"');
prim_serializer.dump_escaped(*o, i->first, ensure_ascii); prim_serializer.dump_escaped(*o, i->first, ensure_ascii);
o->write_characters("\": ", 3); o->write_characters("\": ", 3);
dump(i->second, true, ensure_ascii, indent_step, new_indent); dump(i->second, ensure_ascii, new_indent);
o->write_characters(",\n", 2); o->write_characters(",\n", 2);
} }
@ -115,7 +122,7 @@ class fancy_serializer
o->write_character('\"'); o->write_character('\"');
prim_serializer.dump_escaped(*o, i->first, ensure_ascii); prim_serializer.dump_escaped(*o, i->first, ensure_ascii);
o->write_characters("\": ", 3); o->write_characters("\": ", 3);
dump(i->second, true, ensure_ascii, indent_step, new_indent); dump(i->second, ensure_ascii, new_indent);
o->write_character('\n'); o->write_character('\n');
o->write_characters(indent_string.c_str(), current_indent); o->write_characters(indent_string.c_str(), current_indent);
@ -132,7 +139,7 @@ class fancy_serializer
o->write_character('\"'); o->write_character('\"');
prim_serializer.dump_escaped(*o, i->first, ensure_ascii); prim_serializer.dump_escaped(*o, i->first, ensure_ascii);
o->write_characters("\":", 2); o->write_characters("\":", 2);
dump(i->second, false, ensure_ascii, indent_step, current_indent); dump(i->second, ensure_ascii, current_indent);
o->write_character(','); o->write_character(',');
} }
@ -142,7 +149,7 @@ class fancy_serializer
o->write_character('\"'); o->write_character('\"');
prim_serializer.dump_escaped(*o, i->first, ensure_ascii); prim_serializer.dump_escaped(*o, i->first, ensure_ascii);
o->write_characters("\":", 2); o->write_characters("\":", 2);
dump(i->second, false, ensure_ascii, indent_step, current_indent); dump(i->second, ensure_ascii, current_indent);
o->write_character('}'); o->write_character('}');
} }
@ -158,12 +165,12 @@ class fancy_serializer
return; return;
} }
if (pretty_print) if (style.indent_step > 0)
{ {
o->write_characters("[\n", 2); o->write_characters("[\n", 2);
// variable to hold indentation for recursive calls // variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step; const auto new_indent = current_indent + style.indent_step;
if (JSON_UNLIKELY(indent_string.size() < new_indent)) if (JSON_UNLIKELY(indent_string.size() < new_indent))
{ {
indent_string.resize(indent_string.size() * 2, ' '); indent_string.resize(indent_string.size() * 2, ' ');
@ -174,14 +181,14 @@ class fancy_serializer
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); o->write_characters(indent_string.c_str(), new_indent);
dump(*i, true, ensure_ascii, indent_step, new_indent); dump(*i, ensure_ascii, new_indent);
o->write_characters(",\n", 2); o->write_characters(",\n", 2);
} }
// last element // last element
assert(not val.m_value.array->empty()); assert(not val.m_value.array->empty());
o->write_characters(indent_string.c_str(), new_indent); o->write_characters(indent_string.c_str(), new_indent);
dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); dump(val.m_value.array->back(), ensure_ascii, new_indent);
o->write_character('\n'); o->write_character('\n');
o->write_characters(indent_string.c_str(), current_indent); o->write_characters(indent_string.c_str(), current_indent);
@ -195,13 +202,13 @@ class fancy_serializer
for (auto i = val.m_value.array->cbegin(); for (auto i = val.m_value.array->cbegin();
i != val.m_value.array->cend() - 1; ++i) i != val.m_value.array->cend() - 1; ++i)
{ {
dump(*i, false, ensure_ascii, indent_step, current_indent); dump(*i, ensure_ascii, current_indent);
o->write_character(','); o->write_character(',');
} }
// last element // last element
assert(not val.m_value.array->empty()); assert(not val.m_value.array->empty());
dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); dump(val.m_value.array->back(), ensure_ascii, current_indent);
o->write_character(']'); o->write_character(']');
} }
@ -266,24 +273,25 @@ class fancy_serializer
/// the output of the fancy_serializer /// the output of the fancy_serializer
output_adapter_t<char> o = nullptr; output_adapter_t<char> o = nullptr;
/// the indentation character
const char indent_char;
/// the indentation string /// the indentation string
string_t indent_string; string_t indent_string;
/// Used for serializing "base" objects. Strings are sort of /// Used for serializing "base" objects. Strings are sort of
/// counted in this, but not completely. /// counted in this, but not completely.
primitive_serializer_t prim_serializer; primitive_serializer_t prim_serializer;
/// Output style
fancy_serializer_style style;
}; };
} }
template<typename BasicJsonType> template<typename BasicJsonType>
std::ostream& fancy_dump(std::ostream& o, const BasicJsonType& j, std::ostream& fancy_dump(std::ostream& o, const BasicJsonType& j,
unsigned int indent_step, char indent_char) fancy_serializer_style style)
{ {
// do the actual serialization // do the actual serialization
detail::fancy_serializer<BasicJsonType> s(detail::output_adapter<char>(o), indent_char); detail::fancy_serializer<BasicJsonType> s(detail::output_adapter<char>(o), style);
s.dump(j, indent_step > 0, false, indent_step); s.dump(j, false, 0u);
return o; return o;
} }

View File

@ -10093,6 +10093,13 @@ class serializer
namespace nlohmann namespace nlohmann
{ {
struct fancy_serializer_style
{
unsigned int indent_step = 0;
char indent_char = ' ';
};
namespace detail namespace detail
{ {
/////////////////// ///////////////////
@ -10115,8 +10122,9 @@ class fancy_serializer
@param[in] s output stream to serialize to @param[in] s output stream to serialize to
@param[in] ichar indentation character to use @param[in] ichar indentation character to use
*/ */
fancy_serializer(output_adapter_t<char> s, const char ichar) fancy_serializer(output_adapter_t<char> s,
: o(std::move(s)), indent_char(ichar), indent_string(512, indent_char) const fancy_serializer_style& st)
: o(std::move(s)), indent_string(512, st.indent_char), style(st)
{} {}
// delete because of pointer members // delete because of pointer members
@ -10140,9 +10148,8 @@ class fancy_serializer
@param[in] indent_step the indent level @param[in] indent_step the indent level
@param[in] current_indent the current indent level (only used internally) @param[in] current_indent the current indent level (only used internally)
*/ */
void dump(const BasicJsonType& val, const bool pretty_print, void dump(const BasicJsonType& val,
const bool ensure_ascii, const bool ensure_ascii,
const unsigned int indent_step,
const unsigned int current_indent = 0) const unsigned int current_indent = 0)
{ {
switch (val.m_type) switch (val.m_type)
@ -10155,12 +10162,12 @@ class fancy_serializer
return; return;
} }
if (pretty_print) if (style.indent_step > 0)
{ {
o->write_characters("{\n", 2); o->write_characters("{\n", 2);
// variable to hold indentation for recursive calls // variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step; const auto new_indent = current_indent + style.indent_step;
if (JSON_UNLIKELY(indent_string.size() < new_indent)) if (JSON_UNLIKELY(indent_string.size() < new_indent))
{ {
indent_string.resize(indent_string.size() * 2, ' '); indent_string.resize(indent_string.size() * 2, ' ');
@ -10174,7 +10181,7 @@ class fancy_serializer
o->write_character('\"'); o->write_character('\"');
prim_serializer.dump_escaped(*o, i->first, ensure_ascii); prim_serializer.dump_escaped(*o, i->first, ensure_ascii);
o->write_characters("\": ", 3); o->write_characters("\": ", 3);
dump(i->second, true, ensure_ascii, indent_step, new_indent); dump(i->second, ensure_ascii, new_indent);
o->write_characters(",\n", 2); o->write_characters(",\n", 2);
} }
@ -10185,7 +10192,7 @@ class fancy_serializer
o->write_character('\"'); o->write_character('\"');
prim_serializer.dump_escaped(*o, i->first, ensure_ascii); prim_serializer.dump_escaped(*o, i->first, ensure_ascii);
o->write_characters("\": ", 3); o->write_characters("\": ", 3);
dump(i->second, true, ensure_ascii, indent_step, new_indent); dump(i->second, ensure_ascii, new_indent);
o->write_character('\n'); o->write_character('\n');
o->write_characters(indent_string.c_str(), current_indent); o->write_characters(indent_string.c_str(), current_indent);
@ -10202,7 +10209,7 @@ class fancy_serializer
o->write_character('\"'); o->write_character('\"');
prim_serializer.dump_escaped(*o, i->first, ensure_ascii); prim_serializer.dump_escaped(*o, i->first, ensure_ascii);
o->write_characters("\":", 2); o->write_characters("\":", 2);
dump(i->second, false, ensure_ascii, indent_step, current_indent); dump(i->second, ensure_ascii, current_indent);
o->write_character(','); o->write_character(',');
} }
@ -10212,7 +10219,7 @@ class fancy_serializer
o->write_character('\"'); o->write_character('\"');
prim_serializer.dump_escaped(*o, i->first, ensure_ascii); prim_serializer.dump_escaped(*o, i->first, ensure_ascii);
o->write_characters("\":", 2); o->write_characters("\":", 2);
dump(i->second, false, ensure_ascii, indent_step, current_indent); dump(i->second, ensure_ascii, current_indent);
o->write_character('}'); o->write_character('}');
} }
@ -10228,12 +10235,12 @@ class fancy_serializer
return; return;
} }
if (pretty_print) if (style.indent_step > 0)
{ {
o->write_characters("[\n", 2); o->write_characters("[\n", 2);
// variable to hold indentation for recursive calls // variable to hold indentation for recursive calls
const auto new_indent = current_indent + indent_step; const auto new_indent = current_indent + style.indent_step;
if (JSON_UNLIKELY(indent_string.size() < new_indent)) if (JSON_UNLIKELY(indent_string.size() < new_indent))
{ {
indent_string.resize(indent_string.size() * 2, ' '); indent_string.resize(indent_string.size() * 2, ' ');
@ -10244,14 +10251,14 @@ class fancy_serializer
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); o->write_characters(indent_string.c_str(), new_indent);
dump(*i, true, ensure_ascii, indent_step, new_indent); dump(*i, ensure_ascii, new_indent);
o->write_characters(",\n", 2); o->write_characters(",\n", 2);
} }
// last element // last element
assert(not val.m_value.array->empty()); assert(not val.m_value.array->empty());
o->write_characters(indent_string.c_str(), new_indent); o->write_characters(indent_string.c_str(), new_indent);
dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); dump(val.m_value.array->back(), ensure_ascii, new_indent);
o->write_character('\n'); o->write_character('\n');
o->write_characters(indent_string.c_str(), current_indent); o->write_characters(indent_string.c_str(), current_indent);
@ -10265,13 +10272,13 @@ class fancy_serializer
for (auto i = val.m_value.array->cbegin(); for (auto i = val.m_value.array->cbegin();
i != val.m_value.array->cend() - 1; ++i) i != val.m_value.array->cend() - 1; ++i)
{ {
dump(*i, false, ensure_ascii, indent_step, current_indent); dump(*i, ensure_ascii, current_indent);
o->write_character(','); o->write_character(',');
} }
// last element // last element
assert(not val.m_value.array->empty()); assert(not val.m_value.array->empty());
dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); dump(val.m_value.array->back(), ensure_ascii, current_indent);
o->write_character(']'); o->write_character(']');
} }
@ -10336,24 +10343,25 @@ class fancy_serializer
/// the output of the fancy_serializer /// the output of the fancy_serializer
output_adapter_t<char> o = nullptr; output_adapter_t<char> o = nullptr;
/// the indentation character
const char indent_char;
/// the indentation string /// the indentation string
string_t indent_string; string_t indent_string;
/// Used for serializing "base" objects. Strings are sort of /// Used for serializing "base" objects. Strings are sort of
/// counted in this, but not completely. /// counted in this, but not completely.
primitive_serializer_t prim_serializer; primitive_serializer_t prim_serializer;
/// Output style
fancy_serializer_style style;
}; };
} }
template<typename BasicJsonType> template<typename BasicJsonType>
std::ostream& fancy_dump(std::ostream& o, const BasicJsonType& j, std::ostream& fancy_dump(std::ostream& o, const BasicJsonType& j,
unsigned int indent_step, char indent_char) fancy_serializer_style style)
{ {
// do the actual serialization // do the actual serialization
detail::fancy_serializer<BasicJsonType> s(detail::output_adapter<char>(o), indent_char); detail::fancy_serializer<BasicJsonType> s(detail::output_adapter<char>(o), style);
s.dump(j, indent_step > 0, false, indent_step); s.dump(j, false, 0u);
return o; return o;
} }

View File

@ -33,11 +33,12 @@ SOFTWARE.
using nlohmann::json; using nlohmann::json;
using nlohmann::fancy_dump; using nlohmann::fancy_dump;
using nlohmann::fancy_serializer_style;
std::string fancy_to_string(json j, unsigned int indent_step = 0, char indent_char = ' ') std::string fancy_to_string(json j, fancy_serializer_style style = fancy_serializer_style())
{ {
std::stringstream ss; std::stringstream ss;
fancy_dump(ss, j, indent_step, indent_char); fancy_dump(ss, j, style);
return ss.str(); return ss.str();
} }
@ -78,7 +79,9 @@ TEST_CASE("serialization")
SECTION("given width") SECTION("given width")
{ {
auto str = fancy_to_string({"foo", 1, 2, 3, false, {{"one", 1}}}, 4); fancy_serializer_style style;
style.indent_step = 4;
auto str = fancy_to_string({"foo", 1, 2, 3, false, {{"one", 1}}}, style);
CHECK(str == CHECK(str ==
"[\n" "[\n"
" \"foo\",\n" " \"foo\",\n"
@ -95,7 +98,11 @@ TEST_CASE("serialization")
SECTION("given fill") SECTION("given fill")
{ {
auto str = fancy_to_string({"foo", 1, 2, 3, false, {{"one", 1}}}, 1, '\t'); fancy_serializer_style style;
style.indent_step = 1;
style.indent_char = '\t';
auto str = fancy_to_string({"foo", 1, 2, 3, false, {{"one", 1}}}, style);
CHECK(str == CHECK(str ==
"[\n" "[\n"
"\t\"foo\",\n" "\t\"foo\",\n"