diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/yt/yson_string/convert.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/yt/yson_string/convert.cpp')
-rw-r--r-- | library/cpp/yt/yson_string/convert.cpp | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/library/cpp/yt/yson_string/convert.cpp b/library/cpp/yt/yson_string/convert.cpp new file mode 100644 index 0000000000..27f5c30d01 --- /dev/null +++ b/library/cpp/yt/yson_string/convert.cpp @@ -0,0 +1,381 @@ +#include "convert.h" +#include "format.h" + +#include <library/cpp/yt/assert/assert.h> + +#include <library/cpp/yt/string/format.h> + +#include <library/cpp/yt/coding/varint.h> + +#include <library/cpp/yt/misc/cast.h> + +#include <array> + +#include <util/stream/mem.h> + +namespace NYT::NYson { + +//////////////////////////////////////////////////////////////////////////////// + +template <> +TYsonString ConvertToYsonString<i8>(const i8& value) +{ + return ConvertToYsonString(static_cast<i64>(value)); +} + +template <> +TYsonString ConvertToYsonString<i32>(const i32& value) +{ + return ConvertToYsonString(static_cast<i64>(value)); +} + +template <> +TYsonString ConvertToYsonString<i64>(const i64& value) +{ + std::array<char, 1 + MaxVarInt64Size> buffer; + auto* ptr = buffer.data(); + *ptr++ = NDetail::Int64Marker; + ptr += WriteVarInt64(ptr, value); + return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data())); +} + +template <> +TYsonString ConvertToYsonString<ui8>(const ui8& value) +{ + return ConvertToYsonString(static_cast<ui64>(value)); +} + +template <> +TYsonString ConvertToYsonString<ui32>(const ui32& value) +{ + return ConvertToYsonString(static_cast<ui64>(value)); +} + +template <> +TYsonString ConvertToYsonString<ui64>(const ui64& value) +{ + std::array<char, 1 + MaxVarInt64Size> buffer; + auto* ptr = buffer.data(); + *ptr++ = NDetail::Uint64Marker; + ptr += WriteVarUint64(ptr, value); + return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data())); +} + +template <> +TYsonString ConvertToYsonString<TString>(const TString& value) +{ + return ConvertToYsonString(static_cast<TStringBuf>(value)); +} + +struct TConvertStringToYsonStringTag +{ }; + +template <> +TYsonString ConvertToYsonString<TStringBuf>(const TStringBuf& value) +{ + auto buffer = TSharedMutableRef::Allocate<TConvertStringToYsonStringTag>( + 1 + MaxVarInt64Size + value.length(), + /*initializeStorage*/ false); + auto* ptr = buffer.Begin(); + *ptr++ = NDetail::StringMarker; + ptr += WriteVarInt64(ptr, static_cast<i64>(value.length())); + ::memcpy(ptr, value.data(), value.length()); + ptr += value.length(); + return TYsonString(buffer.Slice(buffer.Begin(), ptr)); +} + +TYsonString ConvertToYsonString(const char* value) +{ + return ConvertToYsonString(TStringBuf(value)); +} + +template <> +TYsonString ConvertToYsonString<float>(const float& value) +{ + return ConvertToYsonString(static_cast<double>(value)); +} + +template <> +TYsonString ConvertToYsonString<double>(const double& value) +{ + std::array<char, 1 + sizeof(double)> buffer; + auto* ptr = buffer.data(); + *ptr++ = NDetail::DoubleMarker; + ::memcpy(ptr, &value, sizeof(value)); + ptr += sizeof(value); + return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data())); +} + +template <> +TYsonString ConvertToYsonString<bool>(const bool& value) +{ + char ch = value ? NDetail::TrueMarker : NDetail::FalseMarker; + return TYsonString(TStringBuf(&ch, 1)); +} + +template <> +TYsonString ConvertToYsonString<TInstant>(const TInstant& value) +{ + return ConvertToYsonString(value.ToString()); +} + +template <> +TYsonString ConvertToYsonString<TDuration>(const TDuration& value) +{ + return ConvertToYsonString(value.MilliSeconds()); +} + +template <> +TYsonString ConvertToYsonString<TGuid>(const TGuid& value) +{ + std::array<char, MaxGuidStringSize> guidBuffer; + auto guidLength = WriteGuidToBuffer(guidBuffer.data(), value) - guidBuffer.data(); + std::array<char, 1 + MaxVarInt64Size + MaxGuidStringSize> ysonBuffer; + auto* ptr = ysonBuffer.data(); + *ptr++ = NDetail::StringMarker; + ptr += WriteVarInt64(ptr, static_cast<i64>(guidLength)); + ::memcpy(ptr, guidBuffer.data(), guidLength); + ptr += guidLength; + return TYsonString(TStringBuf(ysonBuffer.data(), ptr - ysonBuffer.data())); +} + +//////////////////////////////////////////////////////////////////////////////// + +namespace { + +TString FormatUnexpectedMarker(char ch) +{ + switch (ch) { + case NDetail::BeginListSymbol: + return "list"; + case NDetail::BeginMapSymbol: + return "map"; + case NDetail::BeginAttributesSymbol: + return "attributes"; + case NDetail::EntitySymbol: + return "\"entity\" literal"; + case NDetail::StringMarker: + return "\"string\" literal"; + case NDetail::Int64Marker: + return "\"int64\" literal"; + case NDetail::DoubleMarker: + return "\"double\" literal"; + case NDetail::FalseMarker: + case NDetail::TrueMarker: + return "\"boolean\" literal"; + case NDetail::Uint64Marker: + return "\"uint64\" literal"; + default: + return Format("unexpected symbol %qv", ch); + } +} + +i64 ParseInt64FromYsonString(const TYsonStringBuf& str) +{ + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::Int64Marker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + i64 result; + try { + ReadVarInt64(&input, &result); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Failed to decode \"int64\" value"); + } + return result; +} + +ui64 ParseUint64FromYsonString(const TYsonStringBuf& str) +{ + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::Uint64Marker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + ui64 result; + try { + ReadVarUint64(&input, &result); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Failed to decode \"uint64\" value"); + } + return result; +} + +TString ParseStringFromYsonString(const TYsonStringBuf& str) +{ + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::StringMarker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + i64 length; + try { + ReadVarInt64(&input, &length); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Failed to decode string length"); + } + if (length < 0) { + throw TYsonLiteralParseException(Format("Negative string length ", + length)); + } + if (static_cast<i64>(input.Avail()) != length) { + throw TYsonLiteralParseException(Format("Incorrect remaining string length: expected %v, got %v", + length, + input.Avail())); + } + TString result; + result.ReserveAndResize(length); + YT_VERIFY(static_cast<i64>(input.Read(result.Detach(), length)) == length); + return result; +} + +double ParseDoubleFromYsonString(const TYsonStringBuf& str) +{ + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::DoubleMarker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + if (input.Avail() != sizeof(double)) { + throw TYsonLiteralParseException(Format("Incorrect remaining string length: expected %v, got %v", + sizeof(double), + input.Avail())); + } + double result; + YT_VERIFY(input.Read(&result, sizeof(result))); + return result; +} + +} // namespace + +#define PARSE(type, underlyingType) \ + template <> \ + type ConvertFromYsonString<type>(const TYsonStringBuf& str) \ + { \ + try { \ + return CheckedIntegralCast<type>(Parse ## underlyingType ## FromYsonString(str)); \ + } catch (const std::exception& ex) { \ + throw TYsonLiteralParseException(ex, "Error parsing \"" #type "\" value from YSON"); \ + } \ + } + +PARSE(i8, Int64 ) +PARSE(i16, Int64 ) +PARSE(i32, Int64 ) +PARSE(i64, Int64 ) +PARSE(ui8, Uint64) +PARSE(ui16, Uint64) +PARSE(ui32, Uint64) +PARSE(ui64, Uint64) + +#undef PARSE + +template <> +TString ConvertFromYsonString<TString>(const TYsonStringBuf& str) +{ + try { + return ParseStringFromYsonString(str); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"string\" value from YSON"); + } +} + +template <> +float ConvertFromYsonString<float>(const TYsonStringBuf& str) +{ + try { + return static_cast<float>(ParseDoubleFromYsonString(str)); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"float\" value from YSON"); + } +} + +template <> +double ConvertFromYsonString<double>(const TYsonStringBuf& str) +{ + try { + return ParseDoubleFromYsonString(str); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"double\" value from YSON"); + } +} + +template <> +bool ConvertFromYsonString<bool>(const TYsonStringBuf& str) +{ + try { + YT_ASSERT(str.GetType() == EYsonType::Node); + auto strBuf = str.AsStringBuf(); + TMemoryInput input(strBuf.data(), strBuf.length()); + char ch; + if (!input.ReadChar(ch)) { + throw TYsonLiteralParseException("Missing type marker"); + } + if (ch != NDetail::TrueMarker && ch != NDetail::FalseMarker) { + throw TYsonLiteralParseException(Format("Unexpected %v", + FormatUnexpectedMarker(ch))); + } + return ch == NDetail::TrueMarker; + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"boolean\" value from YSON"); + } +} + +template <> +TInstant ConvertFromYsonString<TInstant>(const TYsonStringBuf& str) +{ + try { + return TInstant::ParseIso8601(ParseStringFromYsonString(str)); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"instant\" value from YSON"); + } +} + +template <> +TDuration ConvertFromYsonString<TDuration>(const TYsonStringBuf& str) +{ + try { + return TDuration::MilliSeconds(ParseUint64FromYsonString(str)); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"duration\" value from YSON"); + } +} + +template <> +TGuid ConvertFromYsonString<TGuid>(const TYsonStringBuf& str) +{ + try { + return TGuid::FromString(ParseStringFromYsonString(str)); + } catch (const std::exception& ex) { + throw TYsonLiteralParseException(ex, "Error parsing \"guid\" value from YSON"); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NYson |