123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- #pragma once
- #include "byte_writer.h"
- #include "cescape.h"
- #include "percent_scalar.h"
- #include "stream_counter.h"
- #include "symbols.h"
- #include "varint.h"
- #include <library/cpp/yson_pull/consumer.h>
- #include <library/cpp/yson_pull/event.h>
- #include <library/cpp/yson_pull/output.h>
- #include <library/cpp/yson_pull/stream_type.h>
- #include <library/cpp/yson_pull/writer.h>
- #include <util/generic/vector.h>
- #include <util/system/yassert.h>
- #include <cmath>
- namespace NYsonPull {
- namespace NDetail {
- class writer: public IConsumer {
- enum class state {
- maybe_key,
- maybe_value,
- value,
- value_noattr,
- before_begin,
- before_end,
- after_end,
- };
- byte_writer<stream_counter<false>> stream_;
- TVector<EEventType> stack_;
- bool need_item_separator_ = false;
- EStreamType mode_ = EStreamType::ListFragment;
- state state_ = state::before_begin;
- public:
- void OnBeginStream() override {
- update_state(EEventType::BeginStream);
- }
- void OnEndStream() override {
- update_state(EEventType::EndStream);
- stream_.flush_buffer();
- }
- void OnBeginList() override {
- begin_node();
- write(NSymbol::begin_list);
- update_state(EEventType::BeginList);
- begin_collection(collection_type::list);
- }
- void OnEndList() override {
- update_state(EEventType::EndList);
- end_collection(collection_type::list);
- write(NSymbol::end_list);
- end_node();
- }
- void OnBeginMap() override {
- begin_node();
- write(NSymbol::begin_map);
- update_state(EEventType::BeginMap);
- begin_collection(collection_type::map);
- }
- void OnEndMap() override {
- update_state(EEventType::EndMap);
- end_collection(collection_type::map);
- write(NSymbol::end_map);
- end_node();
- }
- void OnBeginAttributes() override {
- begin_node();
- write(NSymbol::begin_attributes);
- update_state(EEventType::BeginAttributes);
- begin_collection(collection_type::attributes);
- }
- void OnEndAttributes() override {
- update_state(EEventType::EndAttributes);
- end_collection(collection_type::attributes);
- write(NSymbol::end_attributes);
- // no end_node
- }
- void OnEntity() override {
- begin_node();
- update_state(EEventType::Scalar);
- write(NSymbol::entity);
- end_node();
- }
- protected:
- enum class collection_type {
- list,
- map,
- attributes,
- };
- writer(NYsonPull::NOutput::IStream& stream, EStreamType mode)
- : stream_(stream)
- , mode_{mode} {
- }
- bool need_item_separator() const {
- return need_item_separator_;
- }
- void need_item_separator(bool value) {
- need_item_separator_ = value;
- }
- size_t depth() const {
- Y_ASSERT(!stack_.empty());
- if (mode_ == EStreamType::Node) {
- return stack_.size() - 1;
- } else {
- return stack_.size() - 2;
- }
- }
- EStreamType mode() const {
- return mode_;
- }
- void write(ui8 c) {
- stream_.write(c);
- }
- void write(TStringBuf value) {
- write_raw(value.data(), value.size());
- }
- void write_raw(const void* ptr, size_t len) {
- stream_.write(static_cast<const ui8*>(ptr), len);
- }
- template <typename T>
- void write_varint(T value) {
- NVarInt::write(stream_, value);
- }
- void write_escaped_string(TStringBuf value) {
- write(NSymbol::quote);
- NCEscape::encode(stream_, value);
- write(NSymbol::quote);
- }
- void push(EEventType type) {
- stack_.push_back(type);
- }
- void pop(EEventType type) {
- if (stack_.empty()) {
- fail("Unpaired events: empty event stack");
- }
- if (stack_.back() != type) {
- fail("Unpaired events: expected ", type, ", got ", stack_.back());
- }
- stack_.pop_back();
- }
- void update_state(EEventType event) {
- switch (state_) {
- case state::before_begin:
- if (event != EEventType::BeginStream) {
- fail("Expected begin_stream, got ", event);
- }
- begin_stream();
- return;
- case state::before_end:
- if (event != EEventType::EndStream) {
- fail("Expected end_stream, got ", event);
- }
- end_stream();
- return;
- case state::after_end:
- fail("Attempted write past stream end");
- case state::maybe_key:
- if (event == EEventType::Key) {
- state_ = state::value;
- return;
- }
- switch (event) {
- case EEventType::EndStream:
- end_stream();
- return;
- case EEventType::EndMap:
- pop(EEventType::BeginMap);
- next_state();
- return;
- case EEventType::EndAttributes:
- pop(EEventType::BeginAttributes);
- state_ = state::value_noattr;
- return;
- default:
- fail("Unexpected event ", event, " in maybe_key");
- }
- break;
- case state::maybe_value:
- switch (event) {
- case EEventType::EndList:
- pop(EEventType::BeginList);
- next_state();
- return;
- case EEventType::EndStream:
- end_stream();
- return;
- default:
- break;
- }
- [[fallthrough]];
- case state::value:
- if (event == EEventType::BeginAttributes) {
- push(EEventType::BeginAttributes);
- next_state();
- return;
- }
- [[fallthrough]];
- case state::value_noattr:
- switch (event) {
- case EEventType::Scalar:
- next_state();
- return;
- case EEventType::BeginList:
- push(EEventType::BeginList);
- next_state();
- return;
- case EEventType::BeginMap:
- push(EEventType::BeginMap);
- next_state();
- return;
- default:
- fail("Unexpected event ", event, " (in value_*)");
- }
- break;
- }
- }
- void next_state() {
- Y_ASSERT(!stack_.empty());
- switch (stack_.back()) {
- case EEventType::BeginMap:
- case EEventType::BeginAttributes:
- state_ = state::maybe_key;
- break;
- case EEventType::BeginList:
- state_ = state::maybe_value;
- break;
- case EEventType::BeginStream:
- state_ = state::before_end;
- break;
- default:
- Y_UNREACHABLE();
- }
- }
- void begin_stream() {
- push(EEventType::BeginStream);
- switch (mode_) {
- case EStreamType::ListFragment:
- push(EEventType::BeginList);
- state_ = state::maybe_value;
- break;
- case EStreamType::MapFragment:
- push(EEventType::BeginMap);
- state_ = state::maybe_key;
- break;
- case EStreamType::Node:
- state_ = state::value;
- break;
- }
- }
- void end_stream() {
- switch (mode_) {
- case EStreamType::ListFragment:
- pop(EEventType::BeginList);
- break;
- case EStreamType::MapFragment:
- pop(EEventType::BeginMap);
- break;
- case EStreamType::Node:
- break;
- }
- pop(EEventType::BeginStream);
- state_ = state::after_end;
- }
- virtual void begin_node() {
- if (need_item_separator_) {
- write(NSymbol::item_separator);
- }
- }
- virtual void end_node() {
- need_item_separator_ = true;
- }
- virtual void begin_key() {
- begin_node();
- }
- virtual void end_key() {
- need_item_separator_ = false;
- write(NSymbol::key_value_separator);
- }
- virtual void begin_collection(collection_type type) {
- Y_UNUSED(type);
- need_item_separator_ = false;
- }
- virtual void end_collection(collection_type type) {
- need_item_separator_ = (type != collection_type::attributes);
- }
- template <typename... Args>
- ATTRIBUTE(noinline, cold)
- void fail[[noreturn]](const char* msg, Args&&... args) {
- auto formatted_message = format_string(
- msg,
- std::forward<Args>(args)...);
- throw NException::TBadOutput(
- formatted_message,
- stream_.counter().info());
- }
- };
- class TBinaryWriterImpl final: public writer {
- public:
- TBinaryWriterImpl(NYsonPull::NOutput::IStream& stream, EStreamType mode)
- : writer(stream, mode)
- {
- }
- void OnScalarBoolean(bool value) override {
- update_state(EEventType::Scalar);
- begin_node();
- write(value ? NSymbol::true_marker : NSymbol::false_marker);
- end_node();
- }
- void OnScalarInt64(i64 value) override {
- update_state(EEventType::Scalar);
- begin_node();
- write(NSymbol::int64_marker);
- write_varint(value);
- end_node();
- }
- void OnScalarUInt64(ui64 value) override {
- update_state(EEventType::Scalar);
- begin_node();
- write(NSymbol::uint64_marker);
- write_varint(value);
- end_node();
- }
- void OnScalarFloat64(double value) override {
- update_state(EEventType::Scalar);
- begin_node();
- write(NSymbol::double_marker);
- write_raw(&value, sizeof value);
- end_node();
- }
- void OnScalarString(TStringBuf value) override {
- update_state(EEventType::Scalar);
- begin_node();
- write(NSymbol::string_marker);
- write_varint(static_cast<i32>(value.size()));
- write_raw(value.data(), value.size());
- end_node();
- }
- void OnKey(TStringBuf name) override {
- update_state(EEventType::Key);
- begin_key();
- write(NSymbol::string_marker);
- write_varint(static_cast<i32>(name.size()));
- write_raw(name.data(), name.size());
- end_key();
- }
- };
- class TTextWriterImpl: public writer {
- public:
- TTextWriterImpl(NYsonPull::NOutput::IStream& stream, EStreamType mode)
- : writer(stream, mode)
- {
- }
- void OnScalarBoolean(bool value) override {
- update_state(EEventType::Scalar);
- begin_node();
- write(value ? percent_scalar::true_literal : percent_scalar::false_literal);
- end_node();
- }
- void OnScalarInt64(i64 value) override {
- update_state(EEventType::Scalar);
- char buf[32];
- auto len = ::snprintf(buf, sizeof(buf), "%" PRIi64, value);
- begin_node();
- write_raw(buf, len);
- end_node();
- }
- void OnScalarUInt64(ui64 value) override {
- update_state(EEventType::Scalar);
- char buf[32];
- auto len = ::snprintf(buf, sizeof(buf), "%" PRIu64, value);
- begin_node();
- write_raw(buf, len);
- write('u');
- end_node();
- }
- void OnScalarFloat64(double value) override {
- update_state(EEventType::Scalar);
- begin_node();
- if (std::isfinite(value)) {
- char buf[32];
- auto len = ::snprintf(buf, sizeof(buf), "%#.17lg", value);
- write_raw(buf, len);
- } else if (std::isnan(value)) {
- write(percent_scalar::nan_literal);
- } else if (value > 0) {
- write(percent_scalar::positive_inf_literal);
- } else {
- write(percent_scalar::negative_inf_literal);
- }
- end_node();
- }
- void OnScalarString(TStringBuf value) override {
- update_state(EEventType::Scalar);
- begin_node();
- write_escaped_string(value);
- end_node();
- }
- void OnKey(TStringBuf name) override {
- update_state(EEventType::Key);
- begin_key();
- write_escaped_string(name);
- end_key();
- }
- protected:
- void begin_node() override {
- if (need_item_separator()) {
- write(NSymbol::item_separator);
- write(' ');
- }
- }
- void end_node() override {
- if (mode() != EStreamType::Node && depth() == 0) {
- write(NSymbol::item_separator);
- write('\n');
- need_item_separator(false);
- } else {
- writer::end_node();
- }
- }
- void end_key() override {
- write(' ');
- writer::end_key();
- write(' ');
- }
- };
- class TPrettyWriterImpl final: public TTextWriterImpl {
- size_t indent_size_;
- public:
- TPrettyWriterImpl(
- NYsonPull::NOutput::IStream& stream,
- EStreamType mode,
- size_t indent_size)
- : TTextWriterImpl(stream, mode)
- , indent_size_{indent_size} {
- }
- protected:
- void begin_node() override {
- if (need_item_separator()) {
- write(NSymbol::item_separator);
- newline();
- }
- }
- void begin_collection(collection_type type) override {
- TTextWriterImpl::begin_collection(type);
- newline();
- }
- void end_collection(collection_type type) override {
- TTextWriterImpl::end_collection(type);
- newline();
- }
- void newline() {
- write('\n');
- indent(depth());
- }
- void indent(size_t count) {
- for (size_t i = 0; i < count * indent_size_; ++i) {
- write(' ');
- }
- }
- };
- template <typename T, typename... Args>
- NYsonPull::TWriter make_writer(
- THolder<NYsonPull::NOutput::IStream> stream,
- Args&&... args) {
- auto impl = MakeHolder<T>(*stream, std::forward<Args>(args)...);
- return NYsonPull::TWriter(std::move(stream), std::move(impl));
- }
- }
- }
|