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/yson_pull/read_ops.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/yson_pull/read_ops.h')
-rw-r--r-- | library/cpp/yson_pull/read_ops.h | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/library/cpp/yson_pull/read_ops.h b/library/cpp/yson_pull/read_ops.h new file mode 100644 index 0000000000..5c084983ea --- /dev/null +++ b/library/cpp/yson_pull/read_ops.h @@ -0,0 +1,142 @@ +#pragma once + +#include "reader.h" + +#include <util/generic/maybe.h> +#include <util/generic/bt_exception.h> +#include <util/generic/yexception.h> +#include <util/system/yassert.h> + +/** Imperative recursive-descent parsing helpers. + * + * These functions help verify conditions and advance parser state. + * For aggregate parsing functions, common precondition is to require Begin{X} + * event prior to function invocation. Thus, parsers are composable by calling + * sub-parser after dispatching on opening event, e.g.: + * + * if (reader.LastEvent().Type() == EEventType::BeginMap) { + * ReadSomeMap(reader) + * } + * + */ + +namespace NYsonPull { + namespace NReadOps { + class TExpectationFailure: public TWithBackTrace<yexception> { + }; + + inline void Expect(const TEvent& got, EEventType expected) { + Y_ENSURE_EX( + got.Type() == expected, + TExpectationFailure() << "expected " << expected << ", got " << got); + } + + inline void Expect(const TScalar& got, EScalarType expected) { + Y_ENSURE_EX( + got.Type() == expected, + TExpectationFailure() << "expected scalar " << expected << ", got " << got); + } + + // ExpectBegin{X} functions verify that last event WAS X + // SkipBegin{X} functions verify that next event WILL BE X and CONSUME it + + inline void ExpectBeginStream(TReader& reader) { + Expect(reader.LastEvent(), EEventType::BeginStream); + } + + inline void SkipBeginStream(TReader& reader) { + Expect(reader.NextEvent(), EEventType::BeginStream); + } + + inline void ExpectBeginMap(TReader& reader) { + Expect(reader.LastEvent(), EEventType::BeginMap); + } + + inline void SkipBeginMap(TReader& reader) { + Expect(reader.NextEvent(), EEventType::BeginMap); + } + + inline void ExpectBeginList(TReader& reader) { + Expect(reader.LastEvent(), EEventType::BeginList); + } + + inline void SkipBeginList(TReader& reader) { + Expect(reader.NextEvent(), EEventType::BeginList); + } + + inline bool ReadListItem(TReader& reader) { + return reader.NextEvent().Type() != EEventType::EndList; + } + + inline TMaybe<TStringBuf> ReadKey(TReader& reader) { + const auto& event = reader.NextEvent(); + switch (event.Type()) { + case EEventType::Key: + return event.AsString(); + case EEventType::EndMap: + return Nothing(); + default: + ythrow yexception() << "Unexpected event: " << event; + } + } + + template <typename T = const TScalar&> + inline T ReadScalar(TReader& reader); + + template <> + inline const TScalar& ReadScalar<const TScalar&>(TReader& reader) { + const auto& event = reader.NextEvent(); + Expect(event, EEventType::Scalar); + return event.AsScalar(); + } + + template <> + inline i64 ReadScalar<i64>(TReader& reader) { + const auto& scalar = ReadScalar(reader); + Expect(scalar, EScalarType::Int64); + return scalar.AsInt64(); + } + + template <> + inline ui64 ReadScalar<ui64>(TReader& reader) { + const auto& scalar = ReadScalar(reader); + Expect(scalar, EScalarType::UInt64); + return scalar.AsUInt64(); + } + + template <> + inline double ReadScalar<double>(TReader& reader) { + const auto& scalar = ReadScalar(reader); + Expect(scalar, EScalarType::Float64); + return scalar.AsFloat64(); + } + + template <> + inline TStringBuf ReadScalar<TStringBuf>(TReader& reader) { + const auto& scalar = ReadScalar(reader); + Expect(scalar, EScalarType::String); + return scalar.AsString(); + } + + template <> + inline TString ReadScalar<TString>(TReader& reader) { + return TString(ReadScalar<TStringBuf>(reader)); + } + + template <> + inline bool ReadScalar<bool>(TReader& reader) { + const auto& scalar = ReadScalar(reader); + Expect(scalar, EScalarType::Boolean); + return scalar.AsBoolean(); + } + + // Skip value that was already started with `event` + void SkipCurrentValue(const TEvent& event, TReader& reader); + + // Skip value that starts at `reader.next_event()` + void SkipValue(TReader& reader); + + // Skip values with attributes, wait for map value + void SkipControlRecords(TReader& reader); + } +} |