diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/json/writer/json.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/json/writer/json.h')
-rw-r--r-- | library/cpp/json/writer/json.h | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/library/cpp/json/writer/json.h b/library/cpp/json/writer/json.h new file mode 100644 index 0000000000..0aae2531b9 --- /dev/null +++ b/library/cpp/json/writer/json.h @@ -0,0 +1,289 @@ +#pragma once + +#include <util/generic/noncopyable.h> +#include <util/generic/ptr.h> +#include <util/generic/string.h> +#include <util/generic/vector.h> +#include <util/generic/yexception.h> +#include <util/stream/str.h> +#include <util/string/cast.h> + +namespace NJson { + class TJsonValue; +} + +namespace NJsonWriter { + enum EJsonEntity : ui8 { + JE_OUTER_SPACE = 1, + JE_LIST, + JE_OBJECT, + JE_PAIR, + }; + + enum EHtmlEscapeMode { + HEM_ESCAPE_HTML = 1, // Use HTML escaping: < > & \/ + HEM_DONT_ESCAPE_HTML, // Use JSON escaping: \u003C \u003E \u0026 \/ + HEM_RELAXED, // Use JSON escaping: \u003C \u003E \u0026 / + HEM_UNSAFE, // Turn escaping off: < > & / + }; + + class TError: public yexception {}; + + class TValueContext; + class TPairContext; + class TAfterColonContext; + + struct TBufState { + bool NeedComma; + bool NeedNewline; + TVector<EJsonEntity> Stack; + }; + + class TBuf : TNonCopyable { + public: + TBuf(EHtmlEscapeMode mode = HEM_DONT_ESCAPE_HTML, IOutputStream* stream = nullptr); + + TValueContext WriteString(const TStringBuf& s, EHtmlEscapeMode hem); + TValueContext WriteString(const TStringBuf& s); + TValueContext WriteInt(int i); + TValueContext WriteLongLong(long long i); + TValueContext WriteULongLong(unsigned long long i); + TValueContext WriteFloat(float f, EFloatToStringMode mode = PREC_NDIGITS, int ndigits = 6); + TValueContext WriteDouble(double f, EFloatToStringMode mode = PREC_NDIGITS, int ndigits = 10); + TValueContext WriteBool(bool b); + TValueContext WriteNull(); + TValueContext WriteJsonValue(const NJson::TJsonValue* value, bool sortKeys = false, EFloatToStringMode mode = PREC_NDIGITS, int ndigits = 10); + + TValueContext BeginList(); + TBuf& EndList(); + + TPairContext BeginObject(); + TAfterColonContext WriteKey(const TStringBuf& key, EHtmlEscapeMode hem); + TAfterColonContext WriteKey(const TStringBuf& key); + TAfterColonContext UnsafeWriteKey(const TStringBuf& key); + bool KeyExpected() const { + return Stack.back() == JE_OBJECT; + } + + //! deprecated, do not use in new code + TAfterColonContext CompatWriteKeyWithoutQuotes(const TStringBuf& key); + + TBuf& EndObject(); + + /*** Indent the resulting JSON with spaces. + * By default (spaces==0) no formatting is done. */ + TBuf& SetIndentSpaces(int spaces) { + IndentSpaces = spaces; + return *this; + } + + /*** NaN and Inf are not valid json values, + * so if WriteNanAsString is set, writer would write string + * intead of throwing exception (default case) */ + TBuf& SetWriteNanAsString(bool writeNanAsString = true) { + WriteNanAsString = writeNanAsString; + return *this; + } + + /*** Return the string formed in the internal TStringStream. + * You may only call it if the `stream' parameter was NULL + * at construction time. */ + const TString& Str() const; + + /*** Dump and forget the string constructed so far. + * You may only call it if the `stream' parameter was NULL + * at construction time. */ + void FlushTo(IOutputStream* stream); + + /*** Write a literal string that represents a JSON value + * (string, number, object, array, bool, or null). + * + * Example: + * j.UnsafeWriteValue("[1, 2, 3, \"o'clock\", 4, \"o'clock rock\"]"); + * + * As in all of the Unsafe* functions, no escaping is done. */ + void UnsafeWriteValue(const TStringBuf& s); + void UnsafeWriteValue(const char* s, size_t len); + + /*** When in the context of an object, write a literal string + * that represents a key:value pair (or several pairs). + * + * Example: + * j.BeginObject(); + * j.UnsafeWritePair("\"adam\": \"male\", \"eve\": \"female\""); + * j.EndObject(); + * + * As in all of the Unsafe* functions, no escaping is done. */ + TPairContext UnsafeWritePair(const TStringBuf& s); + + /*** Copy the supplied string directly into the output stream. */ + void UnsafeWriteRawBytes(const TStringBuf& s); + void UnsafeWriteRawBytes(const char* c, size_t len); + + TBufState State() const; + void Reset(const TBufState& from); + void Reset(TBufState&& from); + + private: + void BeginValue(); + void EndValue(); + void BeginKey(); + void RawWriteChar(char c); + bool EscapedWriteChar(const char* b, const char* c, EHtmlEscapeMode hem); + void WriteBareString(const TStringBuf s, EHtmlEscapeMode hem); + void WriteComma(); + void PrintIndentation(bool closing); + void PrintWhitespaces(size_t count, bool prependWithNewLine); + void WriteHexEscape(unsigned char c); + + void StackPush(EJsonEntity e); + void StackPop(); + void CheckAndPop(EJsonEntity e); + EJsonEntity StackTop() const; + + template <class TFloat> + TValueContext WriteFloatImpl(TFloat f, EFloatToStringMode mode, int ndigits); + + private: + IOutputStream* Stream; + THolder<TStringStream> StringStream; + typedef TVector<const TString*> TKeys; + TKeys Keys; + + TVector<EJsonEntity> Stack; + bool NeedComma; + bool NeedNewline; + const EHtmlEscapeMode EscapeMode; + int IndentSpaces; + bool WriteNanAsString; + }; + + // Please don't try to instantiate the classes declared below this point. + + template <typename TOutContext> + class TValueWriter { + public: + TOutContext WriteNull(); + TOutContext WriteString(const TStringBuf&); + TOutContext WriteString(const TStringBuf& s, EHtmlEscapeMode hem); + TOutContext WriteInt(int); + TOutContext WriteLongLong(long long); + TOutContext WriteULongLong(unsigned long long); + TOutContext WriteBool(bool); + TOutContext WriteFloat(float); + TOutContext WriteFloat(float, EFloatToStringMode, int ndigits); + TOutContext WriteDouble(double); + TOutContext WriteDouble(double, EFloatToStringMode, int ndigits); + TOutContext WriteJsonValue(const NJson::TJsonValue* value, bool sortKeys = false); + TOutContext UnsafeWriteValue(const TStringBuf&); + + TValueContext BeginList(); + TPairContext BeginObject(); + + protected: + TValueWriter(TBuf& buf) + : Buf(buf) + { + } + friend class TBuf; + + protected: + TBuf& Buf; + }; + + class TValueContext: public TValueWriter<TValueContext> { + public: + TBuf& EndList() { + return Buf.EndList(); + } + TString Str() const { + return Buf.Str(); + } + + private: + TValueContext(TBuf& buf) + : TValueWriter<TValueContext>(buf) + { + } + friend class TBuf; + friend class TValueWriter<TValueContext>; + }; + + class TAfterColonContext: public TValueWriter<TPairContext> { + private: + TAfterColonContext(TBuf& iBuf) + : TValueWriter<TPairContext>(iBuf) + { + } + friend class TBuf; + friend class TPairContext; + }; + + class TPairContext { + public: + TAfterColonContext WriteKey(const TStringBuf& s, EHtmlEscapeMode hem) { + return Buf.WriteKey(s, hem); + } + TAfterColonContext WriteKey(const TStringBuf& s) { + return Buf.WriteKey(s); + } + TAfterColonContext UnsafeWriteKey(const TStringBuf& s) { + return Buf.UnsafeWriteKey(s); + } + TAfterColonContext CompatWriteKeyWithoutQuotes(const TStringBuf& s) { + return Buf.CompatWriteKeyWithoutQuotes(s); + } + TPairContext UnsafeWritePair(const TStringBuf& s) { + return Buf.UnsafeWritePair(s); + } + TBuf& EndObject() { + return Buf.EndObject(); + } + + private: + TPairContext(TBuf& buf) + : Buf(buf) + { + } + + friend class TBuf; + friend class TValueWriter<TPairContext>; + + private: + TBuf& Buf; + }; + +#define JSON_VALUE_WRITER_WRAP(function, params, args) \ + template <typename TOutContext> \ + TOutContext TValueWriter<TOutContext>::function params { \ + Buf.function args; \ + return TOutContext(Buf); \ + } + + JSON_VALUE_WRITER_WRAP(WriteNull, (), ()) + JSON_VALUE_WRITER_WRAP(WriteString, (const TStringBuf& arg), (arg)) + JSON_VALUE_WRITER_WRAP(WriteString, (const TStringBuf& s, EHtmlEscapeMode hem), (s, hem)) + JSON_VALUE_WRITER_WRAP(WriteInt, (int arg), (arg)) + JSON_VALUE_WRITER_WRAP(WriteLongLong, (long long arg), (arg)) + JSON_VALUE_WRITER_WRAP(WriteULongLong, (unsigned long long arg), (arg)) + JSON_VALUE_WRITER_WRAP(WriteBool, (bool arg), (arg)) + JSON_VALUE_WRITER_WRAP(WriteFloat, (float arg), (arg)) + JSON_VALUE_WRITER_WRAP(WriteFloat, (float arg, EFloatToStringMode mode, int ndigits), (arg, mode, ndigits)) + JSON_VALUE_WRITER_WRAP(WriteDouble, (double arg), (arg)) + JSON_VALUE_WRITER_WRAP(WriteDouble, (double arg, EFloatToStringMode mode, int ndigits), (arg, mode, ndigits)) + JSON_VALUE_WRITER_WRAP(WriteJsonValue, (const NJson::TJsonValue* value, bool sortKeys), (value, sortKeys)) + JSON_VALUE_WRITER_WRAP(UnsafeWriteValue, (const TStringBuf& arg), (arg)) +#undef JSON_VALUE_WRITER_WRAP + + template <typename TOutContext> + TValueContext TValueWriter<TOutContext>::BeginList() { + return Buf.BeginList(); + } + + template <typename TOutContext> + TPairContext TValueWriter<TOutContext>::BeginObject() { + return Buf.BeginObject(); + } + + TString WrapJsonToCallback(const TBuf& buf, TStringBuf callback); +} |