diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:17 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:17 +0300 |
commit | d3a398281c6fd1d3672036cb2d63f842d2cb28c5 (patch) | |
tree | dd4bd3ca0f36b817e96812825ffaf10d645803f2 /library/cpp/json/writer | |
parent | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (diff) | |
download | ydb-d3a398281c6fd1d3672036cb2d63f842d2cb28c5.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 2 of 2.
Diffstat (limited to 'library/cpp/json/writer')
-rw-r--r-- | library/cpp/json/writer/json.cpp | 902 | ||||
-rw-r--r-- | library/cpp/json/writer/json.h | 36 | ||||
-rw-r--r-- | library/cpp/json/writer/json_ut.cpp | 70 | ||||
-rw-r--r-- | library/cpp/json/writer/json_value.cpp | 1648 | ||||
-rw-r--r-- | library/cpp/json/writer/json_value.h | 448 | ||||
-rw-r--r-- | library/cpp/json/writer/json_value_ut.cpp | 24 | ||||
-rw-r--r-- | library/cpp/json/writer/ya.make | 4 |
7 files changed, 1566 insertions, 1566 deletions
diff --git a/library/cpp/json/writer/json.cpp b/library/cpp/json/writer/json.cpp index 6bad7cf3a9..02370c2d79 100644 --- a/library/cpp/json/writer/json.cpp +++ b/library/cpp/json/writer/json.cpp @@ -1,94 +1,94 @@ #include "json.h" - + #include <library/cpp/json/json_value.h> - + #include <util/string/cast.h> -#include <util/string/strspn.h> +#include <util/string/strspn.h> #include <util/generic/algorithm.h> #include <util/generic/ymath.h> -#include <util/generic/singleton.h> +#include <util/generic/singleton.h> namespace NJsonWriter { - TBuf::TBuf(EHtmlEscapeMode mode, IOutputStream* stream) - : Stream(stream) - , NeedComma(false) - , NeedNewline(false) - , EscapeMode(mode) - , IndentSpaces(0) - , WriteNanAsString(false) - { - Y_ASSERT(mode == HEM_DONT_ESCAPE_HTML || - mode == HEM_ESCAPE_HTML || - mode == HEM_RELAXED || - mode == HEM_UNSAFE); - if (!Stream) { - StringStream.Reset(new TStringStream); - Stream = StringStream.Get(); - } - - Stack.reserve(64); // should be enough for most cases - StackPush(JE_OUTER_SPACE); - } - - static const char* EntityToStr(EJsonEntity e) { - switch (e) { - case JE_OUTER_SPACE: - return "JE_OUTER_SPACE"; - case JE_LIST: - return "JE_LIST"; - case JE_OBJECT: - return "JE_OBJECT"; - case JE_PAIR: - return "JE_PAIR"; - default: - return "JE_unknown"; - } - } - - inline void TBuf::StackPush(EJsonEntity e) { - Stack.push_back(e); - } - - inline EJsonEntity TBuf::StackTop() const { - return Stack.back(); - } - - inline void TBuf::StackPop() { - Y_ASSERT(!Stack.empty()); - const EJsonEntity current = StackTop(); - Stack.pop_back(); - switch (current) { - case JE_OUTER_SPACE: - ythrow TError() << "JSON writer: stack empty"; - case JE_LIST: - PrintIndentation(true); - RawWriteChar(']'); - break; - case JE_OBJECT: - PrintIndentation(true); - RawWriteChar('}'); - break; - case JE_PAIR: - break; - } - NeedComma = true; - NeedNewline = true; - } - - inline void TBuf::CheckAndPop(EJsonEntity e) { - if (Y_UNLIKELY(StackTop() != e)) { - ythrow TError() << "JSON writer: unexpected value " - << EntityToStr(StackTop()) << " on the stack"; - } - StackPop(); - } - - void TBuf::PrintIndentation(bool closing) { - if (!IndentSpaces) - return; - const int indentation = IndentSpaces * (Stack.size() - 1); - if (!indentation && !closing) - return; + TBuf::TBuf(EHtmlEscapeMode mode, IOutputStream* stream) + : Stream(stream) + , NeedComma(false) + , NeedNewline(false) + , EscapeMode(mode) + , IndentSpaces(0) + , WriteNanAsString(false) + { + Y_ASSERT(mode == HEM_DONT_ESCAPE_HTML || + mode == HEM_ESCAPE_HTML || + mode == HEM_RELAXED || + mode == HEM_UNSAFE); + if (!Stream) { + StringStream.Reset(new TStringStream); + Stream = StringStream.Get(); + } + + Stack.reserve(64); // should be enough for most cases + StackPush(JE_OUTER_SPACE); + } + + static const char* EntityToStr(EJsonEntity e) { + switch (e) { + case JE_OUTER_SPACE: + return "JE_OUTER_SPACE"; + case JE_LIST: + return "JE_LIST"; + case JE_OBJECT: + return "JE_OBJECT"; + case JE_PAIR: + return "JE_PAIR"; + default: + return "JE_unknown"; + } + } + + inline void TBuf::StackPush(EJsonEntity e) { + Stack.push_back(e); + } + + inline EJsonEntity TBuf::StackTop() const { + return Stack.back(); + } + + inline void TBuf::StackPop() { + Y_ASSERT(!Stack.empty()); + const EJsonEntity current = StackTop(); + Stack.pop_back(); + switch (current) { + case JE_OUTER_SPACE: + ythrow TError() << "JSON writer: stack empty"; + case JE_LIST: + PrintIndentation(true); + RawWriteChar(']'); + break; + case JE_OBJECT: + PrintIndentation(true); + RawWriteChar('}'); + break; + case JE_PAIR: + break; + } + NeedComma = true; + NeedNewline = true; + } + + inline void TBuf::CheckAndPop(EJsonEntity e) { + if (Y_UNLIKELY(StackTop() != e)) { + ythrow TError() << "JSON writer: unexpected value " + << EntityToStr(StackTop()) << " on the stack"; + } + StackPop(); + } + + void TBuf::PrintIndentation(bool closing) { + if (!IndentSpaces) + return; + const int indentation = IndentSpaces * (Stack.size() - 1); + if (!indentation && !closing) + return; PrintWhitespaces(Max(0, indentation), true); } @@ -107,258 +107,258 @@ namespace NJsonWriter { } while (count > 0); } - inline void TBuf::WriteComma() { - if (NeedComma) { - RawWriteChar(','); - } - NeedComma = true; - - if (NeedNewline) { - PrintIndentation(false); - } - NeedNewline = true; - } - - inline void TBuf::BeginValue() { - if (Y_UNLIKELY(KeyExpected())) { - ythrow TError() << "JSON writer: value written, " - "but expected a key:value pair"; - } - WriteComma(); - } - - inline void TBuf::BeginKey() { - if (Y_UNLIKELY(!KeyExpected())) { - ythrow TError() << "JSON writer: key written outside of an object"; - } - WriteComma(); - StackPush(JE_PAIR); - NeedComma = false; - NeedNewline = false; - } - - inline void TBuf::EndValue() { - if (StackTop() == JE_PAIR) { - StackPop(); - } - } - - TValueContext TBuf::BeginList() { - NeedNewline = true; - BeginValue(); - RawWriteChar('['); - StackPush(JE_LIST); - NeedComma = false; - return TValueContext(*this); - } - - TPairContext TBuf::BeginObject() { - NeedNewline = true; - BeginValue(); - RawWriteChar('{'); - StackPush(JE_OBJECT); - NeedComma = false; - return TPairContext(*this); - } - - TAfterColonContext TBuf::UnsafeWriteKey(const TStringBuf& s) { - BeginKey(); - RawWriteChar('"'); - UnsafeWriteRawBytes(s); - UnsafeWriteRawBytes("\":", 2); - return TAfterColonContext(*this); - } - - TAfterColonContext TBuf::WriteKey(const TStringBuf& s) { - // use the default escaping mode for this object - return WriteKey(s, EscapeMode); - } - - TAfterColonContext TBuf::WriteKey(const TStringBuf& s, EHtmlEscapeMode hem) { - BeginKey(); - WriteBareString(s, hem); - RawWriteChar(':'); - return TAfterColonContext(*this); - } - - TAfterColonContext TBuf::CompatWriteKeyWithoutQuotes(const TStringBuf& s) { - BeginKey(); - Y_ASSERT(AllOf(s, [](char x) { return 'a' <= x && x <= 'z'; })); - UnsafeWriteRawBytes(s); - RawWriteChar(':'); - return TAfterColonContext(*this); - } - - TBuf& TBuf::EndList() { - CheckAndPop(JE_LIST); - EndValue(); - return *this; - } - - TBuf& TBuf::EndObject() { - CheckAndPop(JE_OBJECT); - EndValue(); - return *this; - } - - TValueContext TBuf::WriteString(const TStringBuf& s) { - // use the default escaping mode for this object - return WriteString(s, EscapeMode); - } - - TValueContext TBuf::WriteString(const TStringBuf& s, EHtmlEscapeMode hem) { - BeginValue(); - WriteBareString(s, hem); - EndValue(); - return TValueContext(*this); - } - - TValueContext TBuf::WriteNull() { + inline void TBuf::WriteComma() { + if (NeedComma) { + RawWriteChar(','); + } + NeedComma = true; + + if (NeedNewline) { + PrintIndentation(false); + } + NeedNewline = true; + } + + inline void TBuf::BeginValue() { + if (Y_UNLIKELY(KeyExpected())) { + ythrow TError() << "JSON writer: value written, " + "but expected a key:value pair"; + } + WriteComma(); + } + + inline void TBuf::BeginKey() { + if (Y_UNLIKELY(!KeyExpected())) { + ythrow TError() << "JSON writer: key written outside of an object"; + } + WriteComma(); + StackPush(JE_PAIR); + NeedComma = false; + NeedNewline = false; + } + + inline void TBuf::EndValue() { + if (StackTop() == JE_PAIR) { + StackPop(); + } + } + + TValueContext TBuf::BeginList() { + NeedNewline = true; + BeginValue(); + RawWriteChar('['); + StackPush(JE_LIST); + NeedComma = false; + return TValueContext(*this); + } + + TPairContext TBuf::BeginObject() { + NeedNewline = true; + BeginValue(); + RawWriteChar('{'); + StackPush(JE_OBJECT); + NeedComma = false; + return TPairContext(*this); + } + + TAfterColonContext TBuf::UnsafeWriteKey(const TStringBuf& s) { + BeginKey(); + RawWriteChar('"'); + UnsafeWriteRawBytes(s); + UnsafeWriteRawBytes("\":", 2); + return TAfterColonContext(*this); + } + + TAfterColonContext TBuf::WriteKey(const TStringBuf& s) { + // use the default escaping mode for this object + return WriteKey(s, EscapeMode); + } + + TAfterColonContext TBuf::WriteKey(const TStringBuf& s, EHtmlEscapeMode hem) { + BeginKey(); + WriteBareString(s, hem); + RawWriteChar(':'); + return TAfterColonContext(*this); + } + + TAfterColonContext TBuf::CompatWriteKeyWithoutQuotes(const TStringBuf& s) { + BeginKey(); + Y_ASSERT(AllOf(s, [](char x) { return 'a' <= x && x <= 'z'; })); + UnsafeWriteRawBytes(s); + RawWriteChar(':'); + return TAfterColonContext(*this); + } + + TBuf& TBuf::EndList() { + CheckAndPop(JE_LIST); + EndValue(); + return *this; + } + + TBuf& TBuf::EndObject() { + CheckAndPop(JE_OBJECT); + EndValue(); + return *this; + } + + TValueContext TBuf::WriteString(const TStringBuf& s) { + // use the default escaping mode for this object + return WriteString(s, EscapeMode); + } + + TValueContext TBuf::WriteString(const TStringBuf& s, EHtmlEscapeMode hem) { + BeginValue(); + WriteBareString(s, hem); + EndValue(); + return TValueContext(*this); + } + + TValueContext TBuf::WriteNull() { UnsafeWriteValue(TStringBuf("null")); - return TValueContext(*this); - } + return TValueContext(*this); + } - TValueContext TBuf::WriteBool(bool b) { + TValueContext TBuf::WriteBool(bool b) { constexpr TStringBuf trueVal = "true"; constexpr TStringBuf falseVal = "false"; UnsafeWriteValue(b ? trueVal : falseVal); - return TValueContext(*this); - } - - TValueContext TBuf::WriteInt(int i) { - char buf[22]; // enough to hold any 64-bit number - size_t len = ToString(i, buf, sizeof(buf)); - UnsafeWriteValue(buf, len); - return TValueContext(*this); - } - - TValueContext TBuf::WriteLongLong(long long i) { - static_assert(sizeof(long long) <= 8, "expect sizeof(long long) <= 8"); - char buf[22]; // enough to hold any 64-bit number - size_t len = ToString(i, buf, sizeof(buf)); - UnsafeWriteValue(buf, len); - return TValueContext(*this); - } - - TValueContext TBuf::WriteULongLong(unsigned long long i) { - char buf[22]; // enough to hold any 64-bit number - size_t len = ToString(i, buf, sizeof(buf)); - UnsafeWriteValue(buf, len); - return TValueContext(*this); - } - - template <class TFloat> - TValueContext TBuf::WriteFloatImpl(TFloat f, EFloatToStringMode mode, int ndigits) { - char buf[512]; // enough to hold most floats, the same buffer is used in FloatToString implementation - if (Y_UNLIKELY(!IsValidFloat(f))) { - if (WriteNanAsString) { - const size_t size = FloatToString(f, buf, Y_ARRAY_SIZE(buf)); - WriteString(TStringBuf(buf, size)); - return TValueContext(*this); - } else { - ythrow TError() << "JSON writer: invalid float value: " << FloatToString(f); - } + return TValueContext(*this); + } + + TValueContext TBuf::WriteInt(int i) { + char buf[22]; // enough to hold any 64-bit number + size_t len = ToString(i, buf, sizeof(buf)); + UnsafeWriteValue(buf, len); + return TValueContext(*this); + } + + TValueContext TBuf::WriteLongLong(long long i) { + static_assert(sizeof(long long) <= 8, "expect sizeof(long long) <= 8"); + char buf[22]; // enough to hold any 64-bit number + size_t len = ToString(i, buf, sizeof(buf)); + UnsafeWriteValue(buf, len); + return TValueContext(*this); + } + + TValueContext TBuf::WriteULongLong(unsigned long long i) { + char buf[22]; // enough to hold any 64-bit number + size_t len = ToString(i, buf, sizeof(buf)); + UnsafeWriteValue(buf, len); + return TValueContext(*this); + } + + template <class TFloat> + TValueContext TBuf::WriteFloatImpl(TFloat f, EFloatToStringMode mode, int ndigits) { + char buf[512]; // enough to hold most floats, the same buffer is used in FloatToString implementation + if (Y_UNLIKELY(!IsValidFloat(f))) { + if (WriteNanAsString) { + const size_t size = FloatToString(f, buf, Y_ARRAY_SIZE(buf)); + WriteString(TStringBuf(buf, size)); + return TValueContext(*this); + } else { + ythrow TError() << "JSON writer: invalid float value: " << FloatToString(f); + } } - size_t len = FloatToString(f, buf, Y_ARRAY_SIZE(buf), mode, ndigits); - UnsafeWriteValue(buf, len); - return TValueContext(*this); - } - - TValueContext TBuf::WriteFloat(float f, EFloatToStringMode mode, int ndigits) { - return WriteFloatImpl(f, mode, ndigits); - } - - TValueContext TBuf::WriteDouble(double f, EFloatToStringMode mode, int ndigits) { - return WriteFloatImpl(f, mode, ndigits); - } - - namespace { - struct TFinder: public TCompactStrSpn { - inline TFinder() - : TCompactStrSpn("\xe2\\\"\b\n\f\r\t<>&\'/") - { - for (ui8 ch = 0; ch < 0x20; ++ch) { - Set(ch); - } - } - }; - } - - inline void TBuf::WriteBareString(const TStringBuf s, EHtmlEscapeMode hem) { - RawWriteChar('"'); - const auto& specialChars = *Singleton<TFinder>(); - const char* b = s.begin(); - const char* e = s.end(); - const char* i = b; - while ((i = specialChars.FindFirstOf(i, e)) != e) { - // U+2028 (line separator) and U+2029 (paragraph separator) are valid string - // contents in JSON, but are treated as line breaks in JavaScript, breaking JSONP. - // In UTF-8, U+2028 is "\xe2\x80\xa8" and U+2029 is "\xe2\x80\xa9". - if (Y_UNLIKELY(e - i >= 3 && i[0] == '\xe2' && i[1] == '\x80' && (i[2] | 1) == '\xa9')) { - UnsafeWriteRawBytes(b, i - b); - UnsafeWriteRawBytes(i[2] == '\xa9' ? "\\u2029" : "\\u2028", 6); - b = i = i + 3; - } else if (EscapedWriteChar(b, i, hem)) { - b = ++i; - } else { - ++i; - } - } - UnsafeWriteRawBytes(b, e - b); - RawWriteChar('"'); - } - - inline void TBuf::RawWriteChar(char c) { - Stream->Write(c); - } - - void TBuf::WriteHexEscape(unsigned char c) { - Y_ASSERT(c < 0x80); - UnsafeWriteRawBytes("\\u00", 4); - static const char hexDigits[] = "0123456789ABCDEF"; - RawWriteChar(hexDigits[(c & 0xf0) >> 4]); - RawWriteChar(hexDigits[(c & 0x0f)]); - } - -#define MATCH(sym, string) \ - case sym: \ - UnsafeWriteRawBytes(beg, cur - beg); \ + size_t len = FloatToString(f, buf, Y_ARRAY_SIZE(buf), mode, ndigits); + UnsafeWriteValue(buf, len); + return TValueContext(*this); + } + + TValueContext TBuf::WriteFloat(float f, EFloatToStringMode mode, int ndigits) { + return WriteFloatImpl(f, mode, ndigits); + } + + TValueContext TBuf::WriteDouble(double f, EFloatToStringMode mode, int ndigits) { + return WriteFloatImpl(f, mode, ndigits); + } + + namespace { + struct TFinder: public TCompactStrSpn { + inline TFinder() + : TCompactStrSpn("\xe2\\\"\b\n\f\r\t<>&\'/") + { + for (ui8 ch = 0; ch < 0x20; ++ch) { + Set(ch); + } + } + }; + } + + inline void TBuf::WriteBareString(const TStringBuf s, EHtmlEscapeMode hem) { + RawWriteChar('"'); + const auto& specialChars = *Singleton<TFinder>(); + const char* b = s.begin(); + const char* e = s.end(); + const char* i = b; + while ((i = specialChars.FindFirstOf(i, e)) != e) { + // U+2028 (line separator) and U+2029 (paragraph separator) are valid string + // contents in JSON, but are treated as line breaks in JavaScript, breaking JSONP. + // In UTF-8, U+2028 is "\xe2\x80\xa8" and U+2029 is "\xe2\x80\xa9". + if (Y_UNLIKELY(e - i >= 3 && i[0] == '\xe2' && i[1] == '\x80' && (i[2] | 1) == '\xa9')) { + UnsafeWriteRawBytes(b, i - b); + UnsafeWriteRawBytes(i[2] == '\xa9' ? "\\u2029" : "\\u2028", 6); + b = i = i + 3; + } else if (EscapedWriteChar(b, i, hem)) { + b = ++i; + } else { + ++i; + } + } + UnsafeWriteRawBytes(b, e - b); + RawWriteChar('"'); + } + + inline void TBuf::RawWriteChar(char c) { + Stream->Write(c); + } + + void TBuf::WriteHexEscape(unsigned char c) { + Y_ASSERT(c < 0x80); + UnsafeWriteRawBytes("\\u00", 4); + static const char hexDigits[] = "0123456789ABCDEF"; + RawWriteChar(hexDigits[(c & 0xf0) >> 4]); + RawWriteChar(hexDigits[(c & 0x0f)]); + } + +#define MATCH(sym, string) \ + case sym: \ + UnsafeWriteRawBytes(beg, cur - beg); \ UnsafeWriteRawBytes(TStringBuf(string)); \ - return true - - inline bool TBuf::EscapedWriteChar(const char* beg, const char* cur, EHtmlEscapeMode hem) { - unsigned char c = *cur; - if (hem == HEM_ESCAPE_HTML) { - switch (c) { - MATCH('"', """); - MATCH('\'', "'"); - MATCH('<', "<"); - MATCH('>', ">"); - MATCH('&', "&"); - } - //for other characters, we fall through to the non-HTML-escaped part + return true + + inline bool TBuf::EscapedWriteChar(const char* beg, const char* cur, EHtmlEscapeMode hem) { + unsigned char c = *cur; + if (hem == HEM_ESCAPE_HTML) { + switch (c) { + MATCH('"', """); + MATCH('\'', "'"); + MATCH('<', "<"); + MATCH('>', ">"); + MATCH('&', "&"); + } + //for other characters, we fall through to the non-HTML-escaped part } - if (hem == HEM_RELAXED && c == '/') - return false; - - if (hem != HEM_UNSAFE) { - switch (c) { - case '/': - UnsafeWriteRawBytes(beg, cur - beg); - UnsafeWriteRawBytes("\\/", 2); - return true; - case '<': - case '>': - case '\'': - UnsafeWriteRawBytes(beg, cur - beg); - WriteHexEscape(c); - return true; - } - // for other characters, fall through to the non-escaped part + if (hem == HEM_RELAXED && c == '/') + return false; + + if (hem != HEM_UNSAFE) { + switch (c) { + case '/': + UnsafeWriteRawBytes(beg, cur - beg); + UnsafeWriteRawBytes("\\/", 2); + return true; + case '<': + case '>': + case '\'': + UnsafeWriteRawBytes(beg, cur - beg); + WriteHexEscape(c); + return true; + } + // for other characters, fall through to the non-escaped part } - switch (c) { + switch (c) { MATCH('"', "\\\""); MATCH('\\', "\\\\"); MATCH('\b', "\\b"); @@ -366,152 +366,152 @@ namespace NJsonWriter { MATCH('\n', "\\n"); MATCH('\r', "\\r"); MATCH('\t', "\\t"); - } - if (c < 0x20) { - UnsafeWriteRawBytes(beg, cur - beg); - WriteHexEscape(c); - return true; - } - - return false; + } + if (c < 0x20) { + UnsafeWriteRawBytes(beg, cur - beg); + WriteHexEscape(c); + return true; + } + + return false; } #undef MATCH - static bool LessStrPtr(const TString* a, const TString* b) { - return *a < *b; - } + static bool LessStrPtr(const TString* a, const TString* b) { + return *a < *b; + } TValueContext TBuf::WriteJsonValue(const NJson::TJsonValue* v, bool sortKeys, EFloatToStringMode mode, int ndigits) { - using namespace NJson; - switch (v->GetType()) { - default: - case JSON_NULL: - WriteNull(); - break; - case JSON_BOOLEAN: - WriteBool(v->GetBoolean()); - break; - case JSON_DOUBLE: + using namespace NJson; + switch (v->GetType()) { + default: + case JSON_NULL: + WriteNull(); + break; + case JSON_BOOLEAN: + WriteBool(v->GetBoolean()); + break; + case JSON_DOUBLE: WriteDouble(v->GetDouble(), mode, ndigits); - break; - case JSON_INTEGER: - WriteLongLong(v->GetInteger()); - break; - case JSON_UINTEGER: - WriteULongLong(v->GetUInteger()); - break; - case JSON_STRING: - WriteString(v->GetString()); - break; - case JSON_ARRAY: { - BeginList(); - const TJsonValue::TArray& arr = v->GetArray(); - for (const auto& it : arr) + break; + case JSON_INTEGER: + WriteLongLong(v->GetInteger()); + break; + case JSON_UINTEGER: + WriteULongLong(v->GetUInteger()); + break; + case JSON_STRING: + WriteString(v->GetString()); + break; + case JSON_ARRAY: { + BeginList(); + const TJsonValue::TArray& arr = v->GetArray(); + for (const auto& it : arr) WriteJsonValue(&it, sortKeys, mode, ndigits); - EndList(); - break; + EndList(); + break; } - case JSON_MAP: { - BeginObject(); - const TJsonValue::TMapType& map = v->GetMap(); - if (sortKeys) { - const size_t oldsz = Keys.size(); - Keys.reserve(map.size() + oldsz); - for (const auto& it : map) { - Keys.push_back(&(it.first)); - } - Sort(Keys.begin() + oldsz, Keys.end(), LessStrPtr); - for (size_t i = oldsz, sz = Keys.size(); i < sz; ++i) { - TJsonValue::TMapType::const_iterator kv = map.find(*Keys[i]); - WriteKey(kv->first); + case JSON_MAP: { + BeginObject(); + const TJsonValue::TMapType& map = v->GetMap(); + if (sortKeys) { + const size_t oldsz = Keys.size(); + Keys.reserve(map.size() + oldsz); + for (const auto& it : map) { + Keys.push_back(&(it.first)); + } + Sort(Keys.begin() + oldsz, Keys.end(), LessStrPtr); + for (size_t i = oldsz, sz = Keys.size(); i < sz; ++i) { + TJsonValue::TMapType::const_iterator kv = map.find(*Keys[i]); + WriteKey(kv->first); WriteJsonValue(&kv->second, sortKeys, mode, ndigits); - } - Keys.resize(oldsz); - } else { - for (const auto& it : map) { - WriteKey(it.first); + } + Keys.resize(oldsz); + } else { + for (const auto& it : map) { + WriteKey(it.first); WriteJsonValue(&it.second, sortKeys, mode, ndigits); - } - } - EndObject(); - break; + } + } + EndObject(); + break; } } - return TValueContext(*this); + return TValueContext(*this); } - - TPairContext TBuf::UnsafeWritePair(const TStringBuf& s) { - if (Y_UNLIKELY(StackTop() != JE_OBJECT)) { - ythrow TError() << "JSON writer: key:value pair written outside of an object"; - } - WriteComma(); - UnsafeWriteRawBytes(s); - return TPairContext(*this); + + TPairContext TBuf::UnsafeWritePair(const TStringBuf& s) { + if (Y_UNLIKELY(StackTop() != JE_OBJECT)) { + ythrow TError() << "JSON writer: key:value pair written outside of an object"; + } + WriteComma(); + UnsafeWriteRawBytes(s); + return TPairContext(*this); } - void TBuf::UnsafeWriteValue(const TStringBuf& s) { - BeginValue(); - UnsafeWriteRawBytes(s); - EndValue(); + void TBuf::UnsafeWriteValue(const TStringBuf& s) { + BeginValue(); + UnsafeWriteRawBytes(s); + EndValue(); } - void TBuf::UnsafeWriteValue(const char* s, size_t len) { - BeginValue(); - UnsafeWriteRawBytes(s, len); - EndValue(); - } + void TBuf::UnsafeWriteValue(const char* s, size_t len) { + BeginValue(); + UnsafeWriteRawBytes(s, len); + EndValue(); + } - void TBuf::UnsafeWriteRawBytes(const char* src, size_t len) { - Stream->Write(src, len); - } + void TBuf::UnsafeWriteRawBytes(const char* src, size_t len) { + Stream->Write(src, len); + } - void TBuf::UnsafeWriteRawBytes(const TStringBuf& s) { + void TBuf::UnsafeWriteRawBytes(const TStringBuf& s) { UnsafeWriteRawBytes(s.data(), s.size()); - } - - const TString& TBuf::Str() const { - if (!StringStream) { - ythrow TError() << "JSON writer: Str() called " - "but writing to an external stream"; - } - if (!(Stack.size() == 1 && StackTop() == JE_OUTER_SPACE)) { - ythrow TError() << "JSON writer: incomplete object converted to string"; - } - return StringStream->Str(); - } - - void TBuf::FlushTo(IOutputStream* stream) { - if (!StringStream) { - ythrow TError() << "JSON writer: FlushTo() called " - "but writing to an external stream"; - } - stream->Write(StringStream->Str()); - StringStream->Clear(); - } - - TString WrapJsonToCallback(const TBuf& buf, TStringBuf callback) { - if (!callback) { - return buf.Str(); - } else { - return TString::Join(callback, "(", buf.Str(), ")"); - } - } - - TBufState TBuf::State() const { - return TBufState{NeedComma, NeedNewline, Stack}; - } - - void TBuf::Reset(const TBufState& from) { - NeedComma = from.NeedComma; - NeedNewline = from.NeedNewline; - Stack = from.Stack; - } - - void TBuf::Reset(TBufState&& from) { - NeedComma = from.NeedComma; - NeedNewline = from.NeedNewline; - Stack.swap(from.Stack); - } + } + + const TString& TBuf::Str() const { + if (!StringStream) { + ythrow TError() << "JSON writer: Str() called " + "but writing to an external stream"; + } + if (!(Stack.size() == 1 && StackTop() == JE_OUTER_SPACE)) { + ythrow TError() << "JSON writer: incomplete object converted to string"; + } + return StringStream->Str(); + } + + void TBuf::FlushTo(IOutputStream* stream) { + if (!StringStream) { + ythrow TError() << "JSON writer: FlushTo() called " + "but writing to an external stream"; + } + stream->Write(StringStream->Str()); + StringStream->Clear(); + } + + TString WrapJsonToCallback(const TBuf& buf, TStringBuf callback) { + if (!callback) { + return buf.Str(); + } else { + return TString::Join(callback, "(", buf.Str(), ")"); + } + } + + TBufState TBuf::State() const { + return TBufState{NeedComma, NeedNewline, Stack}; + } + + void TBuf::Reset(const TBufState& from) { + NeedComma = from.NeedComma; + NeedNewline = from.NeedNewline; + Stack = from.Stack; + } + + void TBuf::Reset(TBufState&& from) { + NeedComma = from.NeedComma; + NeedNewline = from.NeedNewline; + Stack.swap(from.Stack); + } } diff --git a/library/cpp/json/writer/json.h b/library/cpp/json/writer/json.h index eca04a510a..0aae2531b9 100644 --- a/library/cpp/json/writer/json.h +++ b/library/cpp/json/writer/json.h @@ -39,7 +39,7 @@ namespace NJsonWriter { TVector<EJsonEntity> Stack; }; - class TBuf : TNonCopyable { + class TBuf : TNonCopyable { public: TBuf(EHtmlEscapeMode mode = HEM_DONT_ESCAPE_HTML, IOutputStream* stream = nullptr); @@ -183,8 +183,8 @@ namespace NJsonWriter { protected: TValueWriter(TBuf& buf) : Buf(buf) - { - } + { + } friend class TBuf; protected: @@ -196,25 +196,25 @@ namespace NJsonWriter { TBuf& EndList() { return Buf.EndList(); } - TString Str() const { - return Buf.Str(); - } - + 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) - { - } + TAfterColonContext(TBuf& iBuf) + : TValueWriter<TPairContext>(iBuf) + { + } friend class TBuf; friend class TPairContext; }; @@ -275,15 +275,15 @@ namespace NJsonWriter { JSON_VALUE_WRITER_WRAP(UnsafeWriteValue, (const TStringBuf& arg), (arg)) #undef JSON_VALUE_WRITER_WRAP - template <typename TOutContext> - TValueContext TValueWriter<TOutContext>::BeginList() { + template <typename TOutContext> + TValueContext TValueWriter<TOutContext>::BeginList() { return Buf.BeginList(); } - template <typename TOutContext> - TPairContext TValueWriter<TOutContext>::BeginObject() { + template <typename TOutContext> + TPairContext TValueWriter<TOutContext>::BeginObject() { return Buf.BeginObject(); } - TString WrapJsonToCallback(const TBuf& buf, TStringBuf callback); + TString WrapJsonToCallback(const TBuf& buf, TStringBuf callback); } diff --git a/library/cpp/json/writer/json_ut.cpp b/library/cpp/json/writer/json_ut.cpp index e8d0be3566..9980555683 100644 --- a/library/cpp/json/writer/json_ut.cpp +++ b/library/cpp/json/writer/json_ut.cpp @@ -16,12 +16,12 @@ Y_UNIT_TEST_SUITE(JsonWriter) { .UnsafeWritePair("\"xk\":13") .WriteKey("key2") .BeginList() - .BeginObject() - .EndObject() - .BeginObject() - .EndObject() + .BeginObject() + .EndObject() + .BeginObject() + .EndObject() .EndList() - .EndObject(); + .EndObject(); w.WriteInt(43); w.UnsafeWriteValue("\"x\""); w.WriteString("..."); @@ -75,11 +75,11 @@ Y_UNIT_TEST_SUITE(JsonWriter) { Y_UNIT_TEST(BareKey) { NJsonWriter::TBuf w; w.BeginObject() - .CompatWriteKeyWithoutQuotes("p") - .WriteInt(1) - .CompatWriteKeyWithoutQuotes("n") - .WriteInt(0) - .EndObject(); + .CompatWriteKeyWithoutQuotes("p") + .WriteInt(1) + .CompatWriteKeyWithoutQuotes("n") + .WriteInt(0) + .EndObject(); TString ws = w.Str(); const char* exp = "{p:1,n:0}"; UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp); @@ -108,12 +108,12 @@ Y_UNIT_TEST_SUITE(JsonWriter) { .WriteInt(1) .WriteString("hello") .BeginObject() - .WriteKey("abc") - .WriteInt(3) - .WriteKey("def") - .WriteInt(4) + .WriteKey("abc") + .WriteInt(3) + .WriteKey("def") + .WriteInt(4) .EndObject() - .EndList(); + .EndList(); const char* exp = "[\n" " 1,\n" " \"hello\",\n" @@ -196,12 +196,12 @@ Y_UNIT_TEST_SUITE(JsonWriter) { .WriteFloat(244.13854, PREC_NDIGITS, 4) .WriteFloat(10385.8324, PREC_POINT_DIGITS, 2) .BeginObject() - .WriteKey("1") - .WriteDouble(1111.71, PREC_POINT_DIGITS, 0) - .WriteKey("2") - .WriteDouble(1111.71, PREC_NDIGITS, 1) + .WriteKey("1") + .WriteDouble(1111.71, PREC_POINT_DIGITS, 0) + .WriteKey("2") + .WriteDouble(1111.71, PREC_NDIGITS, 1) .EndObject() - .EndList(); + .EndList(); const char exp[] = "[0.123457,0.1234567899,0.316,244.1,10385.83,{\"1\":1112,\"2\":1e+03}]"; UNIT_ASSERT_STRINGS_EQUAL(exp, buf.Str()); } @@ -238,17 +238,17 @@ Y_UNIT_TEST_SUITE(JsonWriter) { buf.SetWriteNanAsString(); buf.BeginObject() - .WriteKey("nanvalue") - .WriteFloat(std::numeric_limits<double>::quiet_NaN()) - .WriteKey("infvalue") - .WriteFloat(std::numeric_limits<double>::infinity()) - .WriteKey("minus_infvalue") - .WriteFloat(-std::numeric_limits<float>::infinity()) + .WriteKey("nanvalue") + .WriteFloat(std::numeric_limits<double>::quiet_NaN()) + .WriteKey("infvalue") + .WriteFloat(std::numeric_limits<double>::infinity()) + .WriteKey("minus_infvalue") + .WriteFloat(-std::numeric_limits<float>::infinity()) .WriteKey("l") - .BeginList() - .WriteFloat(std::numeric_limits<float>::quiet_NaN()) - .EndList() - .EndObject(); + .BeginList() + .WriteFloat(std::numeric_limits<float>::quiet_NaN()) + .EndList() + .EndObject(); UNIT_ASSERT_STRINGS_EQUAL(buf.Str(), R"raw_json({"nanvalue":"nan","infvalue":"inf","minus_infvalue":"-inf","l":["nan"]})raw_json"); } @@ -256,11 +256,11 @@ Y_UNIT_TEST_SUITE(JsonWriter) { { NJsonWriter::TBuf buf; buf.BeginObject() - .WriteKey("<>&") - .WriteString("Ololo") - .UnsafeWriteKey("<>&") - .WriteString("Ololo2") - .EndObject(); + .WriteKey("<>&") + .WriteString("Ololo") + .UnsafeWriteKey("<>&") + .WriteString("Ololo2") + .EndObject(); UNIT_ASSERT_STRINGS_EQUAL(buf.Str(), R"({"\u003C\u003E&":"Ololo","<>&":"Ololo2"})"); } diff --git a/library/cpp/json/writer/json_value.cpp b/library/cpp/json/writer/json_value.cpp index 4e85a6bc08..c61e8d1dc4 100644 --- a/library/cpp/json/writer/json_value.cpp +++ b/library/cpp/json/writer/json_value.cpp @@ -1,12 +1,12 @@ #include "json_value.h" #include "json.h" -#include <util/generic/ymath.h> +#include <util/generic/ymath.h> #include <util/generic/ylimits.h> #include <util/generic/utility.h> -#include <util/generic/singleton.h> +#include <util/generic/singleton.h> #include <util/stream/str.h> -#include <util/stream/output.h> +#include <util/stream/output.h> #include <util/string/cast.h> #include <util/string/type.h> #include <util/string/vector.h> @@ -59,7 +59,7 @@ AreJsonArraysEqual(const NJson::TJsonValue& lhs, const NJson::TJsonValue& rhs) { return false; for (TArray::const_iterator lhsIt = lhsArray.begin(), rhsIt = rhsArray.begin(); - lhsIt != lhsArray.end(); ++lhsIt, ++rhsIt) { + lhsIt != lhsArray.end(); ++lhsIt, ++rhsIt) { if (*lhsIt != *rhsIt) return false; } @@ -68,926 +68,926 @@ AreJsonArraysEqual(const NJson::TJsonValue& lhs, const NJson::TJsonValue& rhs) { } namespace NJson { - const TJsonValue TJsonValue::UNDEFINED{}; - - TJsonValue::TJsonValue(const EJsonValueType type) { - SetType(type); - } - - TJsonValue::TJsonValue(TJsonValue&& vval) noexcept - : Type(JSON_UNDEFINED) - { - vval.SwapWithUndefined(*this); - Zero(vval.Value); - } - - TJsonValue::TJsonValue(const TJsonValue& val) - : Type(val.Type) - { - switch (Type) { - case JSON_STRING: - new (&Value.String) TString(val.GetString()); - break; - case JSON_MAP: - Value.Map = new TMapType(val.GetMap()); - break; - case JSON_ARRAY: - Value.Array = new TArray(val.GetArray()); - break; - case JSON_UNDEFINED: - case JSON_NULL: - case JSON_BOOLEAN: - case JSON_INTEGER: - case JSON_UINTEGER: - case JSON_DOUBLE: - std::memcpy(&Value, &val.Value, sizeof(Value)); - break; - } - } - - TJsonValue& TJsonValue::operator=(const TJsonValue& val) { - if (this == &val) - return *this; - TJsonValue tmp(val); - tmp.Swap(*this); + const TJsonValue TJsonValue::UNDEFINED{}; + + TJsonValue::TJsonValue(const EJsonValueType type) { + SetType(type); + } + + TJsonValue::TJsonValue(TJsonValue&& vval) noexcept + : Type(JSON_UNDEFINED) + { + vval.SwapWithUndefined(*this); + Zero(vval.Value); + } + + TJsonValue::TJsonValue(const TJsonValue& val) + : Type(val.Type) + { + switch (Type) { + case JSON_STRING: + new (&Value.String) TString(val.GetString()); + break; + case JSON_MAP: + Value.Map = new TMapType(val.GetMap()); + break; + case JSON_ARRAY: + Value.Array = new TArray(val.GetArray()); + break; + case JSON_UNDEFINED: + case JSON_NULL: + case JSON_BOOLEAN: + case JSON_INTEGER: + case JSON_UINTEGER: + case JSON_DOUBLE: + std::memcpy(&Value, &val.Value, sizeof(Value)); + break; + } + } + + TJsonValue& TJsonValue::operator=(const TJsonValue& val) { + if (this == &val) + return *this; + TJsonValue tmp(val); + tmp.Swap(*this); return *this; - } + } - TJsonValue& TJsonValue::operator=(TJsonValue&& val) noexcept { - if (this == &val) - return *this; - TJsonValue tmp(std::move(val)); - tmp.Swap(*this); + TJsonValue& TJsonValue::operator=(TJsonValue&& val) noexcept { + if (this == &val) + return *this; + TJsonValue tmp(std::move(val)); + tmp.Swap(*this); return *this; - } - - TJsonValue::TJsonValue(const bool value) noexcept { - SetType(JSON_BOOLEAN); - Value.Boolean = value; - } - - TJsonValue::TJsonValue(const long long value) noexcept { - SetType(JSON_INTEGER); - Value.Integer = value; - } - - TJsonValue::TJsonValue(const unsigned long long value) noexcept { - SetType(JSON_UINTEGER); - Value.UInteger = value; - } - - TJsonValue::TJsonValue(const int value) noexcept { - SetType(JSON_INTEGER); - Value.Integer = value; - } - - TJsonValue::TJsonValue(const unsigned int value) noexcept { - SetType(JSON_UINTEGER); - Value.UInteger = value; - } - - TJsonValue::TJsonValue(const long value) noexcept { - SetType(JSON_INTEGER); - Value.Integer = value; - } - - TJsonValue::TJsonValue(const unsigned long value) noexcept { - SetType(JSON_UINTEGER); - Value.UInteger = value; - } - - TJsonValue::TJsonValue(const double value) noexcept { - SetType(JSON_DOUBLE); - Value.Double = value; - } + } + + TJsonValue::TJsonValue(const bool value) noexcept { + SetType(JSON_BOOLEAN); + Value.Boolean = value; + } + + TJsonValue::TJsonValue(const long long value) noexcept { + SetType(JSON_INTEGER); + Value.Integer = value; + } + + TJsonValue::TJsonValue(const unsigned long long value) noexcept { + SetType(JSON_UINTEGER); + Value.UInteger = value; + } + + TJsonValue::TJsonValue(const int value) noexcept { + SetType(JSON_INTEGER); + Value.Integer = value; + } + + TJsonValue::TJsonValue(const unsigned int value) noexcept { + SetType(JSON_UINTEGER); + Value.UInteger = value; + } + + TJsonValue::TJsonValue(const long value) noexcept { + SetType(JSON_INTEGER); + Value.Integer = value; + } + + TJsonValue::TJsonValue(const unsigned long value) noexcept { + SetType(JSON_UINTEGER); + Value.UInteger = value; + } + + TJsonValue::TJsonValue(const double value) noexcept { + SetType(JSON_DOUBLE); + Value.Double = value; + } TJsonValue::TJsonValue(TString value) { - SetType(JSON_STRING); - Value.String = std::move(value); - } - - TJsonValue::TJsonValue(const TStringBuf value) { - SetType(JSON_STRING); - Value.String = value; - } - - TJsonValue::TJsonValue(const char* value) { - SetType(JSON_STRING); - Value.String = value; - } - - EJsonValueType TJsonValue::GetType() const noexcept { - return Type; - } - - TJsonValue& TJsonValue::SetType(const EJsonValueType type) { - if (Type == type) - return *this; - - Clear(); - Type = type; - - switch (Type) { - case JSON_STRING: - new (&Value.String) TString(); - break; - case JSON_MAP: - Value.Map = new TMapType(); - break; - case JSON_ARRAY: - Value.Array = new TArray(); - break; - case JSON_UNDEFINED: - case JSON_NULL: - case JSON_BOOLEAN: - case JSON_INTEGER: - case JSON_UINTEGER: - case JSON_DOUBLE: - break; - } - - return *this; - } - - TJsonValue& TJsonValue::SetValue(const TJsonValue& value) { - return *this = value; - } - - TJsonValue& TJsonValue::SetValue(TJsonValue&& value) { - *this = std::move(value); - return *this; - } - - TJsonValue& TJsonValue::InsertValue(const TString& key, const TJsonValue& value) { - SetType(JSON_MAP); - return (*Value.Map)[key] = value; - } - - TJsonValue& TJsonValue::InsertValue(const TStringBuf key, const TJsonValue& value) { - SetType(JSON_MAP); - return (*Value.Map)[key] = value; - } - - TJsonValue& TJsonValue::InsertValue(const char* key, const TJsonValue& value) { - SetType(JSON_MAP); - return (*Value.Map)[key] = value; - } - - TJsonValue& TJsonValue::InsertValue(const TString& key, TJsonValue&& value) { - SetType(JSON_MAP); - return (*Value.Map)[key] = std::move(value); - } - - TJsonValue& TJsonValue::InsertValue(const TStringBuf key, TJsonValue&& value) { - SetType(JSON_MAP); - return (*Value.Map)[key] = std::move(value); - } - - TJsonValue& TJsonValue::InsertValue(const char* key, TJsonValue&& value) { - SetType(JSON_MAP); - return (*Value.Map)[key] = std::move(value); - } - - TJsonValue& TJsonValue::Back() { + SetType(JSON_STRING); + Value.String = std::move(value); + } + + TJsonValue::TJsonValue(const TStringBuf value) { + SetType(JSON_STRING); + Value.String = value; + } + + TJsonValue::TJsonValue(const char* value) { + SetType(JSON_STRING); + Value.String = value; + } + + EJsonValueType TJsonValue::GetType() const noexcept { + return Type; + } + + TJsonValue& TJsonValue::SetType(const EJsonValueType type) { + if (Type == type) + return *this; + + Clear(); + Type = type; + + switch (Type) { + case JSON_STRING: + new (&Value.String) TString(); + break; + case JSON_MAP: + Value.Map = new TMapType(); + break; + case JSON_ARRAY: + Value.Array = new TArray(); + break; + case JSON_UNDEFINED: + case JSON_NULL: + case JSON_BOOLEAN: + case JSON_INTEGER: + case JSON_UINTEGER: + case JSON_DOUBLE: + break; + } + + return *this; + } + + TJsonValue& TJsonValue::SetValue(const TJsonValue& value) { + return *this = value; + } + + TJsonValue& TJsonValue::SetValue(TJsonValue&& value) { + *this = std::move(value); + return *this; + } + + TJsonValue& TJsonValue::InsertValue(const TString& key, const TJsonValue& value) { + SetType(JSON_MAP); + return (*Value.Map)[key] = value; + } + + TJsonValue& TJsonValue::InsertValue(const TStringBuf key, const TJsonValue& value) { + SetType(JSON_MAP); + return (*Value.Map)[key] = value; + } + + TJsonValue& TJsonValue::InsertValue(const char* key, const TJsonValue& value) { + SetType(JSON_MAP); + return (*Value.Map)[key] = value; + } + + TJsonValue& TJsonValue::InsertValue(const TString& key, TJsonValue&& value) { + SetType(JSON_MAP); + return (*Value.Map)[key] = std::move(value); + } + + TJsonValue& TJsonValue::InsertValue(const TStringBuf key, TJsonValue&& value) { + SetType(JSON_MAP); + return (*Value.Map)[key] = std::move(value); + } + + TJsonValue& TJsonValue::InsertValue(const char* key, TJsonValue&& value) { + SetType(JSON_MAP); + return (*Value.Map)[key] = std::move(value); + } + + TJsonValue& TJsonValue::Back() { BackChecks(); return Value.Array->back(); } const TJsonValue& TJsonValue::Back() const { BackChecks(); - return Value.Array->back(); - } - - TJsonValue& TJsonValue::AppendValue(const TJsonValue& value) { - SetType(JSON_ARRAY); - Value.Array->push_back(value); - return Value.Array->back(); - } - - TJsonValue& TJsonValue::AppendValue(TJsonValue&& value) { - SetType(JSON_ARRAY); - Value.Array->push_back(std::move(value)); - return Value.Array->back(); - } - - void TJsonValue::EraseValue(const TStringBuf key) { - if (IsMap()) { - TMapType::iterator it = Value.Map->find(key); - if (it != Value.Map->end()) - Value.Map->erase(it); - } - } - - void TJsonValue::EraseValue(const size_t index) { - if (IsArray()) { - if (index >= Value.Array->size()) { - return; - } - TArray::iterator it = Value.Array->begin() + index; - Value.Array->erase(it); - } - } - - void TJsonValue::Clear() noexcept { - switch (Type) { - case JSON_STRING: - Value.String.~TString(); - break; - case JSON_MAP: - delete Value.Map; - break; - case JSON_ARRAY: - delete Value.Array; - break; - case JSON_UNDEFINED: - case JSON_NULL: - case JSON_BOOLEAN: - case JSON_INTEGER: - case JSON_UINTEGER: - case JSON_DOUBLE: - break; + return Value.Array->back(); + } + + TJsonValue& TJsonValue::AppendValue(const TJsonValue& value) { + SetType(JSON_ARRAY); + Value.Array->push_back(value); + return Value.Array->back(); + } + + TJsonValue& TJsonValue::AppendValue(TJsonValue&& value) { + SetType(JSON_ARRAY); + Value.Array->push_back(std::move(value)); + return Value.Array->back(); + } + + void TJsonValue::EraseValue(const TStringBuf key) { + if (IsMap()) { + TMapType::iterator it = Value.Map->find(key); + if (it != Value.Map->end()) + Value.Map->erase(it); } - Zero(Value); - Type = JSON_UNDEFINED; } - TJsonValue& TJsonValue::operator[](const size_t idx) { - SetType(JSON_ARRAY); - if (Value.Array->size() <= idx) - Value.Array->resize(idx + 1); - return (*Value.Array)[idx]; - } + void TJsonValue::EraseValue(const size_t index) { + if (IsArray()) { + if (index >= Value.Array->size()) { + return; + } + TArray::iterator it = Value.Array->begin() + index; + Value.Array->erase(it); + } + } - TJsonValue& TJsonValue::operator[](const TStringBuf& key) { - SetType(JSON_MAP); - return (*Value.Map)[key]; + void TJsonValue::Clear() noexcept { + switch (Type) { + case JSON_STRING: + Value.String.~TString(); + break; + case JSON_MAP: + delete Value.Map; + break; + case JSON_ARRAY: + delete Value.Array; + break; + case JSON_UNDEFINED: + case JSON_NULL: + case JSON_BOOLEAN: + case JSON_INTEGER: + case JSON_UINTEGER: + case JSON_DOUBLE: + break; + } + Zero(Value); + Type = JSON_UNDEFINED; } - namespace { - struct TDefaultsHolder { - const TString String{}; - const TJsonValue::TMapType Map{}; - const TJsonValue::TArray Array{}; - const TJsonValue Value{}; - }; - } + TJsonValue& TJsonValue::operator[](const size_t idx) { + SetType(JSON_ARRAY); + if (Value.Array->size() <= idx) + Value.Array->resize(idx + 1); + return (*Value.Array)[idx]; + } - const TJsonValue& TJsonValue::operator[](const size_t idx) const noexcept { - const TJsonValue* ret = nullptr; - if (GetValuePointer(idx, &ret)) - return *ret; + TJsonValue& TJsonValue::operator[](const TStringBuf& key) { + SetType(JSON_MAP); + return (*Value.Map)[key]; + } - return Singleton<TDefaultsHolder>()->Value; - } + namespace { + struct TDefaultsHolder { + const TString String{}; + const TJsonValue::TMapType Map{}; + const TJsonValue::TArray Array{}; + const TJsonValue Value{}; + }; + } - const TJsonValue& TJsonValue::operator[](const TStringBuf& key) const noexcept { - const TJsonValue* ret = nullptr; - if (GetValuePointer(key, &ret)) - return *ret; + const TJsonValue& TJsonValue::operator[](const size_t idx) const noexcept { + const TJsonValue* ret = nullptr; + if (GetValuePointer(idx, &ret)) + return *ret; - return Singleton<TDefaultsHolder>()->Value; - } + return Singleton<TDefaultsHolder>()->Value; + } - bool TJsonValue::GetBoolean() const { - return Type != JSON_BOOLEAN ? false : Value.Boolean; - } + const TJsonValue& TJsonValue::operator[](const TStringBuf& key) const noexcept { + const TJsonValue* ret = nullptr; + if (GetValuePointer(key, &ret)) + return *ret; - long long TJsonValue::GetInteger() const { - if (!IsInteger()) - return 0; + return Singleton<TDefaultsHolder>()->Value; + } - switch (Type) { - case JSON_INTEGER: - return Value.Integer; + bool TJsonValue::GetBoolean() const { + return Type != JSON_BOOLEAN ? false : Value.Boolean; + } - case JSON_UINTEGER: - return Value.UInteger; + long long TJsonValue::GetInteger() const { + if (!IsInteger()) + return 0; - case JSON_DOUBLE: - return Value.Double; + switch (Type) { + case JSON_INTEGER: + return Value.Integer; + + case JSON_UINTEGER: + return Value.UInteger; + + case JSON_DOUBLE: + return Value.Double; - default: - Y_ASSERT(false && "Unexpected type."); - return 0; - } + default: + Y_ASSERT(false && "Unexpected type."); + return 0; + } } - unsigned long long TJsonValue::GetUInteger() const { - if (!IsUInteger()) - return 0; + unsigned long long TJsonValue::GetUInteger() const { + if (!IsUInteger()) + return 0; - switch (Type) { - case JSON_UINTEGER: - return Value.UInteger; + switch (Type) { + case JSON_UINTEGER: + return Value.UInteger; - case JSON_INTEGER: - return Value.Integer; + case JSON_INTEGER: + return Value.Integer; - case JSON_DOUBLE: - return Value.Double; + case JSON_DOUBLE: + return Value.Double; - default: - Y_ASSERT(false && "Unexpected type."); - return 0; - } + default: + Y_ASSERT(false && "Unexpected type."); + return 0; + } } - double TJsonValue::GetDouble() const { - if (!IsDouble()) - return 0.0; + double TJsonValue::GetDouble() const { + if (!IsDouble()) + return 0.0; - switch (Type) { - case JSON_DOUBLE: - return Value.Double; + switch (Type) { + case JSON_DOUBLE: + return Value.Double; - case JSON_INTEGER: - return Value.Integer; + case JSON_INTEGER: + return Value.Integer; - case JSON_UINTEGER: - return Value.UInteger; + case JSON_UINTEGER: + return Value.UInteger; - default: - Y_ASSERT(false && "Unexpected type."); - return 0.0; - } + default: + Y_ASSERT(false && "Unexpected type."); + return 0.0; + } } - const TString& TJsonValue::GetString() const { - return Type != JSON_STRING ? Singleton<TDefaultsHolder>()->String : Value.String; - } + const TString& TJsonValue::GetString() const { + return Type != JSON_STRING ? Singleton<TDefaultsHolder>()->String : Value.String; + } - const TJsonValue::TMapType& TJsonValue::GetMap() const { - return Type != JSON_MAP ? Singleton<TDefaultsHolder>()->Map : *Value.Map; - } + const TJsonValue::TMapType& TJsonValue::GetMap() const { + return Type != JSON_MAP ? Singleton<TDefaultsHolder>()->Map : *Value.Map; + } - const TJsonValue::TArray& TJsonValue::GetArray() const { - return (Type != JSON_ARRAY) ? Singleton<TDefaultsHolder>()->Array : *Value.Array; - } + const TJsonValue::TArray& TJsonValue::GetArray() const { + return (Type != JSON_ARRAY) ? Singleton<TDefaultsHolder>()->Array : *Value.Array; + } - bool TJsonValue::GetBooleanSafe() const { - if (Type != JSON_BOOLEAN) - ythrow TJsonException() << "Not a boolean"; + bool TJsonValue::GetBooleanSafe() const { + if (Type != JSON_BOOLEAN) + ythrow TJsonException() << "Not a boolean"; - return Value.Boolean; - } + return Value.Boolean; + } - long long TJsonValue::GetIntegerSafe() const { - if (!IsInteger()) - ythrow TJsonException() << "Not an integer"; + long long TJsonValue::GetIntegerSafe() const { + if (!IsInteger()) + ythrow TJsonException() << "Not an integer"; - return GetInteger(); - } + return GetInteger(); + } - unsigned long long TJsonValue::GetUIntegerSafe() const { - if (!IsUInteger()) - ythrow TJsonException() << "Not an unsigned integer"; + unsigned long long TJsonValue::GetUIntegerSafe() const { + if (!IsUInteger()) + ythrow TJsonException() << "Not an unsigned integer"; - return GetUInteger(); - } + return GetUInteger(); + } - double TJsonValue::GetDoubleSafe() const { - if (!IsDouble()) - ythrow TJsonException() << "Not a double"; + double TJsonValue::GetDoubleSafe() const { + if (!IsDouble()) + ythrow TJsonException() << "Not a double"; - return GetDouble(); - } + return GetDouble(); + } - const TString& TJsonValue::GetStringSafe() const { - if (Type != JSON_STRING) - ythrow TJsonException() << "Not a string"; + const TString& TJsonValue::GetStringSafe() const { + if (Type != JSON_STRING) + ythrow TJsonException() << "Not a string"; - return Value.String; - } + return Value.String; + } - bool TJsonValue::GetBooleanSafe(const bool defaultValue) const { - if (Type == JSON_UNDEFINED) - return defaultValue; + bool TJsonValue::GetBooleanSafe(const bool defaultValue) const { + if (Type == JSON_UNDEFINED) + return defaultValue; - return GetBooleanSafe(); - } + return GetBooleanSafe(); + } - long long TJsonValue::GetIntegerSafe(const long long defaultValue) const { - if (Type == JSON_UNDEFINED) - return defaultValue; + long long TJsonValue::GetIntegerSafe(const long long defaultValue) const { + if (Type == JSON_UNDEFINED) + return defaultValue; - return GetIntegerSafe(); - } + return GetIntegerSafe(); + } - unsigned long long TJsonValue::GetUIntegerSafe(const unsigned long long defaultValue) const { - if (Type == JSON_UNDEFINED) - return defaultValue; + unsigned long long TJsonValue::GetUIntegerSafe(const unsigned long long defaultValue) const { + if (Type == JSON_UNDEFINED) + return defaultValue; - return GetUIntegerSafe(); - } + return GetUIntegerSafe(); + } - double TJsonValue::GetDoubleSafe(const double defaultValue) const { - if (Type == JSON_UNDEFINED) - return defaultValue; + double TJsonValue::GetDoubleSafe(const double defaultValue) const { + if (Type == JSON_UNDEFINED) + return defaultValue; - return GetDoubleSafe(); - } + return GetDoubleSafe(); + } - TString TJsonValue::GetStringSafe(const TString& defaultValue) const { - if (Type == JSON_UNDEFINED) - return defaultValue; + TString TJsonValue::GetStringSafe(const TString& defaultValue) const { + if (Type == JSON_UNDEFINED) + return defaultValue; - return GetStringSafe(); - } + return GetStringSafe(); + } - const TJsonValue::TMapType& TJsonValue::GetMapSafe() const { - if (Type != JSON_MAP) - ythrow TJsonException() << "Not a map"; + const TJsonValue::TMapType& TJsonValue::GetMapSafe() const { + if (Type != JSON_MAP) + ythrow TJsonException() << "Not a map"; - return *Value.Map; - } + return *Value.Map; + } - TJsonValue::TMapType& TJsonValue::GetMapSafe() { - return const_cast<TJsonValue::TMapType&>(const_cast<const TJsonValue*>(this)->GetMapSafe()); - } + TJsonValue::TMapType& TJsonValue::GetMapSafe() { + return const_cast<TJsonValue::TMapType&>(const_cast<const TJsonValue*>(this)->GetMapSafe()); + } - const TJsonValue::TArray& TJsonValue::GetArraySafe() const { - if (Type != JSON_ARRAY) - ythrow TJsonException() << "Not an array"; + const TJsonValue::TArray& TJsonValue::GetArraySafe() const { + if (Type != JSON_ARRAY) + ythrow TJsonException() << "Not an array"; - return *Value.Array; - } + return *Value.Array; + } - TJsonValue::TArray& TJsonValue::GetArraySafe() { - return const_cast<TJsonValue::TArray&>(const_cast<const TJsonValue*>(this)->GetArraySafe()); - } + TJsonValue::TArray& TJsonValue::GetArraySafe() { + return const_cast<TJsonValue::TArray&>(const_cast<const TJsonValue*>(this)->GetArraySafe()); + } - bool TJsonValue::GetBooleanRobust() const noexcept { - switch (Type) { - case JSON_ARRAY: - return !Value.Array->empty(); - case JSON_MAP: - return !Value.Map->empty(); - case JSON_INTEGER: - case JSON_UINTEGER: - case JSON_DOUBLE: - return GetIntegerRobust(); - case JSON_STRING: - return GetIntegerRobust() || IsTrue(Value.String); - case JSON_NULL: - case JSON_UNDEFINED: - default: + bool TJsonValue::GetBooleanRobust() const noexcept { + switch (Type) { + case JSON_ARRAY: + return !Value.Array->empty(); + case JSON_MAP: + return !Value.Map->empty(); + case JSON_INTEGER: + case JSON_UINTEGER: + case JSON_DOUBLE: + return GetIntegerRobust(); + case JSON_STRING: + return GetIntegerRobust() || IsTrue(Value.String); + case JSON_NULL: + case JSON_UNDEFINED: + default: return false; - case JSON_BOOLEAN: - return Value.Boolean; - } - } - - long long TJsonValue::GetIntegerRobust() const noexcept { - switch (Type) { - case JSON_ARRAY: - return Value.Array->size(); - case JSON_MAP: - return Value.Map->size(); - case JSON_BOOLEAN: - return Value.Boolean; - case JSON_DOUBLE: - return GetDoubleRobust(); - case JSON_STRING: - try { - i64 res = 0; - if (Value.String && TryFromString(Value.String, res)) { - return res; - } - } catch (const yexception&) { - } - return 0; - case JSON_NULL: - case JSON_UNDEFINED: - default: - return 0; - case JSON_INTEGER: - case JSON_UINTEGER: - return Value.Integer; - } - } - - unsigned long long TJsonValue::GetUIntegerRobust() const noexcept { - switch (Type) { - case JSON_ARRAY: - return Value.Array->size(); - case JSON_MAP: - return Value.Map->size(); - case JSON_BOOLEAN: - return Value.Boolean; - case JSON_DOUBLE: - return GetDoubleRobust(); - case JSON_STRING: - try { - ui64 res = 0; - if (Value.String && TryFromString(Value.String, res)) { - return res; - } - } catch (const yexception&) { - } - return 0; - case JSON_NULL: - case JSON_UNDEFINED: - default: - return 0; - case JSON_INTEGER: - case JSON_UINTEGER: - return Value.UInteger; - } - } - - double TJsonValue::GetDoubleRobust() const noexcept { - switch (Type) { - case JSON_ARRAY: - return Value.Array->size(); - case JSON_MAP: - return Value.Map->size(); - case JSON_BOOLEAN: - return Value.Boolean; - case JSON_INTEGER: - return Value.Integer; - case JSON_UINTEGER: - return Value.UInteger; - case JSON_STRING: - try { - double res = 0; - if (Value.String && TryFromString(Value.String, res)) { - return res; - } - } catch (const yexception&) { - } - return 0; - case JSON_NULL: - case JSON_UNDEFINED: - default: - return 0; - case JSON_DOUBLE: - return Value.Double; - } - } - - TString TJsonValue::GetStringRobust() const { - switch (Type) { - case JSON_ARRAY: - case JSON_MAP: - case JSON_BOOLEAN: - case JSON_DOUBLE: - case JSON_INTEGER: - case JSON_UINTEGER: - case JSON_NULL: - case JSON_UNDEFINED: - default: { - NJsonWriter::TBuf sout; - sout.WriteJsonValue(this); - return sout.Str(); - } - case JSON_STRING: - return Value.String; - } - } - - bool TJsonValue::GetBoolean(bool* value) const noexcept { - if (Type != JSON_BOOLEAN) - return false; - - *value = Value.Boolean; - return true; - } - - bool TJsonValue::GetInteger(long long* value) const noexcept { - if (!IsInteger()) - return false; - - *value = GetInteger(); - return true; - } - - bool TJsonValue::GetUInteger(unsigned long long* value) const noexcept { - if (!IsUInteger()) - return false; - - *value = GetUInteger(); - return true; - } - - bool TJsonValue::GetDouble(double* value) const noexcept { - if (!IsDouble()) - return false; - - *value = GetDouble(); - return true; - } - - bool TJsonValue::GetString(TString* value) const { - if (Type != JSON_STRING) - return false; - - *value = Value.String; - return true; - } - - bool TJsonValue::GetMap(TJsonValue::TMapType* value) const { - if (Type != JSON_MAP) - return false; - - *value = *Value.Map; - return true; - } - - bool TJsonValue::GetArray(TJsonValue::TArray* value) const { - if (Type != JSON_ARRAY) - return false; - - *value = *Value.Array; - return true; - } - - bool TJsonValue::GetMapPointer(const TJsonValue::TMapType** value) const noexcept { - if (Type != JSON_MAP) - return false; - - *value = Value.Map; - return true; - } - - bool TJsonValue::GetArrayPointer(const TJsonValue::TArray** value) const noexcept { - if (Type != JSON_ARRAY) - return false; - - *value = Value.Array; + case JSON_BOOLEAN: + return Value.Boolean; + } + } + + long long TJsonValue::GetIntegerRobust() const noexcept { + switch (Type) { + case JSON_ARRAY: + return Value.Array->size(); + case JSON_MAP: + return Value.Map->size(); + case JSON_BOOLEAN: + return Value.Boolean; + case JSON_DOUBLE: + return GetDoubleRobust(); + case JSON_STRING: + try { + i64 res = 0; + if (Value.String && TryFromString(Value.String, res)) { + return res; + } + } catch (const yexception&) { + } + return 0; + case JSON_NULL: + case JSON_UNDEFINED: + default: + return 0; + case JSON_INTEGER: + case JSON_UINTEGER: + return Value.Integer; + } + } + + unsigned long long TJsonValue::GetUIntegerRobust() const noexcept { + switch (Type) { + case JSON_ARRAY: + return Value.Array->size(); + case JSON_MAP: + return Value.Map->size(); + case JSON_BOOLEAN: + return Value.Boolean; + case JSON_DOUBLE: + return GetDoubleRobust(); + case JSON_STRING: + try { + ui64 res = 0; + if (Value.String && TryFromString(Value.String, res)) { + return res; + } + } catch (const yexception&) { + } + return 0; + case JSON_NULL: + case JSON_UNDEFINED: + default: + return 0; + case JSON_INTEGER: + case JSON_UINTEGER: + return Value.UInteger; + } + } + + double TJsonValue::GetDoubleRobust() const noexcept { + switch (Type) { + case JSON_ARRAY: + return Value.Array->size(); + case JSON_MAP: + return Value.Map->size(); + case JSON_BOOLEAN: + return Value.Boolean; + case JSON_INTEGER: + return Value.Integer; + case JSON_UINTEGER: + return Value.UInteger; + case JSON_STRING: + try { + double res = 0; + if (Value.String && TryFromString(Value.String, res)) { + return res; + } + } catch (const yexception&) { + } + return 0; + case JSON_NULL: + case JSON_UNDEFINED: + default: + return 0; + case JSON_DOUBLE: + return Value.Double; + } + } + + TString TJsonValue::GetStringRobust() const { + switch (Type) { + case JSON_ARRAY: + case JSON_MAP: + case JSON_BOOLEAN: + case JSON_DOUBLE: + case JSON_INTEGER: + case JSON_UINTEGER: + case JSON_NULL: + case JSON_UNDEFINED: + default: { + NJsonWriter::TBuf sout; + sout.WriteJsonValue(this); + return sout.Str(); + } + case JSON_STRING: + return Value.String; + } + } + + bool TJsonValue::GetBoolean(bool* value) const noexcept { + if (Type != JSON_BOOLEAN) + return false; + + *value = Value.Boolean; + return true; + } + + bool TJsonValue::GetInteger(long long* value) const noexcept { + if (!IsInteger()) + return false; + + *value = GetInteger(); + return true; + } + + bool TJsonValue::GetUInteger(unsigned long long* value) const noexcept { + if (!IsUInteger()) + return false; + + *value = GetUInteger(); + return true; + } + + bool TJsonValue::GetDouble(double* value) const noexcept { + if (!IsDouble()) + return false; + + *value = GetDouble(); + return true; + } + + bool TJsonValue::GetString(TString* value) const { + if (Type != JSON_STRING) + return false; + + *value = Value.String; return true; } - bool TJsonValue::GetValue(const size_t index, TJsonValue* value) const { - const TJsonValue* tmp = nullptr; - if (GetValuePointer(index, &tmp)) { - *value = *tmp; - return true; - } - return false; + bool TJsonValue::GetMap(TJsonValue::TMapType* value) const { + if (Type != JSON_MAP) + return false; + + *value = *Value.Map; + return true; } - bool TJsonValue::GetValue(const TStringBuf key, TJsonValue* value) const { - const TJsonValue* tmp = nullptr; - if (GetValuePointer(key, &tmp)) { - *value = *tmp; - return true; - } - return false; + bool TJsonValue::GetArray(TJsonValue::TArray* value) const { + if (Type != JSON_ARRAY) + return false; + + *value = *Value.Array; + return true; } - bool TJsonValue::GetValuePointer(const size_t index, const TJsonValue** value) const noexcept { - if (Type == JSON_ARRAY && index < Value.Array->size()) { - *value = &(*Value.Array)[index]; + bool TJsonValue::GetMapPointer(const TJsonValue::TMapType** value) const noexcept { + if (Type != JSON_MAP) + return false; + + *value = Value.Map; + return true; + } + + bool TJsonValue::GetArrayPointer(const TJsonValue::TArray** value) const noexcept { + if (Type != JSON_ARRAY) + return false; + + *value = Value.Array; + return true; + } + + bool TJsonValue::GetValue(const size_t index, TJsonValue* value) const { + const TJsonValue* tmp = nullptr; + if (GetValuePointer(index, &tmp)) { + *value = *tmp; return true; } - return false; + return false; } - bool TJsonValue::GetValuePointer(const TStringBuf key, const TJsonValue** value) const noexcept { - if (Type == JSON_MAP) { - const TMapType::const_iterator it = Value.Map->find(key); - if (it != Value.Map->end()) { - *value = &(it->second); - return true; - } - } - return false; - } + bool TJsonValue::GetValue(const TStringBuf key, TJsonValue* value) const { + const TJsonValue* tmp = nullptr; + if (GetValuePointer(key, &tmp)) { + *value = *tmp; + return true; + } + return false; + } - bool TJsonValue::GetValuePointer(const TStringBuf key, TJsonValue** value) noexcept { - return static_cast<const TJsonValue*>(this)->GetValuePointer(key, const_cast<const TJsonValue**>(value)); - } + bool TJsonValue::GetValuePointer(const size_t index, const TJsonValue** value) const noexcept { + if (Type == JSON_ARRAY && index < Value.Array->size()) { + *value = &(*Value.Array)[index]; + return true; + } + return false; + } - bool TJsonValue::IsNull() const noexcept { - return Type == JSON_NULL; - } + bool TJsonValue::GetValuePointer(const TStringBuf key, const TJsonValue** value) const noexcept { + if (Type == JSON_MAP) { + const TMapType::const_iterator it = Value.Map->find(key); + if (it != Value.Map->end()) { + *value = &(it->second); + return true; + } + } + return false; + } - bool TJsonValue::IsBoolean() const noexcept { - return Type == JSON_BOOLEAN; - } + bool TJsonValue::GetValuePointer(const TStringBuf key, TJsonValue** value) noexcept { + return static_cast<const TJsonValue*>(this)->GetValuePointer(key, const_cast<const TJsonValue**>(value)); + } + + bool TJsonValue::IsNull() const noexcept { + return Type == JSON_NULL; + } - bool TJsonValue::IsInteger() const noexcept { - switch (Type) { - case JSON_INTEGER: - return true; + bool TJsonValue::IsBoolean() const noexcept { + return Type == JSON_BOOLEAN; + } - case JSON_UINTEGER: - return (Value.UInteger <= static_cast<unsigned long long>(Max<long long>())); + bool TJsonValue::IsInteger() const noexcept { + switch (Type) { + case JSON_INTEGER: + return true; - case JSON_DOUBLE: - return ((long long)Value.Double == Value.Double); - - default: - return false; - } + case JSON_UINTEGER: + return (Value.UInteger <= static_cast<unsigned long long>(Max<long long>())); + + case JSON_DOUBLE: + return ((long long)Value.Double == Value.Double); + + default: + return false; + } } - bool TJsonValue::IsUInteger() const noexcept { - switch (Type) { - case JSON_UINTEGER: - return true; + bool TJsonValue::IsUInteger() const noexcept { + switch (Type) { + case JSON_UINTEGER: + return true; - case JSON_INTEGER: - return (Value.Integer >= 0); + case JSON_INTEGER: + return (Value.Integer >= 0); - case JSON_DOUBLE: - return ((unsigned long long)Value.Double == Value.Double); + case JSON_DOUBLE: + return ((unsigned long long)Value.Double == Value.Double); - default: - return false; - } + default: + return false; + } } - bool TJsonValue::IsDouble() const noexcept { - // Check whether we can convert integer to floating-point - // without precision loss. - switch (Type) { - case JSON_DOUBLE: - return true; + bool TJsonValue::IsDouble() const noexcept { + // Check whether we can convert integer to floating-point + // without precision loss. + switch (Type) { + case JSON_DOUBLE: + return true; - case JSON_INTEGER: + case JSON_INTEGER: return (1ll << std::numeric_limits<double>::digits) >= Abs(Value.Integer); - case JSON_UINTEGER: + case JSON_UINTEGER: return (1ull << std::numeric_limits<double>::digits) >= Value.UInteger; - default: - return false; - } - } - - namespace { - template <class TPtr, class T> - TPtr* CreateOrNullptr(TPtr* p, T key, std::true_type /*create*/) { - return &(*p)[key]; - } - - template <class TPtr, class T> - TPtr* CreateOrNullptr(const TPtr* p, T key, std::false_type /*create*/) noexcept { - const TPtr* const next = &(*p)[key]; - return next->IsDefined() ? const_cast<TPtr*>(next) : nullptr; - } - - template <bool Create, class TJsonPtr> - TJsonPtr GetValuePtrByPath(TJsonPtr currentJson, TStringBuf path, char delimiter) noexcept(!Create) { - static_assert( - !(Create && std::is_const<std::remove_pointer_t<TJsonPtr>>::value), - "TJsonPtr must be a `TJsonValue*` if `Create` is true"); - constexpr std::integral_constant<bool, Create> create_tag{}; - - while (!path.empty()) { - size_t index = 0; - const TStringBuf step = path.NextTok(delimiter); - if (step.size() > 2 && *step.begin() == '[' && step.back() == ']' && TryFromString(step.substr(1, step.size() - 2), index)) { - currentJson = CreateOrNullptr(currentJson, index, create_tag); - } else { - currentJson = CreateOrNullptr(currentJson, step, create_tag); - } - - if (!currentJson) { - return nullptr; - } + default: + return false; + } + } + + namespace { + template <class TPtr, class T> + TPtr* CreateOrNullptr(TPtr* p, T key, std::true_type /*create*/) { + return &(*p)[key]; + } + + template <class TPtr, class T> + TPtr* CreateOrNullptr(const TPtr* p, T key, std::false_type /*create*/) noexcept { + const TPtr* const next = &(*p)[key]; + return next->IsDefined() ? const_cast<TPtr*>(next) : nullptr; + } + + template <bool Create, class TJsonPtr> + TJsonPtr GetValuePtrByPath(TJsonPtr currentJson, TStringBuf path, char delimiter) noexcept(!Create) { + static_assert( + !(Create && std::is_const<std::remove_pointer_t<TJsonPtr>>::value), + "TJsonPtr must be a `TJsonValue*` if `Create` is true"); + constexpr std::integral_constant<bool, Create> create_tag{}; + + while (!path.empty()) { + size_t index = 0; + const TStringBuf step = path.NextTok(delimiter); + if (step.size() > 2 && *step.begin() == '[' && step.back() == ']' && TryFromString(step.substr(1, step.size() - 2), index)) { + currentJson = CreateOrNullptr(currentJson, index, create_tag); + } else { + currentJson = CreateOrNullptr(currentJson, step, create_tag); + } + + if (!currentJson) { + return nullptr; + } } - return currentJson; + return currentJson; } - } // anonymous namespace + } // anonymous namespace - bool TJsonValue::GetValueByPath(const TStringBuf path, TJsonValue& result, char delimiter) const { - const TJsonValue* const ptr = GetValuePtrByPath<false>(this, path, delimiter); - if (ptr) { - result = *ptr; - return true; - } - return false; + bool TJsonValue::GetValueByPath(const TStringBuf path, TJsonValue& result, char delimiter) const { + const TJsonValue* const ptr = GetValuePtrByPath<false>(this, path, delimiter); + if (ptr) { + result = *ptr; + return true; + } + return false; } - bool TJsonValue::SetValueByPath(const TStringBuf path, const TJsonValue& value, char delimiter) { - TJsonValue* const ptr = GetValuePtrByPath<true>(this, path, delimiter); - if (ptr) { - *ptr = value; - return true; - } - return false; + bool TJsonValue::SetValueByPath(const TStringBuf path, const TJsonValue& value, char delimiter) { + TJsonValue* const ptr = GetValuePtrByPath<true>(this, path, delimiter); + if (ptr) { + *ptr = value; + return true; + } + return false; } - bool TJsonValue::SetValueByPath(const TStringBuf path, TJsonValue&& value, char delimiter) { - TJsonValue* const ptr = GetValuePtrByPath<true>(this, path, delimiter); - if (ptr) { - *ptr = std::move(value); - return true; - } - return false; + bool TJsonValue::SetValueByPath(const TStringBuf path, TJsonValue&& value, char delimiter) { + TJsonValue* const ptr = GetValuePtrByPath<true>(this, path, delimiter); + if (ptr) { + *ptr = std::move(value); + return true; + } + return false; } - const TJsonValue* TJsonValue::GetValueByPath(const TStringBuf key, char delim) const noexcept { - return GetValuePtrByPath<false>(this, key, delim); + const TJsonValue* TJsonValue::GetValueByPath(const TStringBuf key, char delim) const noexcept { + return GetValuePtrByPath<false>(this, key, delim); } - TJsonValue* TJsonValue::GetValueByPath(const TStringBuf key, char delim) noexcept { - return GetValuePtrByPath<false>(this, key, delim); + TJsonValue* TJsonValue::GetValueByPath(const TStringBuf key, char delim) noexcept { + return GetValuePtrByPath<false>(this, key, delim); } - void TJsonValue::DoScan(const TString& path, TJsonValue* parent, IScanCallback& callback) { - if (!callback.Do(path, parent, *this)) { - return; + void TJsonValue::DoScan(const TString& path, TJsonValue* parent, IScanCallback& callback) { + if (!callback.Do(path, parent, *this)) { + return; } - - if (Type == JSON_MAP) { - for (auto&& i : *Value.Map) { + + if (Type == JSON_MAP) { + for (auto&& i : *Value.Map) { i.second.DoScan(!!path ? TString::Join(path, ".", i.first) : i.first, this, callback); - } - } else if (Type == JSON_ARRAY) { - for (ui32 i = 0; i < Value.Array->size(); ++i) { + } + } else if (Type == JSON_ARRAY) { + for (ui32 i = 0; i < Value.Array->size(); ++i) { (*Value.Array)[i].DoScan(TString::Join(path, "[", ToString(i), "]"), this, callback); - } + } } } - void TJsonValue::Scan(IScanCallback& callback) { - DoScan("", nullptr, callback); + void TJsonValue::Scan(IScanCallback& callback) { + DoScan("", nullptr, callback); } - bool TJsonValue::IsString() const noexcept { - return Type == JSON_STRING; + bool TJsonValue::IsString() const noexcept { + return Type == JSON_STRING; } - bool TJsonValue::IsMap() const noexcept { - return Type == JSON_MAP; + bool TJsonValue::IsMap() const noexcept { + return Type == JSON_MAP; } - bool TJsonValue::IsArray() const noexcept { - return Type == JSON_ARRAY; + bool TJsonValue::IsArray() const noexcept { + return Type == JSON_ARRAY; } - bool TJsonValue::Has(const TStringBuf& key) const noexcept { + bool TJsonValue::Has(const TStringBuf& key) const noexcept { return Type == JSON_MAP && Value.Map->contains(key); } - bool TJsonValue::Has(size_t key) const noexcept { - return Type == JSON_ARRAY && Value.Array->size() > key; - } - - bool TJsonValue::operator==(const TJsonValue& rhs) const { - switch (Type) { - case JSON_UNDEFINED: { - return (rhs.GetType() == JSON_UNDEFINED); - } - - case JSON_NULL: { - return rhs.IsNull(); - } - - case JSON_BOOLEAN: { - return (rhs.IsBoolean() && Value.Boolean == rhs.Value.Boolean); - } - - case JSON_INTEGER: { - return (rhs.IsInteger() && GetInteger() == rhs.GetInteger()); - } - - case JSON_UINTEGER: { - return (rhs.IsUInteger() && GetUInteger() == rhs.GetUInteger()); - } - - case JSON_STRING: { - return (rhs.IsString() && Value.String == rhs.Value.String); - } - - case JSON_DOUBLE: { - return (rhs.IsDouble() && fabs(GetDouble() - rhs.GetDouble()) <= FLT_EPSILON); - } - - case JSON_MAP: - return AreJsonMapsEqual(*this, rhs); - - case JSON_ARRAY: - return AreJsonArraysEqual(*this, rhs); - - default: - Y_ASSERT(false && "Unknown type."); - return false; - } - } - - void TJsonValue::SwapWithUndefined(TJsonValue& output) noexcept { - if (Type == JSON_STRING) { - static_assert(std::is_nothrow_move_constructible<TString>::value, "noexcept violation! Add some try {} catch (...) logic"); - new (&output.Value.String) TString(std::move(Value.String)); - Value.String.~TString(); - } else { - std::memcpy(&output.Value, &Value, sizeof(Value)); - } - - output.Type = Type; - Type = JSON_UNDEFINED; - } - - void TJsonValue::Swap(TJsonValue& rhs) noexcept { - TJsonValue tmp(std::move(*this)); - rhs.SwapWithUndefined(*this); - tmp.SwapWithUndefined(rhs); - } + bool TJsonValue::Has(size_t key) const noexcept { + return Type == JSON_ARRAY && Value.Array->size() > key; + } + + bool TJsonValue::operator==(const TJsonValue& rhs) const { + switch (Type) { + case JSON_UNDEFINED: { + return (rhs.GetType() == JSON_UNDEFINED); + } + + case JSON_NULL: { + return rhs.IsNull(); + } + + case JSON_BOOLEAN: { + return (rhs.IsBoolean() && Value.Boolean == rhs.Value.Boolean); + } + + case JSON_INTEGER: { + return (rhs.IsInteger() && GetInteger() == rhs.GetInteger()); + } + + case JSON_UINTEGER: { + return (rhs.IsUInteger() && GetUInteger() == rhs.GetUInteger()); + } + + case JSON_STRING: { + return (rhs.IsString() && Value.String == rhs.Value.String); + } + + case JSON_DOUBLE: { + return (rhs.IsDouble() && fabs(GetDouble() - rhs.GetDouble()) <= FLT_EPSILON); + } + + case JSON_MAP: + return AreJsonMapsEqual(*this, rhs); + + case JSON_ARRAY: + return AreJsonArraysEqual(*this, rhs); + + default: + Y_ASSERT(false && "Unknown type."); + return false; + } + } + + void TJsonValue::SwapWithUndefined(TJsonValue& output) noexcept { + if (Type == JSON_STRING) { + static_assert(std::is_nothrow_move_constructible<TString>::value, "noexcept violation! Add some try {} catch (...) logic"); + new (&output.Value.String) TString(std::move(Value.String)); + Value.String.~TString(); + } else { + std::memcpy(&output.Value, &Value, sizeof(Value)); + } + + output.Type = Type; + Type = JSON_UNDEFINED; + } + + void TJsonValue::Swap(TJsonValue& rhs) noexcept { + TJsonValue tmp(std::move(*this)); + rhs.SwapWithUndefined(*this); + tmp.SwapWithUndefined(rhs); + } void TJsonValue::Save(IOutputStream* s) const { ::Save(s, static_cast<ui8>(Type)); @@ -1051,43 +1051,43 @@ namespace NJson { } } - //**************************************************************** + //**************************************************************** - bool GetMapPointer(const TJsonValue& jv, const size_t index, const TJsonValue::TMapType** value) { - const TJsonValue* v; - if (!jv.GetValuePointer(index, &v) || !v->IsMap()) - return false; + bool GetMapPointer(const TJsonValue& jv, const size_t index, const TJsonValue::TMapType** value) { + const TJsonValue* v; + if (!jv.GetValuePointer(index, &v) || !v->IsMap()) + return false; - *value = &v->GetMap(); - return true; - } + *value = &v->GetMap(); + return true; + } - bool GetArrayPointer(const TJsonValue& jv, const size_t index, const TJsonValue::TArray** value) { - const TJsonValue* v; - if (!jv.GetValuePointer(index, &v) || !v->IsArray()) - return false; + bool GetArrayPointer(const TJsonValue& jv, const size_t index, const TJsonValue::TArray** value) { + const TJsonValue* v; + if (!jv.GetValuePointer(index, &v) || !v->IsArray()) + return false; - *value = &v->GetArray(); - return true; - } + *value = &v->GetArray(); + return true; + } - bool GetMapPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TMapType** value) { - const TJsonValue* v; - if (!jv.GetValuePointer(key, &v) || !v->IsMap()) - return false; + bool GetMapPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TMapType** value) { + const TJsonValue* v; + if (!jv.GetValuePointer(key, &v) || !v->IsMap()) + return false; - *value = &v->GetMap(); - return true; - } + *value = &v->GetMap(); + return true; + } - bool GetArrayPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TArray** value) { - const TJsonValue* v; - if (!jv.GetValuePointer(key, &v) || !v->IsArray()) - return false; + bool GetArrayPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TArray** value) { + const TJsonValue* v; + if (!jv.GetValuePointer(key, &v) || !v->IsArray()) + return false; - *value = &v->GetArray(); - return true; - } + *value = &v->GetArray(); + return true; + } void TJsonValue::BackChecks() const { if (Type != JSON_ARRAY) @@ -1098,8 +1098,8 @@ namespace NJson { } } -template <> +template <> void Out<NJson::TJsonValue>(IOutputStream& out, const NJson::TJsonValue& v) { NJsonWriter::TBuf buf(NJsonWriter::HEM_DONT_ESCAPE_HTML, &out); buf.WriteJsonValue(&v); -} +} diff --git a/library/cpp/json/writer/json_value.h b/library/cpp/json/writer/json_value.h index 721453f001..3f0f50bc4c 100644 --- a/library/cpp/json/writer/json_value.h +++ b/library/cpp/json/writer/json_value.h @@ -1,189 +1,189 @@ #pragma once #include <library/cpp/json/common/defs.h> - + #include <util/generic/string.h> #include <util/generic/hash.h> #include <util/generic/vector.h> -#include <util/generic/deque.h> +#include <util/generic/deque.h> #include <util/generic/utility.h> #include <util/generic/yexception.h> namespace NJson { - enum EJsonValueType { - JSON_UNDEFINED /* "Undefined" */, - JSON_NULL /* "Null" */, - JSON_BOOLEAN /* "Boolean" */, - JSON_INTEGER /* "Integer" */, - JSON_DOUBLE /* "Double" */, - JSON_STRING /* "String" */, - JSON_MAP /* "Map" */, - JSON_ARRAY /* "Array" */, - JSON_UINTEGER /* "UInteger" */ - }; - - class TJsonValue; - - class IScanCallback { - public: + enum EJsonValueType { + JSON_UNDEFINED /* "Undefined" */, + JSON_NULL /* "Null" */, + JSON_BOOLEAN /* "Boolean" */, + JSON_INTEGER /* "Integer" */, + JSON_DOUBLE /* "Double" */, + JSON_STRING /* "String" */, + JSON_MAP /* "Map" */, + JSON_ARRAY /* "Array" */, + JSON_UINTEGER /* "UInteger" */ + }; + + class TJsonValue; + + class IScanCallback { + public: virtual ~IScanCallback() = default; - virtual bool Do(const TString& path, TJsonValue* parent, TJsonValue& value) = 0; - }; - - class TJsonValue { - void Clear() noexcept; - - public: - typedef THashMap<TString, TJsonValue> TMapType; - typedef TDeque<TJsonValue> TArray; - - TJsonValue() noexcept = default; - TJsonValue(EJsonValueType type); - TJsonValue(bool value) noexcept; - TJsonValue(int value) noexcept; - TJsonValue(unsigned int value) noexcept; - TJsonValue(long value) noexcept; - TJsonValue(unsigned long value) noexcept; - TJsonValue(long long value) noexcept; - TJsonValue(unsigned long long value) noexcept; - TJsonValue(double value) noexcept; + virtual bool Do(const TString& path, TJsonValue* parent, TJsonValue& value) = 0; + }; + + class TJsonValue { + void Clear() noexcept; + + public: + typedef THashMap<TString, TJsonValue> TMapType; + typedef TDeque<TJsonValue> TArray; + + TJsonValue() noexcept = default; + TJsonValue(EJsonValueType type); + TJsonValue(bool value) noexcept; + TJsonValue(int value) noexcept; + TJsonValue(unsigned int value) noexcept; + TJsonValue(long value) noexcept; + TJsonValue(unsigned long value) noexcept; + TJsonValue(long long value) noexcept; + TJsonValue(unsigned long long value) noexcept; + TJsonValue(double value) noexcept; TJsonValue(TString value); - TJsonValue(const char* value); - template <class T> - TJsonValue(const T*) = delete; - TJsonValue(TStringBuf value); - - TJsonValue(const std::string& s) - : TJsonValue(TStringBuf(s)) - { - } - - TJsonValue(const TJsonValue& vval); - TJsonValue(TJsonValue&& vval) noexcept; - - TJsonValue& operator=(const TJsonValue& val); - TJsonValue& operator=(TJsonValue&& val) noexcept; - - ~TJsonValue() { - Clear(); - } - - EJsonValueType GetType() const noexcept; - TJsonValue& SetType(EJsonValueType type); - - TJsonValue& SetValue(const TJsonValue& value); - TJsonValue& SetValue(TJsonValue&& value); - - // for Map - TJsonValue& InsertValue(const TString& key, const TJsonValue& value); - TJsonValue& InsertValue(TStringBuf key, const TJsonValue& value); - TJsonValue& InsertValue(const char* key, const TJsonValue& value); - TJsonValue& InsertValue(const TString& key, TJsonValue&& value); - TJsonValue& InsertValue(TStringBuf key, TJsonValue&& value); - TJsonValue& InsertValue(const char* key, TJsonValue&& value); - - // for Array - TJsonValue& AppendValue(const TJsonValue& value); - TJsonValue& AppendValue(TJsonValue&& value); - TJsonValue& Back(); + TJsonValue(const char* value); + template <class T> + TJsonValue(const T*) = delete; + TJsonValue(TStringBuf value); + + TJsonValue(const std::string& s) + : TJsonValue(TStringBuf(s)) + { + } + + TJsonValue(const TJsonValue& vval); + TJsonValue(TJsonValue&& vval) noexcept; + + TJsonValue& operator=(const TJsonValue& val); + TJsonValue& operator=(TJsonValue&& val) noexcept; + + ~TJsonValue() { + Clear(); + } + + EJsonValueType GetType() const noexcept; + TJsonValue& SetType(EJsonValueType type); + + TJsonValue& SetValue(const TJsonValue& value); + TJsonValue& SetValue(TJsonValue&& value); + + // for Map + TJsonValue& InsertValue(const TString& key, const TJsonValue& value); + TJsonValue& InsertValue(TStringBuf key, const TJsonValue& value); + TJsonValue& InsertValue(const char* key, const TJsonValue& value); + TJsonValue& InsertValue(const TString& key, TJsonValue&& value); + TJsonValue& InsertValue(TStringBuf key, TJsonValue&& value); + TJsonValue& InsertValue(const char* key, TJsonValue&& value); + + // for Array + TJsonValue& AppendValue(const TJsonValue& value); + TJsonValue& AppendValue(TJsonValue&& value); + TJsonValue& Back(); const TJsonValue& Back() const; - bool GetValueByPath(TStringBuf path, TJsonValue& result, char delimiter = '.') const; - bool SetValueByPath(TStringBuf path, const TJsonValue& value, char delimiter = '.'); - bool SetValueByPath(TStringBuf path, TJsonValue&& value, char delimiter = '.'); - - // returns NULL on failure - const TJsonValue* GetValueByPath(TStringBuf path, char delimiter = '.') const noexcept; - TJsonValue* GetValueByPath(TStringBuf path, char delimiter = '.') noexcept; - - void EraseValue(TStringBuf key); - void EraseValue(size_t index); - - TJsonValue& operator[](size_t idx); - TJsonValue& operator[](const TStringBuf& key); - const TJsonValue& operator[](size_t idx) const noexcept; - const TJsonValue& operator[](const TStringBuf& key) const noexcept; - - bool GetBoolean() const; - long long GetInteger() const; - unsigned long long GetUInteger() const; - double GetDouble() const; - const TString& GetString() const; - const TMapType& GetMap() const; - const TArray& GetArray() const; - - //throwing TJsonException possible - bool GetBooleanSafe() const; - long long GetIntegerSafe() const; - unsigned long long GetUIntegerSafe() const; - double GetDoubleSafe() const; - const TString& GetStringSafe() const; - const TMapType& GetMapSafe() const; - TMapType& GetMapSafe(); - const TArray& GetArraySafe() const; - TArray& GetArraySafe(); - - bool GetBooleanSafe(bool defaultValue) const; - long long GetIntegerSafe(long long defaultValue) const; - unsigned long long GetUIntegerSafe(unsigned long long defaultValue) const; - double GetDoubleSafe(double defaultValue) const; - TString GetStringSafe(const TString& defaultValue) const; - - bool GetBooleanRobust() const noexcept; - long long GetIntegerRobust() const noexcept; - unsigned long long GetUIntegerRobust() const noexcept; - double GetDoubleRobust() const noexcept; - TString GetStringRobust() const; - - // Exception-free accessors - bool GetBoolean(bool* value) const noexcept; - bool GetInteger(long long* value) const noexcept; - bool GetUInteger(unsigned long long* value) const noexcept; - bool GetDouble(double* value) const noexcept; - bool GetMapPointer(const TMapType** value) const noexcept; - bool GetArrayPointer(const TArray** value) const noexcept; - - bool GetString(TString* value) const; - bool GetMap(TMapType* value) const; - bool GetArray(TArray* value) const; - bool GetValue(size_t index, TJsonValue* value) const; - bool GetValue(TStringBuf key, TJsonValue* value) const; - bool GetValuePointer(size_t index, const TJsonValue** value) const noexcept; - bool GetValuePointer(TStringBuf key, const TJsonValue** value) const noexcept; - bool GetValuePointer(TStringBuf key, TJsonValue** value) noexcept; - - // Checking for defined non-null value - bool IsDefined() const noexcept { - return Type != JSON_UNDEFINED && Type != JSON_NULL; - } - - bool IsNull() const noexcept; - bool IsBoolean() const noexcept; - bool IsDouble() const noexcept; - bool IsString() const noexcept; - bool IsMap() const noexcept; - bool IsArray() const noexcept; - - /// @return true if JSON_INTEGER or (JSON_UINTEGER and Value <= Max<long long>) - bool IsInteger() const noexcept; - - /// @return true if JSON_UINTEGER or (JSON_INTEGER and Value >= 0) - bool IsUInteger() const noexcept; - - bool Has(const TStringBuf& key) const noexcept; - bool Has(size_t key) const noexcept; - - void Scan(IScanCallback& callback); - - /// Non-robust comparison. - bool operator==(const TJsonValue& rhs) const; - - bool operator!=(const TJsonValue& rhs) const { - return !(*this == rhs); - } - - void Swap(TJsonValue& rhs) noexcept; + bool GetValueByPath(TStringBuf path, TJsonValue& result, char delimiter = '.') const; + bool SetValueByPath(TStringBuf path, const TJsonValue& value, char delimiter = '.'); + bool SetValueByPath(TStringBuf path, TJsonValue&& value, char delimiter = '.'); + + // returns NULL on failure + const TJsonValue* GetValueByPath(TStringBuf path, char delimiter = '.') const noexcept; + TJsonValue* GetValueByPath(TStringBuf path, char delimiter = '.') noexcept; + + void EraseValue(TStringBuf key); + void EraseValue(size_t index); + + TJsonValue& operator[](size_t idx); + TJsonValue& operator[](const TStringBuf& key); + const TJsonValue& operator[](size_t idx) const noexcept; + const TJsonValue& operator[](const TStringBuf& key) const noexcept; + + bool GetBoolean() const; + long long GetInteger() const; + unsigned long long GetUInteger() const; + double GetDouble() const; + const TString& GetString() const; + const TMapType& GetMap() const; + const TArray& GetArray() const; + + //throwing TJsonException possible + bool GetBooleanSafe() const; + long long GetIntegerSafe() const; + unsigned long long GetUIntegerSafe() const; + double GetDoubleSafe() const; + const TString& GetStringSafe() const; + const TMapType& GetMapSafe() const; + TMapType& GetMapSafe(); + const TArray& GetArraySafe() const; + TArray& GetArraySafe(); + + bool GetBooleanSafe(bool defaultValue) const; + long long GetIntegerSafe(long long defaultValue) const; + unsigned long long GetUIntegerSafe(unsigned long long defaultValue) const; + double GetDoubleSafe(double defaultValue) const; + TString GetStringSafe(const TString& defaultValue) const; + + bool GetBooleanRobust() const noexcept; + long long GetIntegerRobust() const noexcept; + unsigned long long GetUIntegerRobust() const noexcept; + double GetDoubleRobust() const noexcept; + TString GetStringRobust() const; + + // Exception-free accessors + bool GetBoolean(bool* value) const noexcept; + bool GetInteger(long long* value) const noexcept; + bool GetUInteger(unsigned long long* value) const noexcept; + bool GetDouble(double* value) const noexcept; + bool GetMapPointer(const TMapType** value) const noexcept; + bool GetArrayPointer(const TArray** value) const noexcept; + + bool GetString(TString* value) const; + bool GetMap(TMapType* value) const; + bool GetArray(TArray* value) const; + bool GetValue(size_t index, TJsonValue* value) const; + bool GetValue(TStringBuf key, TJsonValue* value) const; + bool GetValuePointer(size_t index, const TJsonValue** value) const noexcept; + bool GetValuePointer(TStringBuf key, const TJsonValue** value) const noexcept; + bool GetValuePointer(TStringBuf key, TJsonValue** value) noexcept; + + // Checking for defined non-null value + bool IsDefined() const noexcept { + return Type != JSON_UNDEFINED && Type != JSON_NULL; + } + + bool IsNull() const noexcept; + bool IsBoolean() const noexcept; + bool IsDouble() const noexcept; + bool IsString() const noexcept; + bool IsMap() const noexcept; + bool IsArray() const noexcept; + + /// @return true if JSON_INTEGER or (JSON_UINTEGER and Value <= Max<long long>) + bool IsInteger() const noexcept; + + /// @return true if JSON_UINTEGER or (JSON_INTEGER and Value >= 0) + bool IsUInteger() const noexcept; + + bool Has(const TStringBuf& key) const noexcept; + bool Has(size_t key) const noexcept; + + void Scan(IScanCallback& callback); + + /// Non-robust comparison. + bool operator==(const TJsonValue& rhs) const; + + bool operator!=(const TJsonValue& rhs) const { + return !(*this == rhs); + } + + void Swap(TJsonValue& rhs) noexcept; // save using util/ysaveload.h serialization (not to JSON stream) void Save(IOutputStream* s) const; @@ -191,28 +191,28 @@ namespace NJson { // load using util/ysaveload.h serialization (not as JSON stream) void Load(IInputStream* s); - static const TJsonValue UNDEFINED; + static const TJsonValue UNDEFINED; - private: - EJsonValueType Type = JSON_UNDEFINED; - union TValueUnion { - bool Boolean; - long long Integer; - unsigned long long UInteger; - double Double; - TString String; - TMapType* Map; - TArray* Array; + private: + EJsonValueType Type = JSON_UNDEFINED; + union TValueUnion { + bool Boolean; + long long Integer; + unsigned long long UInteger; + double Double; + TString String; + TMapType* Map; + TArray* Array; - TValueUnion() noexcept { + TValueUnion() noexcept { Zero(*this); - } - ~TValueUnion() noexcept { - } - }; - TValueUnion Value; - void DoScan(const TString& path, TJsonValue* parent, IScanCallback& callback); - void SwapWithUndefined(TJsonValue& output) noexcept; + } + ~TValueUnion() noexcept { + } + }; + TValueUnion Value; + void DoScan(const TString& path, TJsonValue* parent, IScanCallback& callback); + void SwapWithUndefined(TJsonValue& output) noexcept; /** @throw yexception if Back shouldn't be called on the object. @@ -220,51 +220,51 @@ namespace NJson { void BackChecks() const; }; - inline bool GetBoolean(const TJsonValue& jv, size_t index, bool* value) noexcept { - return jv[index].GetBoolean(value); - } + inline bool GetBoolean(const TJsonValue& jv, size_t index, bool* value) noexcept { + return jv[index].GetBoolean(value); + } - inline bool GetInteger(const TJsonValue& jv, size_t index, long long* value) noexcept { - return jv[index].GetInteger(value); - } + inline bool GetInteger(const TJsonValue& jv, size_t index, long long* value) noexcept { + return jv[index].GetInteger(value); + } - inline bool GetUInteger(const TJsonValue& jv, size_t index, unsigned long long* value) noexcept { - return jv[index].GetUInteger(value); - } + inline bool GetUInteger(const TJsonValue& jv, size_t index, unsigned long long* value) noexcept { + return jv[index].GetUInteger(value); + } - inline bool GetDouble(const TJsonValue& jv, size_t index, double* value) noexcept { - return jv[index].GetDouble(value); - } + inline bool GetDouble(const TJsonValue& jv, size_t index, double* value) noexcept { + return jv[index].GetDouble(value); + } - inline bool GetString(const TJsonValue& jv, size_t index, TString* value) { - return jv[index].GetString(value); - } + inline bool GetString(const TJsonValue& jv, size_t index, TString* value) { + return jv[index].GetString(value); + } - bool GetMapPointer(const TJsonValue& jv, size_t index, const TJsonValue::TMapType** value); - bool GetArrayPointer(const TJsonValue& jv, size_t index, const TJsonValue::TArray** value); + bool GetMapPointer(const TJsonValue& jv, size_t index, const TJsonValue::TMapType** value); + bool GetArrayPointer(const TJsonValue& jv, size_t index, const TJsonValue::TArray** value); - inline bool GetBoolean(const TJsonValue& jv, TStringBuf key, bool* value) noexcept { - return jv[key].GetBoolean(value); - } + inline bool GetBoolean(const TJsonValue& jv, TStringBuf key, bool* value) noexcept { + return jv[key].GetBoolean(value); + } - inline bool GetInteger(const TJsonValue& jv, TStringBuf key, long long* value) noexcept { - return jv[key].GetInteger(value); - } + inline bool GetInteger(const TJsonValue& jv, TStringBuf key, long long* value) noexcept { + return jv[key].GetInteger(value); + } - inline bool GetUInteger(const TJsonValue& jv, TStringBuf key, unsigned long long* value) noexcept { - return jv[key].GetUInteger(value); - } + inline bool GetUInteger(const TJsonValue& jv, TStringBuf key, unsigned long long* value) noexcept { + return jv[key].GetUInteger(value); + } - inline bool GetDouble(const TJsonValue& jv, TStringBuf key, double* value) noexcept { - return jv[key].GetDouble(value); - } + inline bool GetDouble(const TJsonValue& jv, TStringBuf key, double* value) noexcept { + return jv[key].GetDouble(value); + } - inline bool GetString(const TJsonValue& jv, TStringBuf key, TString* value) { - return jv[key].GetString(value); - } + inline bool GetString(const TJsonValue& jv, TStringBuf key, TString* value) { + return jv[key].GetString(value); + } - bool GetMapPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TMapType** value); - bool GetArrayPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TArray** value); + bool GetMapPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TMapType** value); + bool GetArrayPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TArray** value); class TJsonMap: public TJsonValue { public: diff --git a/library/cpp/json/writer/json_value_ut.cpp b/library/cpp/json/writer/json_value_ut.cpp index d3f3c42bea..dc7f6affdf 100644 --- a/library/cpp/json/writer/json_value_ut.cpp +++ b/library/cpp/json/writer/json_value_ut.cpp @@ -18,7 +18,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { TJsonValue emptyMap(JSON_MAP); UNIT_ASSERT(!undef.IsDefined()); - UNIT_ASSERT(!null.IsDefined()); // json NULL is undefined too! + UNIT_ASSERT(!null.IsDefined()); // json NULL is undefined too! UNIT_ASSERT(_false.IsDefined()); UNIT_ASSERT(zeroInt.IsDefined()); UNIT_ASSERT(zeroDouble.IsDefined()); @@ -259,7 +259,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { UNIT_ASSERT_EQUAL(lhs.GetValueByPath("l/a/c/e/x", '/'), NULL); UNIT_ASSERT_EQUAL(lhs.GetValueByPath("a/c/e/x", '/'), NULL); UNIT_ASSERT_EQUAL(lhs.GetValueByPath("nokey", '/'), NULL); - UNIT_ASSERT_EQUAL(*lhs.GetValueByPath("", '/'), lhs); // itself + UNIT_ASSERT_EQUAL(*lhs.GetValueByPath("", '/'), lhs); // itself TJsonValue array; TJsonValue third; @@ -325,7 +325,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { } { const TJsonValue* result = lhs.GetValueByPath("", '/'); - UNIT_ASSERT_EQUAL(*result, lhs); // itself + UNIT_ASSERT_EQUAL(*result, lhs); // itself } TJsonValue array; @@ -335,8 +335,8 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { third["t"] = array; UNIT_ASSERT(array.GetValueByPath("[0].e", '.')->GetStringRobust() == "f"); - UNIT_ASSERT(third.GetValueByPath("t.[0].e", '.')->GetStringRobust() == "f"); - UNIT_ASSERT(third.GetValueByPath("t.[1].c.e", '.')->GetStringRobust() == "f"); + UNIT_ASSERT(third.GetValueByPath("t.[0].e", '.')->GetStringRobust() == "f"); + UNIT_ASSERT(third.GetValueByPath("t.[1].c.e", '.')->GetStringRobust() == "f"); } Y_UNIT_TEST(EraseValueFromArray) { @@ -385,7 +385,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { value1.AppendValue(1); value1.AppendValue(2); src.InsertValue("key", value1); - src.InsertValue("key1", "HI!"); + src.InsertValue("key1", "HI!"); TJsonValue dst; TJsonValue value2; @@ -426,7 +426,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { dst.InsertValue("arr", arr2); src["arr"].AppendValue(value1); - for (auto& node : src["arr"].GetArraySafe()) { + for (auto& node : src["arr"].GetArraySafe()) { node.InsertValue("yek", "eulav"); } UNIT_ASSERT(src == dst); @@ -550,7 +550,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { outer.AppendValue(json); } - const TJsonValue::TArray* array = nullptr; + const TJsonValue::TArray* array = nullptr; GetArrayPointer(outer, 0, &array); UNIT_ASSERT_VALUES_EQUAL((*array)[1], 2); } @@ -565,7 +565,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { outer.InsertValue("x", json); } - const TJsonValue::TArray* array = nullptr; + const TJsonValue::TArray* array = nullptr; GetArrayPointer(outer, "x", &array); UNIT_ASSERT_VALUES_EQUAL((*array)[1], 2); } @@ -580,7 +580,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { outer.AppendValue(json); } - const TJsonValue::TMapType* map = nullptr; + const TJsonValue::TMapType* map = nullptr; GetMapPointer(outer, 0, &map); UNIT_ASSERT_VALUES_EQUAL((*map).at("b"), 2); } @@ -595,7 +595,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { outer.InsertValue("x", json); } - const TJsonValue::TMapType* map = nullptr; + const TJsonValue::TMapType* map = nullptr; GetMapPointer(outer, "x", &map); UNIT_ASSERT_VALUES_EQUAL((*map).at("b"), 2); } @@ -617,7 +617,7 @@ Y_UNIT_TEST_SUITE(TJsonValueTest) { const char* longTestString = "Testing TJsonValue& operator=(TJsonValue&&) subpart self moving " - "after TJsonValue was constrcuted from TString&&."; + "after TJsonValue was constrcuted from TString&&."; json["hello"] = TString{longTestString}; json = std::move(json["hello"]); diff --git a/library/cpp/json/writer/ya.make b/library/cpp/json/writer/ya.make index 1f1e2df08e..3989ff3504 100644 --- a/library/cpp/json/writer/ya.make +++ b/library/cpp/json/writer/ya.make @@ -5,8 +5,8 @@ OWNER( myltsev pg ) - -PEERDIR( + +PEERDIR( library/cpp/json/common ) |