aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/json/json_prettifier.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/json/json_prettifier.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/json/json_prettifier.cpp')
-rw-r--r--library/cpp/json/json_prettifier.cpp277
1 files changed, 277 insertions, 0 deletions
diff --git a/library/cpp/json/json_prettifier.cpp b/library/cpp/json/json_prettifier.cpp
new file mode 100644
index 0000000000..bb16aab44e
--- /dev/null
+++ b/library/cpp/json/json_prettifier.cpp
@@ -0,0 +1,277 @@
+#include "json_prettifier.h"
+
+#include <util/generic/deque.h>
+#include <util/generic/algorithm.h>
+#include <util/memory/pool.h>
+#include <util/string/util.h>
+
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+
+namespace NJson {
+ struct TRewritableOut {
+ IOutputStream& Slave;
+
+ char Last = 0;
+ bool Dirty = false;
+
+ TRewritableOut(IOutputStream& sl)
+ : Slave(sl)
+ {
+ }
+
+ template <typename T>
+ void Write(const T& t) {
+ Flush();
+ Slave << t;
+ }
+
+ void Hold(char c) {
+ if (Dirty)
+ Flush();
+ Last = c;
+ Dirty = true;
+ }
+
+ void Flush() {
+ if (Dirty) {
+ Slave << Last;
+ Dirty = false;
+ }
+ }
+
+ void Revert() {
+ Dirty = false;
+ }
+ };
+
+ struct TSpaces {
+ char S[256];
+
+ TSpaces() {
+ memset(&S, ' ', sizeof(S));
+ }
+
+ TStringBuf Get(ui8 sz) const {
+ return TStringBuf(S, sz);
+ }
+ };
+
+ bool TJsonPrettifier::MayUnquoteNew(TStringBuf s) {
+ static str_spn alpha("a-zA-Z_@$", true);
+ static str_spn alnum("a-zA-Z_@$0-9.-", true);
+ static TStringBuf true0("true");
+ static TStringBuf false0("false");
+ static TStringBuf null0("null");
+
+ return !!s && alpha.chars_table[(ui8)s[0]] && alnum.cbrk(s.begin() + 1, s.end()) == s.end() && !EqualToOneOf(s, null0, true0, false0);
+ }
+
+ // to keep arcadia tests happy
+ bool TJsonPrettifier::MayUnquoteOld(TStringBuf s) {
+ static str_spn alpha("a-zA-Z_@$", true);
+ static str_spn alnum("a-zA-Z_@$0-9", true);
+ static TStringBuf true0("true");
+ static TStringBuf false0("false");
+ static TStringBuf true1("on");
+ static TStringBuf false1("off");
+ static TStringBuf true2("da");
+ static TStringBuf false2("net");
+ static TStringBuf null0("null");
+
+ return !!s && alpha.chars_table[(ui8)s[0]] && alnum.cbrk(s.begin() + 1, s.end()) == s.end() && !EqualToOneOf(s, null0, true0, false0, true1, false1, true2, false2);
+ }
+
+ class TPrettifier: public TJsonCallbacks {
+ TRewritableOut Out;
+ TStringBuf Spaces;
+ TStringBuf Quote;
+ TStringBuf Unsafe;
+ TStringBuf Safe;
+
+ ui32 Level = 0;
+ ui32 MaxPaddingLevel;
+
+ bool Unquote = false;
+ bool Compactify = false;
+ bool NewUnquote = false;
+
+ public:
+ TPrettifier(IOutputStream& out, const TJsonPrettifier& p)
+ : Out(out)
+ , MaxPaddingLevel(p.MaxPaddingLevel)
+ , Unquote(p.Unquote)
+ , Compactify(p.Compactify)
+ , NewUnquote(p.NewUnquote)
+ {
+ static TSpaces spaces;
+ Spaces = spaces.Get(p.Padding);
+ if (p.SingleQuotes) {
+ Quote = Unsafe = "'";
+ Safe = "\"";
+ } else {
+ Quote = Unsafe = "\"";
+ Safe = "'";
+ }
+ }
+
+ void Pad(bool close = false) {
+ if (Compactify) {
+ Out.Flush();
+ return;
+ }
+ if (Level > MaxPaddingLevel || (Level == MaxPaddingLevel && close)) {
+ Out.Write(" ");
+ return;
+ }
+ if (Level || close) {
+ Out.Write(Spaces ? "\n" : " ");
+ }
+ for (ui32 i = 0; i < Level; ++i) {
+ Out.Write(Spaces);
+ }
+ }
+
+ void WriteSpace(char sp) {
+ if (Compactify) {
+ Out.Flush();
+ return;
+ }
+
+ Out.Write(sp);
+ }
+
+ void OnVal() {
+ if (Out.Dirty && ':' == Out.Last) {
+ WriteSpace(' ');
+ } else {
+ Pad();
+ }
+ }
+
+ void AfterVal() {
+ Out.Hold(',');
+ }
+
+ template <typename T>
+ bool WriteVal(const T& t) {
+ OnVal();
+ Out.Write(t);
+ AfterVal();
+ return true;
+ }
+
+ bool OnNull() override {
+ return WriteVal(TStringBuf("null"));
+ }
+
+ bool OnBoolean(bool v) override {
+ return WriteVal(v ? TStringBuf("true") : TStringBuf("false"));
+ }
+
+ bool OnInteger(long long i) override {
+ return WriteVal(i);
+ }
+
+ bool OnUInteger(unsigned long long i) override {
+ return WriteVal(i);
+ }
+
+ bool OnDouble(double d) override {
+ return WriteVal(d);
+ }
+
+ void WriteString(TStringBuf s) {
+ if (Unquote && (NewUnquote ? TJsonPrettifier::MayUnquoteNew(s) : TJsonPrettifier::MayUnquoteOld(s))) {
+ Out.Slave << s;
+ } else {
+ Out.Slave << Quote;
+ NEscJ::EscapeJ<false, true>(s, Out.Slave, Safe, Unsafe);
+ Out.Slave << Quote;
+ }
+ }
+
+ bool OnString(const TStringBuf& s) override {
+ OnVal();
+ WriteString(s);
+ AfterVal();
+ return true;
+ }
+
+ bool OnOpen(char c) {
+ OnVal();
+ Level++;
+ Out.Hold(c);
+ return true;
+ }
+
+ bool OnOpenMap() override {
+ return OnOpen('{');
+ }
+
+ bool OnOpenArray() override {
+ return OnOpen('[');
+ }
+
+ bool OnMapKey(const TStringBuf& k) override {
+ OnVal();
+ WriteString(k);
+ WriteSpace(' ');
+ Out.Hold(':');
+ return true;
+ }
+
+ bool OnClose(char c) {
+ if (!Level)
+ return false;
+
+ Level--;
+
+ if (Out.Dirty && c == Out.Last) {
+ WriteSpace(' ');
+ } else {
+ Out.Revert();
+ Pad(true);
+ }
+
+ return true;
+ }
+
+ bool OnCloseMap() override {
+ if (!OnClose('{'))
+ return false;
+ Out.Write("}");
+ AfterVal();
+ return true;
+ }
+
+ bool OnCloseArray() override {
+ if (!OnClose('['))
+ return false;
+ Out.Write("]");
+ AfterVal();
+ return true;
+ }
+
+ bool OnEnd() override {
+ return !Level;
+ }
+ };
+
+ bool TJsonPrettifier::Prettify(TStringBuf in, IOutputStream& out) const {
+ TPrettifier p(out, *this);
+ if (Strict) {
+ TMemoryInput mIn(in.data(), in.size());
+ return ReadJson(&mIn, &p);
+ } else {
+ return ReadJsonFast(in, &p);
+ }
+ }
+
+ TString TJsonPrettifier::Prettify(TStringBuf in) const {
+ TStringStream s;
+ if (Prettify(in, s))
+ return s.Str();
+ return TString();
+ }
+
+}