diff --git a/include/flatbuffers/flexbuffers.h b/include/flatbuffers/flexbuffers.h index d55ab8495..6651157b8 100644 --- a/include/flatbuffers/flexbuffers.h +++ b/include/flatbuffers/flexbuffers.h @@ -360,16 +360,40 @@ class Map : public Vector { bool IsTheEmptyMap() const { return data_ == EmptyMap().data_; } }; +inline void IndentString(std::string &s, int indent, + const char *indent_string) { + for (int i = 0; i < indent; i++) s += indent_string; +} + +template +void AppendToString(std::string &s, T &&v, bool keys_quoted, bool indented, + int cur_indent, const char *indent_string) { + s += "["; + s += indented ? "\n" : " "; + for (size_t i = 0; i < v.size(); i++) { + if (i) { + s += ","; + s += indented ? "\n" : " "; + } + if (indented) IndentString(s, cur_indent, indent_string); + v[i].ToString(true, keys_quoted, s, indented, cur_indent, + indent_string); + } + if (indented) { + s += "\n"; + IndentString(s, cur_indent - 1, indent_string); + } else { + s += " "; + } + s += "]"; +} + template void AppendToString(std::string &s, T &&v, bool keys_quoted) { - s += "[ "; - for (size_t i = 0; i < v.size(); i++) { - if (i) s += ", "; - v[i].ToString(true, keys_quoted, s); - } - s += " ]"; + AppendToString(s, v, keys_quoted); } + class Reference { public: Reference() @@ -542,8 +566,13 @@ class Reference { // Convert any type to a JSON-like string. strings_quoted determines if // string values at the top level receive "" quotes (inside other values // they always do). keys_quoted determines if keys are quoted, at any level. - // TODO(wvo): add further options to have indentation/newlines. void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const { + ToString(strings_quoted, keys_quoted, s, false, 0, ""); + } + + // This version additionally allow you to specify if you want indentation. + void ToString(bool strings_quoted, bool keys_quoted, std::string &s, + bool indented, int cur_indent, const char *indent_string) const { if (type_ == FBT_STRING) { String str(Indirect(), byte_width_); if (strings_quoted) { @@ -569,7 +598,8 @@ class Reference { } else if (IsBool()) { s += AsBool() ? "true" : "false"; } else if (IsMap()) { - s += "{ "; + s += "{"; + s += indented ? "\n" : " "; auto m = AsMap(); auto keys = m.Keys(); auto vals = m.Values(); @@ -590,18 +620,28 @@ class Reference { } } } + if (indented) IndentString(s, cur_indent + 1, indent_string); keys[i].ToString(true, kq, s); s += ": "; - vals[i].ToString(true, keys_quoted, s); - if (i < keys.size() - 1) s += ", "; + vals[i].ToString(true, keys_quoted, s, indented, cur_indent + 1, indent_string); + if (i < keys.size() - 1) { + s += ","; + if (!indented) s += " "; + } + if (indented) s += "\n"; } - s += " }"; + if (!indented) s += " "; + if (indented) IndentString(s, cur_indent, indent_string); + s += "}"; } else if (IsVector()) { - AppendToString(s, AsVector(), keys_quoted); + AppendToString(s, AsVector(), keys_quoted, indented, + cur_indent + 1, indent_string); } else if (IsTypedVector()) { - AppendToString(s, AsTypedVector(), keys_quoted); + AppendToString(s, AsTypedVector(), keys_quoted, indented, + cur_indent + 1, indent_string); } else if (IsFixedTypedVector()) { - AppendToString(s, AsFixedTypedVector(), keys_quoted); + AppendToString(s, AsFixedTypedVector(), keys_quoted, + indented, cur_indent + 1, indent_string); } else if (IsBlob()) { auto blob = AsBlob(); flatbuffers::EscapeString(reinterpret_cast(blob.data()), diff --git a/tests/flexbuffers_test.cpp b/tests/flexbuffers_test.cpp index c504f4e3b..0c7d04e7c 100644 --- a/tests/flexbuffers_test.cpp +++ b/tests/flexbuffers_test.cpp @@ -132,6 +132,12 @@ void FlexBuffersTest() { // And from FlexBuffer back to JSON: auto jsonback = jroot.ToString(); TEST_EQ_STR(jsontest, jsonback.c_str()); + // With indentation: + std::string jsonback_indented; + jroot.ToString(true, false, jsonback_indented, true, 0, " "); + auto jsontest_indented = + "{\n a: [\n 123,\n 456.0\n ],\n b: \"hello\",\n c: true,\n d: false\n}"; + TEST_EQ_STR(jsontest_indented, jsonback_indented.c_str()); slb.Clear(); slb.Vector([&]() {