aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2023-05-05 11:09:01 +0300
committerDaniil Cherednik <dan.cherednik@gmail.com>2023-05-05 11:09:01 +0300
commitb5a989b16cafa8a3b3bc076f1097a0eda6f48c06 (patch)
tree4da744117a5aab37758921fa43b95a3068e5aec1 /library/cpp/yaml/fyamlcpp/fyamlcpp.cpp
parentfc1cffcfa7f0497a1f97b384a24bcbf23362f3be (diff)
downloadydb-b5a989b16cafa8a3b3bc076f1097a0eda6f48c06.tar.gz
Ydb stable 23-1-2623.1.26
x-stable-origin-commit: 22184a7e157553d447f17a2dffc4ea2d32dfd74d
Diffstat (limited to 'library/cpp/yaml/fyamlcpp/fyamlcpp.cpp')
-rw-r--r--library/cpp/yaml/fyamlcpp/fyamlcpp.cpp969
1 files changed, 969 insertions, 0 deletions
diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp
new file mode 100644
index 0000000000..b8d8b17596
--- /dev/null
+++ b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp
@@ -0,0 +1,969 @@
+#include "fyamlcpp.h"
+
+#include <contrib/libs/libfyaml/include/libfyaml.h>
+
+#include <util/digest/murmur.h>
+
+namespace NFyaml {
+
+#define ENSURE_NODE_NOT_EMPTY(NODE) Y_ENSURE_EX(NODE, TFyamlEx() << "Expected non-empty Node")
+#define ENSURE_DOCUMENT_NOT_EMPTY(NODE) Y_ENSURE_EX(NODE, TFyamlEx() << "Expected non-empty Document")
+
+const char* zstr = "";
+
+enum class EErrorType {
+ Debug = FYET_DEBUG,
+ Info = FYET_INFO,
+ Notice = FYET_NOTICE,
+ Warning = FYET_WARNING,
+ Error = FYET_ERROR,
+ Max = FYET_MAX,
+};
+
+enum class EErrorModule {
+ Unknown = FYEM_UNKNOWN,
+ Atom = FYEM_ATOM,
+ Scan = FYEM_SCAN,
+ Parse = FYEM_PARSE,
+ Doc = FYEM_DOC,
+ Build = FYEM_BUILD,
+ Internal = FYEM_INTERNAL,
+ System = FYEM_SYSTEM,
+ Max = FYEM_MAX,
+};
+
+enum class EParseCfgFlags {
+ Quiet = FYPCF_QUIET,
+ CollectDiag = FYPCF_COLLECT_DIAG,
+ ResolveDocument = FYPCF_RESOLVE_DOCUMENT,
+ DisableMmapOpt = FYPCF_DISABLE_MMAP_OPT,
+ DisableRecycling = FYPCF_DISABLE_RECYCLING,
+ ParseComments = FYPCF_PARSE_COMMENTS,
+ DisableDepth_limit = FYPCF_DISABLE_DEPTH_LIMIT,
+ DisableAccelerators = FYPCF_DISABLE_ACCELERATORS,
+ DisableBuffering = FYPCF_DISABLE_BUFFERING,
+ DefaultVersionAuto = FYPCF_DEFAULT_VERSION_AUTO,
+ DefaultVersion1_1 = FYPCF_DEFAULT_VERSION_1_1,
+ DefaultVersion1_2 = FYPCF_DEFAULT_VERSION_1_2,
+ DefaultVersion1_3 = FYPCF_DEFAULT_VERSION_1_3,
+ SloppyFlowIndentation = FYPCF_SLOPPY_FLOW_INDENTATION,
+ PreferRecursive = FYPCF_PREFER_RECURSIVE,
+ JsonAuto = FYPCF_JSON_AUTO,
+ JsonNone = FYPCF_JSON_NONE,
+ JsonForce = FYPCF_JSON_FORCE,
+ YpathAliases = FYPCF_YPATH_ALIASES,
+ AllowDuplicateKeys = FYPCF_ALLOW_DUPLICATE_KEYS,
+};
+
+enum class EEventType {
+ None = FYET_NONE,
+ StreamStart = FYET_STREAM_START,
+ StreamEnd = FYET_STREAM_END,
+ DocumentStart = FYET_DOCUMENT_START,
+ DocumentEnd = FYET_DOCUMENT_END,
+ MappingStart = FYET_MAPPING_START,
+ MappingEnd = FYET_MAPPING_END,
+ SequenceStart = FYET_SEQUENCE_START,
+ SequenceEnd = FYET_SEQUENCE_END,
+ Scalar = FYET_SCALAR,
+ Alias = FYET_ALIAS,
+};
+
+enum class EScalarStyle {
+ Any = FYSS_ANY,
+ Plain = FYSS_PLAIN,
+ SingleQuoted = FYSS_SINGLE_QUOTED,
+ DoubleQuoted = FYSS_DOUBLE_QUOTED,
+ Literal = FYSS_LITERAL,
+ Folded = FYSS_FOLDED,
+ Max = FYSS_MAX,
+};
+
+enum class EEmitterWriteType {
+ DocumentIndicator = fyewt_document_indicator,
+ TagDirective = fyewt_tag_directive,
+ VersionDirective = fyewt_version_directive,
+ Indent = fyewt_indent,
+ Indicator = fyewt_indicator,
+ Whitespace = fyewt_whitespace,
+ PlainScalar = fyewt_plain_scalar,
+ SingleQuotedScalar = fyewt_single_quoted_scalar,
+ DoubleQuotedScalar = fyewt_double_quoted_scalar,
+ LiteralScalar = fyewt_literal_scalar,
+ FoldedScalar = fyewt_folded_scalar,
+ Anchor = fyewt_anchor,
+ Tag = fyewt_tag,
+ Linebreak = fyewt_linebreak,
+ Alias = fyewt_alias,
+ TerminatingZero = fyewt_terminating_zero,
+ PlainScalarKey = fyewt_plain_scalar_key,
+ SingleQuotedScalarKey = fyewt_single_quoted_scalar_key,
+ DoubleQuotedScalarKey = fyewt_double_quoted_scalar_key,
+ Comment = fyewt_comment,
+};
+
+enum class ECommentPlacement {
+ Top = fycp_top,
+ Right = fycp_right,
+ Bottom = fycp_bottom,
+};
+
+enum EEmitterCfgFlags {
+ SortKeys = FYECF_SORT_KEYS,
+ OutputComments = FYECF_OUTPUT_COMMENTS,
+ StripLabels = FYECF_STRIP_LABELS,
+ StripTags = FYECF_STRIP_TAGS,
+ StripDoc = FYECF_STRIP_DOC,
+ NoEndingNewline = FYECF_NO_ENDING_NEWLINE,
+ StripEmptyKv = FYECF_STRIP_EMPTY_KV,
+ IndentDefault = FYECF_INDENT_DEFAULT,
+ Indent1 = FYECF_INDENT_1,
+ Indent2 = FYECF_INDENT_2,
+ Indent3 = FYECF_INDENT_3,
+ Indent4 = FYECF_INDENT_4,
+ Indent5 = FYECF_INDENT_5,
+ Indent6 = FYECF_INDENT_6,
+ Indent7 = FYECF_INDENT_7,
+ Indent8 = FYECF_INDENT_8,
+ Indent9 = FYECF_INDENT_9,
+ WidthDefault = FYECF_WIDTH_DEFAULT,
+ Width80 = FYECF_WIDTH_80,
+ Width132 = FYECF_WIDTH_132,
+ WidthInf = FYECF_WIDTH_INF,
+ ModeOriginal = FYECF_MODE_ORIGINAL,
+ ModeBlock = FYECF_MODE_BLOCK,
+ ModeFlow = FYECF_MODE_FLOW,
+ ModeFlowOneline = FYECF_MODE_FLOW_ONELINE,
+ ModeJson = FYECF_MODE_JSON,
+ ModeJsonTp = FYECF_MODE_JSON_TP,
+ ModeJsonOneline = FYECF_MODE_JSON_ONELINE,
+ ModeDejson = FYECF_MODE_DEJSON,
+ ModePretty = FYECF_MODE_PRETTY,
+ DocStartMarkAuto = FYECF_DOC_START_MARK_AUTO,
+ DocStartMarkOff = FYECF_DOC_START_MARK_OFF,
+ DocStartMarkOn = FYECF_DOC_START_MARK_ON,
+ DocEndMarkAuto = FYECF_DOC_END_MARK_AUTO,
+ DocEndMarkOff = FYECF_DOC_END_MARK_OFF,
+ DocEndMarkOn = FYECF_DOC_END_MARK_ON,
+ VersionDirAuto = FYECF_VERSION_DIR_AUTO,
+ VersionDirOff = FYECF_VERSION_DIR_OFF,
+ VersionDirOn = FYECF_VERSION_DIR_ON,
+ TagDirAuto = FYECF_TAG_DIR_AUTO,
+ TagDirOff = FYECF_TAG_DIR_OFF,
+ TagDirOn = FYECF_TAG_DIR_ON,
+
+ Default = FYECF_DEFAULT,
+};
+
+enum class ENodeStyle {
+ Any = FYNS_ANY,
+ Flow = FYNS_FLOW,
+ Block = FYNS_BLOCK,
+ Plain = FYNS_PLAIN,
+ SingleQuoted = FYNS_SINGLE_QUOTED,
+ DoubleQuoted = FYNS_DOUBLE_QUOTED,
+ Literal = FYNS_LITERAL,
+ Folded = FYNS_FOLDED,
+ Alias = FYNS_ALIAS,
+};
+
+enum class ENodeWalkFlags {
+ DontFollow = FYNWF_DONT_FOLLOW,
+ Follow = FYNWF_FOLLOW,
+ PtrYaml = FYNWF_PTR_YAML,
+ PtrJson = FYNWF_PTR_JSON,
+ PtrReljson = FYNWF_PTR_RELJSON,
+ PtrYpath = FYNWF_PTR_YPATH,
+ UriEncoded = FYNWF_URI_ENCODED,
+ MaxdepthDefault = FYNWF_MAXDEPTH_DEFAULT,
+ MarkerDefault = FYNWF_MARKER_DEFAULT,
+ PtrDefault = FYNWF_PTR_DEFAULT,
+};
+
+enum class EPathParseCfgFlags {
+ Quiet = FYPPCF_QUIET,
+ DisableRecycling = FYPPCF_DISABLE_RECYCLING,
+ DisableAccelerators = FYPPCF_DISABLE_ACCELERATORS,
+};
+
+enum class EPathExecCfgFlags {
+ Quiet = FYPXCF_QUIET,
+ DisableRecycling = FYPXCF_DISABLE_RECYCLING,
+ DisableAccelerators = FYPXCF_DISABLE_ACCELERATORS,
+};
+
+enum class ETokenType {
+ /* non-content token types */
+ None = FYTT_NONE,
+ StreamStart = FYTT_STREAM_START,
+ StreamEnd = FYTT_STREAM_END,
+ VersionDirective = FYTT_VERSION_DIRECTIVE,
+ TagDirective = FYTT_TAG_DIRECTIVE,
+ DocumentStart = FYTT_DOCUMENT_START,
+ DocumentEnd = FYTT_DOCUMENT_END,
+ /* content token types */
+ BlockSequenceStart = FYTT_BLOCK_SEQUENCE_START,
+ BlockMappingStart = FYTT_BLOCK_MAPPING_START,
+ BlockEnd = FYTT_BLOCK_END,
+ FlowSequenceStart = FYTT_FLOW_SEQUENCE_START,
+ FlowSequenceEnd = FYTT_FLOW_SEQUENCE_END,
+ FlowMappingStart = FYTT_FLOW_MAPPING_START,
+ FlowMappingEnd = FYTT_FLOW_MAPPING_END,
+ BlockEntry = FYTT_BLOCK_ENTRY,
+ FlowEntry = FYTT_FLOW_ENTRY,
+ Key = FYTT_KEY,
+ Value = FYTT_VALUE,
+ Alias = FYTT_ALIAS,
+ Anchor = FYTT_ANCHOR,
+ Tag = FYTT_TAG,
+ Scalar = FYTT_SCALAR,
+
+ /* special error reporting */
+ Input_marker = FYTT_INPUT_MARKER,
+
+ /* path expression tokens */
+ PeSlash = FYTT_PE_SLASH,
+ PeRoot = FYTT_PE_ROOT,
+ PeThis = FYTT_PE_THIS,
+ PeParent = FYTT_PE_PARENT,
+ PeMapKey = FYTT_PE_MAP_KEY,
+ PeSeqIndex = FYTT_PE_SEQ_INDEX,
+ PeSeqSlice = FYTT_PE_SEQ_SLICE,
+ PeScalarFilter = FYTT_PE_SCALAR_FILTER,
+ PeCollectionFilter = FYTT_PE_COLLECTION_FILTER,
+ PeSeqFilter = FYTT_PE_SEQ_FILTER,
+ PeMapFilter = FYTT_PE_MAP_FILTER,
+ PeUniqueFilter = FYTT_PE_UNIQUE_FILTER,
+ PeEveryChild = FYTT_PE_EVERY_CHILD,
+ PeEveryChildR = FYTT_PE_EVERY_CHILD_R,
+ PeAlias = FYTT_PE_ALIAS,
+ PeSibling = FYTT_PE_SIBLING,
+ PeComma = FYTT_PE_COMMA,
+ PeBarbar = FYTT_PE_BARBAR,
+ PeAmpamp = FYTT_PE_AMPAMP,
+ PeLparen = FYTT_PE_LPAREN,
+ PeRparen = FYTT_PE_RPAREN,
+
+ /* comparison operators */
+ PeEqeq = FYTT_PE_EQEQ,
+ PeNoteq = FYTT_PE_NOTEQ,
+ PeLt = FYTT_PE_LT,
+ PeGt = FYTT_PE_GT,
+ PeLte = FYTT_PE_LTE,
+ PeGte = FYTT_PE_GTE,
+
+ /* scalar expression tokens */
+ SePlus = FYTT_SE_PLUS,
+ SeMinus = FYTT_SE_MINUS,
+ SeMult = FYTT_SE_MULT,
+ SeDiv = FYTT_SE_DIV,
+
+ PeMethod = FYTT_PE_METHOD,
+ SeMethod = FYTT_SE_METHOD,
+};
+
+enum class EComposerReturn {
+ OkContinue = FYCR_OK_CONTINUE,
+ OkStop = FYCR_OK_STOP,
+ OkStartSkip = FYCR_OK_START_SKIP,
+ OkStopSkip = FYCR_OK_STOP_SKIP,
+ Error = FYCR_ERROR,
+};
+
+TDocumentIterator::TDocumentIterator(fy_document_iterator* iterator)
+ : Iterator_(iterator, fy_document_iterator_destroy)
+{}
+
+TNode TNodeRef::CreateReference() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return TNode(fy_node_create_reference(Node_));
+}
+
+TNode TNodeRef::Copy() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return TNode(fy_node_copy(fy_node_document(Node_), Node_));
+}
+
+TNode TNodeRef::Copy(TDocument& to) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ auto* fromDoc = fy_node_document(Node_);
+ auto& fromUserdata = *reinterpret_cast<THashSet<TSimpleSharedPtr<TString>, TStringPtrHashT>*>(fy_document_get_userdata(fromDoc));
+ auto& toUserdata = *reinterpret_cast<THashSet<TSimpleSharedPtr<TString>, TStringPtrHashT>*>(fy_document_get_userdata(to.Document_.get()));
+ toUserdata.insert(fromUserdata.begin(), fromUserdata.end());
+ return TNode(fy_node_copy(to.Document_.get(), Node_));
+}
+
+TString TNodeRef::Path() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ char* path = fy_node_get_path(Node_);
+
+ if (path) {
+ TString str(path);
+ free(path);
+ return str;
+ }
+
+ return {};
+}
+
+ENodeType TNodeRef::Type() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return static_cast<ENodeType>(fy_node_get_type(Node_));
+}
+
+bool TNodeRef::IsAlias() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return fy_node_is_alias(Node_);
+}
+
+TNodeRef TNodeRef::ResolveAlias() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ Y_VERIFY_DEBUG(IsAlias());
+ return TNodeRef(fy_node_resolve_alias(Node_));
+}
+
+TString TNodeRef::Scalar() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ Y_ENSURE_EX(fy_node_is_scalar(Node_), TFyamlEx() << "Node is not Scalar: " << Path());
+ size_t size;
+ const char* text = fy_node_get_scalar(Node_, &size);
+ return TString(text, size);
+}
+
+TMapping TNodeRef::Map() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ Y_ENSURE_EX(fy_node_is_mapping(Node_), TFyamlEx() << "Node is not Mapping: " << Path());
+ return TMapping(*this);
+}
+
+TSequence TNodeRef::Sequence() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ Y_ENSURE_EX(fy_node_is_sequence(Node_), TFyamlEx() << "Node is not Sequence: " << Path());
+ return TSequence(*this);
+}
+
+void TNodeRef::Insert(const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ NDetail::RethrowOnError(fy_node_insert(Node_, node.Node_), Node_);
+}
+
+std::optional<TString> TNodeRef::Tag() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ size_t len = 0;
+ const char* tag = fy_node_get_tag(Node_, &len);
+
+ if (tag) {
+ return TString(tag, len);
+ }
+
+ return std::nullopt;
+}
+
+void TNodeRef::SetTag(const TString& tag) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ auto* str = new TString(std::move(tag));
+ auto* data = new NDetail::TUserDataHolder(UserData(), str);
+ SetUserData(data);
+ NDetail::RethrowOnError(fy_node_set_tag(Node_, str->c_str(), str->length()), Node_);
+}
+
+bool TNodeRef::RemoveTag() {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ bool ret = fy_node_remove_tag(Node_);
+ ClearUserData();
+ return ret;
+}
+
+bool TNodeRef::HasAnchor() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return fy_node_get_anchor(Node_) != nullptr;
+}
+
+void TNodeRef::SetAnchor(const TString& anchor) {
+ auto* str = new TString(anchor);
+ auto* data = new NDetail::TUserDataHolder(UserData(), str);
+ SetUserData(data);
+ NDetail::RethrowOnError(fy_node_set_anchor(Node_, str->c_str(), str->length()), Node_);
+}
+
+bool TNodeRef::DeepEqual(const TNodeRef& other) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(other.Node_);
+ return fy_node_compare(Node_, other.Node_);
+}
+
+std::unique_ptr<char, void(*)(char*)> TNodeRef::EmitToCharArray() const {
+ std::unique_ptr<char, void(*)(char*)> res(
+ fy_emit_node_to_string(
+ Node_,
+ (fy_emitter_cfg_flags)(FYECF_DEFAULT)), &NDetail::FreeChar);
+ return res;
+}
+
+void TNodeRef::SetUserData(NDetail::IBasicUserData* data) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ fy_node_set_meta(Node_, data);
+}
+
+NDetail::IBasicUserData* TNodeRef::UserData() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return reinterpret_cast<NDetail::IBasicUserData* >(fy_node_get_meta(Node_));
+}
+
+void TNodeRef::ClearUserData() {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ fy_node_clear_meta(Node_);
+}
+
+TNode& TNode::operator=(fy_node* node) {
+ Node_.reset(node, fy_node_free);
+ return *this;
+}
+
+TNode::TNode(fy_node* node)
+ : Node_(node, fy_node_free)
+{}
+
+TNodeRef TNodePairRef::Key() const {
+ ENSURE_NODE_NOT_EMPTY(Pair_);
+ return TNodeRef(fy_node_pair_key(Pair_));
+}
+
+void TNodePairRef::SetKey(const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Pair_);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_pair_set_key(Pair_, node.Node_), Pair_);
+}
+
+TNodeRef TNodePairRef::Value() const {
+ ENSURE_NODE_NOT_EMPTY(Pair_);
+ return TNodeRef(fy_node_pair_value(Pair_));
+}
+
+void TNodePairRef::SetValue(const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Pair_);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_pair_set_value(Pair_, node.Node_), Pair_);
+}
+
+TMappingIterator::TMappingIterator(const TNodeRef& node, bool end)
+ : Node_(node)
+{
+ if (!end) {
+ NodePair_ = TNodePairRef(fy_node_mapping_iterate(Node_.Node_, reinterpret_cast<void**>(&NodePair_.Pair_)));
+ }
+}
+
+TMappingIterator& TMappingIterator::operator++() {
+ NodePair_ = TNodePairRef(fy_node_mapping_iterate(Node_.Node_, reinterpret_cast<void**>(&NodePair_.Pair_)));
+ return *this;
+}
+
+TReverseMappingIterator::TReverseMappingIterator(const TNodeRef& node, bool end)
+ : Node_(node)
+{
+ if (!end) {
+ NodePair_ = TNodePairRef(fy_node_mapping_reverse_iterate(Node_.Node_, reinterpret_cast<void**>(&NodePair_.Pair_)));
+ }
+}
+
+TReverseMappingIterator& TReverseMappingIterator::operator++() {
+ NodePair_ = TNodePairRef(fy_node_mapping_reverse_iterate(Node_.Node_, reinterpret_cast<void**>(&NodePair_.Pair_)));
+ return *this;
+}
+
+size_t TMapping::size() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return fy_node_mapping_item_count(Node_);
+}
+
+size_t TMapping::empty() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return fy_node_mapping_is_empty(Node_);
+}
+
+TNodePairRef TMapping::at(int index) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ auto res = fy_node_mapping_get_by_index(Node_, index);
+ Y_ENSURE_EX(res, TFyamlEx() << "No such child: " << Path() << "/" << index);
+ return TNodePairRef(res);
+}
+
+TNodePairRef TMapping::operator[](int index) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return TNodePairRef(fy_node_mapping_get_by_index(Node_, index));
+}
+
+TNodeRef TMapping::at(const TString& index) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ auto res = fy_node_mapping_lookup_by_string(Node_, index.data(), index.size());
+ Y_ENSURE_EX(res, TFyamlEx() << "No such child: " << Path() << "/" << index);
+ return TNodeRef(res);
+}
+
+TNodePairRef TMapping::pair_at(const TString& index) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ auto res = fy_node_mapping_lookup_pair_by_string(Node_, index.data(), index.size());
+ Y_ENSURE_EX(res, TFyamlEx() << "No such child: " << Path() << "/" << index);
+ return TNodePairRef(res);
+}
+
+TNodePairRef TMapping::pair_at_opt(const TString& index) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return TNodePairRef(fy_node_mapping_lookup_pair_by_string(Node_, index.data(), index.size()));
+}
+
+TNodeRef TMapping::operator[](const TString& index) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return TNodeRef(fy_node_mapping_lookup_by_string(Node_, index.data(), index.size()));
+}
+
+TNodeRef TMapping::operator[](const char* str) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ TString index(str);
+ return TNodeRef(fy_node_mapping_lookup_by_string(Node_, index.data(), index.size()));
+}
+
+void TMapping::Append(const TNodeRef& key, const TNodeRef& value) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(key);
+ ENSURE_NODE_NOT_EMPTY(value);
+ NDetail::RethrowOnError(fy_node_mapping_append(Node_, key.Node_, value.Node_), Node_);
+}
+
+void TMapping::Prepend(const TNodeRef& key, const TNodeRef& value) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(key);
+ ENSURE_NODE_NOT_EMPTY(value);
+ NDetail::RethrowOnError(fy_node_mapping_prepend(Node_, key.Node_, value.Node_), Node_);
+}
+
+void TMapping::Remove(const TNodePairRef& toRemove) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(toRemove);
+ NDetail::RethrowOnError(fy_node_mapping_remove(Node_, toRemove.Pair_), Node_);
+}
+
+TMappingIterator TMapping::Remove(const TMappingIterator& toRemove) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ Y_VERIFY_DEBUG(Node_ == toRemove.Node_);
+ TMappingIterator ret = toRemove;
+ ++ret;
+ fy_node_mapping_remove(Node_, toRemove.NodePair_.Pair_);
+ return ret;
+}
+
+void TMapping::Remove(const TNodeRef& key) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ fy_node_free(fy_node_mapping_remove_by_key(Node_, key.Node_));
+}
+
+TSequenceIterator::TSequenceIterator(const TNodeRef& node, bool end)
+ : Node_(node)
+{
+ if (!end) {
+ IterNode_ = TNodeRef(fy_node_sequence_iterate(Node_.Node_, &Iter_));
+ }
+}
+
+TSequenceIterator& TSequenceIterator::operator++() {
+ IterNode_ = TNodeRef(fy_node_sequence_iterate(Node_.Node_, &Iter_));
+ return *this;
+}
+
+void TSequenceIterator::InsertBefore(const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(IterNode_);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_sequence_insert_before(Node_.Node_, IterNode_.Node_, node.Node_), Node_.Node_);
+}
+
+void TSequenceIterator::InsertAfter(const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(IterNode_);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_sequence_insert_after(Node_.Node_, IterNode_.Node_, node.Node_), Node_.Node_);
+}
+
+TReverseSequenceIterator::TReverseSequenceIterator(const TNodeRef& node, bool end)
+ : Node_(node)
+{
+ if (!end) {
+ IterNode_ = TNodeRef(fy_node_sequence_reverse_iterate(Node_.Node_, &Iter_));
+ }
+}
+
+TReverseSequenceIterator& TReverseSequenceIterator::operator++() {
+ IterNode_ = TNodeRef(fy_node_sequence_reverse_iterate(Node_.Node_, &Iter_));
+ return *this;
+}
+
+void TReverseSequenceIterator::InsertBefore(const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(IterNode_);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_sequence_insert_after(Node_.Node_, IterNode_.Node_, node.Node_), Node_.Node_);
+}
+
+void TReverseSequenceIterator::InsertAfter(const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(IterNode_);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_sequence_insert_before(Node_.Node_, IterNode_.Node_, node.Node_), Node_.Node_);
+}
+
+size_t TSequence::size() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return fy_node_sequence_item_count(Node_);
+}
+
+size_t TSequence::empty() const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return fy_node_sequence_is_empty(Node_);
+}
+
+TNodeRef TSequence::at(int index) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ auto res = fy_node_sequence_get_by_index(Node_, index);
+ Y_ENSURE_EX(res, TFyamlEx() << "No such index: " << Path() << "/" << index);
+ return TNodeRef(res);
+}
+
+TNodeRef TSequence::operator[](int index) const {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ return TNodeRef(fy_node_sequence_get_by_index(Node_, index));
+}
+
+void TSequence::Append(const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_sequence_append(Node_, node.Node_), Node_);
+}
+
+void TSequence::Prepend(const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_sequence_prepend(Node_, node.Node_), Node_);
+}
+
+void TSequence::InsertBefore(const TNodeRef& mark, const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(mark);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_sequence_insert_before(Node_, mark.Node_, node.Node_), Node_);
+}
+
+void TSequence::InsertAfter(const TNodeRef& mark, const TNodeRef& node) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(mark);
+ ENSURE_NODE_NOT_EMPTY(node);
+ NDetail::RethrowOnError(fy_node_sequence_insert_after(Node_, mark.Node_, node.Node_), Node_);
+}
+
+TNode TSequence::Remove(const TNodeRef& toRemove) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ ENSURE_NODE_NOT_EMPTY(toRemove.Node_);
+ return TNode(fy_node_sequence_remove(Node_, toRemove.Node_));
+}
+
+TSequenceIterator TSequence::Remove(const TSequenceIterator& toRemove) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ Y_VERIFY_DEBUG(Node_ == toRemove.Node_);
+ ENSURE_NODE_NOT_EMPTY(toRemove.IterNode_);
+ TSequenceIterator ret = toRemove;
+ ++ret;
+ fy_node_sequence_remove(Node_, toRemove.IterNode_.Node_);
+ fy_node_free(toRemove.IterNode_.Node_); // TODO add extract
+ return ret;
+}
+
+TReverseSequenceIterator TSequence::Remove(const TReverseSequenceIterator& toRemove) {
+ ENSURE_NODE_NOT_EMPTY(Node_);
+ Y_VERIFY_DEBUG(Node_ == toRemove.Node_);
+ ENSURE_NODE_NOT_EMPTY(toRemove.IterNode_);
+ TReverseSequenceIterator ret = toRemove;
+ ++ret;
+ fy_node_sequence_remove(Node_, toRemove.IterNode_.Node_);
+ fy_node_free(toRemove.IterNode_.Node_); // TODO add extract
+ return ret;
+}
+
+TDocumentNodeIterator::TDocumentNodeIterator(TNodeRef&& node)
+ : Node_(node)
+{
+ if (node) {
+ Iterator_ = {fy_document_iterator_create(), fy_document_iterator_destroy};
+ fy_document_iterator_node_start(Iterator_.get(), node.Node_);
+ }
+}
+
+TDocumentNodeIterator& TDocumentNodeIterator::operator++() {
+ Node_ = fy_document_iterator_node_next(Iterator_.get());
+ return *this;
+}
+
+TDocument::TDocument(TString str, fy_document* doc, fy_diag* diag)
+ : Document_(doc, fy_document_destroy)
+ , Diag_(diag, fy_diag_destroy)
+{
+ auto* userdata = new THashSet<TSimpleSharedPtr<TString>, TStringPtrHashT>({MakeSimpleShared<TString>(std::move(str))});
+ fy_document_set_userdata(doc, userdata);
+ fy_document_register_on_destroy(doc, &DestroyDocumentStrings);
+ RegisterUserDataCleanup();
+}
+
+TDocument::TDocument(fy_document* doc, fy_diag* diag)
+ : Document_(doc, fy_document_destroy)
+ , Diag_(diag, fy_diag_destroy)
+{
+ RegisterUserDataCleanup();
+}
+
+
+TDocument TDocument::Parse(TString str) {
+ const char* cstr = str.empty() ? zstr : str.cbegin();
+ fy_diag_cfg dcfg;
+ fy_diag_cfg_default(&dcfg);
+ std::unique_ptr<fy_diag, void(*)(fy_diag*)> diag(fy_diag_create(&dcfg), fy_diag_destroy);
+ fy_diag_set_collect_errors(diag.get(), true);
+ fy_parse_cfg cfg{
+ "",
+ // FYPCF_PARSE_COMMENTS,
+ FYPCF_QUIET,
+ nullptr,
+ diag.get()
+ };
+ fy_document* doc = fy_document_build_from_string(&cfg, cstr, FY_NT);
+ if (!doc) {
+ fy_diag_error* err;
+ void *iter = nullptr;
+ while ((err = fy_diag_errors_iterate(diag.get(), &iter)) != nullptr) {
+ ythrow yexception() << err->file << ":" << err->line << ":" << err->column << " " << err->msg;
+ }
+ }
+ return TDocument(std::move(str), doc, diag.release());
+}
+
+TDocument TDocument::Clone() const {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ fy_document* doc = fy_document_clone(Document_.get());
+ fy_document_set_userdata(
+ doc,
+ new THashSet<TSimpleSharedPtr<TString>, TStringPtrHashT>(
+ *reinterpret_cast<THashSet<TSimpleSharedPtr<TString>, TStringPtrHashT>*>(fy_document_get_userdata(Document_.get()))
+ )
+ );
+ fy_document_register_on_destroy(doc, &DestroyDocumentStrings);
+ return TDocument(doc, fy_document_get_diag(doc));
+}
+
+void TDocument::InsertAt(const char* path, const TNodeRef& node) {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ NDetail::RethrowOnError(fy_document_insert_at(Document_.get(), path, FY_NT, node.Node_), Diag_.get());
+}
+
+TNodeRef TDocument::Buildf(const char* content) {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ return fy_node_build_from_string(Document_.get(), content, strlen(content));
+}
+
+void TDocument::Resolve() {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ if (fy_document_resolve(Document_.get()) != 0) {
+ fy_diag_error* err;
+ void *iter = nullptr;
+ while ((err = fy_diag_errors_iterate(Diag_.get(), &iter)) != nullptr) {
+ ythrow yexception() << err->line << ":" << err->column << " " << err->msg;
+ }
+ }
+}
+
+bool TDocument::HasDirectives() {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ return fy_document_has_directives(Document_.get());
+}
+
+bool TDocument::HasExplicitDocumentStart() {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ return fy_document_has_explicit_document_start(Document_.get());
+}
+
+bool TDocument::HasExplicitDocumentEnd() {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ return fy_document_has_explicit_document_end(Document_.get());
+}
+
+void TDocument::SetParent(const TDocument& doc) {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ ENSURE_DOCUMENT_NOT_EMPTY(doc.Document_);
+ NDetail::RethrowOnError(fy_document_set_parent(doc.Document_.get(), Document_.release()), Diag_.get());
+}
+
+TNodeRef TDocument::Root() {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ return fy_document_root(Document_.get());
+}
+
+void TDocument::SetRoot(const TNodeRef& node) {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ ENSURE_NODE_NOT_EMPTY(node.Node_);
+ NDetail::RethrowOnError(fy_document_set_root(Document_.get(), node.Node_), Diag_.get());
+}
+
+TNodeRef TDocument::CreateAlias(const TString& name) {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ return TNodeRef(fy_node_create_alias_copy(Document_.get(), name.c_str(), name.length()));
+}
+
+std::unique_ptr<char, void(*)(char*)> TDocument::EmitToCharArray() const {
+ std::unique_ptr<char, void(*)(char*)> res(
+ fy_emit_document_to_string(
+ Document_.get(),
+ (fy_emitter_cfg_flags)(FYECF_DEFAULT | FYECF_OUTPUT_COMMENTS)), &NDetail::FreeChar);
+ return res;
+}
+
+bool TDocument::RegisterUserDataCleanup() {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ return fy_document_register_meta(Document_.get(), &DestroyUserData, nullptr) == 0;
+}
+
+void TDocument::UnregisterUserDataCleanup() {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ fy_document_unregister_meta(Document_.get());
+}
+
+TMark TDocument::BeginMark() const {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ auto* fyds = fy_document_get_document_state(Document_.get());
+ auto* mark = fy_document_state_start_mark(fyds);
+ return TMark{
+ mark->input_pos,
+ mark->line,
+ mark->column,
+ };
+}
+
+TMark TDocument::EndMark() const {
+ ENSURE_DOCUMENT_NOT_EMPTY(Document_);
+ auto* fyds = fy_document_get_document_state(Document_.get());
+ auto* mark = fy_document_state_end_mark(fyds);
+ return TMark{
+ mark->input_pos,
+ mark->line,
+ mark->column,
+ };
+}
+
+std::unique_ptr<char, void(*)(char*)> TJsonEmitter::EmitToCharArray() const {
+ std::unique_ptr<char, void(*)(char*)> res(
+ fy_emit_node_to_string(
+ Node_.Node_,
+ (fy_emitter_cfg_flags)(FYECF_DEFAULT | FYECF_SORT_KEYS | FYECF_MODE_JSON_TP)), &NDetail::FreeChar);
+ return res;
+}
+
+TParser::TParser(TString rawStream, fy_parser* parser, fy_diag* diag)
+ : RawDocumentStream_(std::move(rawStream))
+ , Parser_(parser, fy_parser_destroy)
+ , Diag_(diag, fy_diag_destroy)
+{}
+
+TParser TParser::Create(TString str)
+{
+ const char* stream = str.empty() ? zstr : str.cbegin();
+ fy_diag_cfg dcfg;
+ fy_diag_cfg_default(&dcfg);
+ std::unique_ptr<fy_diag, void(*)(fy_diag*)> diag(fy_diag_create(&dcfg), fy_diag_destroy);
+ fy_diag_set_collect_errors(diag.get(), true);
+ fy_parse_cfg cfg{
+ "",
+ // FYPCF_PARSE_COMMENTS,
+ FYPCF_QUIET,
+ nullptr,
+ diag.get()
+ };
+ auto* parser = fy_parser_create(&cfg);
+ if (!parser) {
+ fy_diag_error* err;
+ void *iter = nullptr;
+ while ((err = fy_diag_errors_iterate(diag.get(), &iter)) != nullptr) {
+ ythrow yexception() << err->file << ":" << err->line << ":" << err->column << " " << err->msg;
+ }
+ }
+
+ fy_parser_set_string(parser, stream, -1);
+
+ return TParser(std::move(str), parser, diag.release());
+}
+
+std::optional<TDocument> TParser::NextDocument() {
+ auto* doc = fy_parse_load_document(Parser_.get());
+ if (!doc) {
+ return std::nullopt;
+ }
+
+ return TDocument(RawDocumentStream_, doc, fy_document_get_diag(doc));
+}
+
+namespace NDetail {
+
+void RethrowError(fy_diag* diag) {
+ void *iter = nullptr;
+ fy_diag_error* err;
+ TStringStream ss;
+ while ((err = fy_diag_errors_iterate(diag, &iter)) != nullptr) {
+ ss << err->line << ":" << err->column << " " << err->msg << "\n";
+ }
+ ythrow yexception() << ss.Str();
+}
+
+void RethrowOnError(bool isError, fy_node* node) {
+ if (!isError) {
+ return;
+ }
+
+ std::unique_ptr<fy_diag, void(*)(fy_diag*)> diag(fy_document_get_diag(fy_node_document(node)), fy_diag_unref);
+ RethrowError(diag.get());
+}
+
+void RethrowOnError(bool isError, fy_node_pair* pair) {
+ if (!isError) {
+ return;
+ }
+
+ std::unique_ptr<fy_diag, void(*)(fy_diag*)> diag(fy_document_get_diag(fy_node_document(fy_node_pair_key(pair))), fy_diag_unref);
+ RethrowError(diag.get());
+}
+
+void RethrowOnError(bool isError, fy_diag* diag) {
+ if (!isError) {
+ return;
+ }
+
+ RethrowError(diag);
+}
+
+
+void FreeChar(char* mem) {
+ free(mem);
+}
+
+} // namespace NDetail
+
+} // namespace NFyaml
+
+template <>
+void Out<NFyaml::TDocument>(IOutputStream& out, const NFyaml::TDocument& value) {
+ out << value.EmitToCharArray().get();
+}
+
+template <>
+void Out<NFyaml::TNodeRef>(IOutputStream& out, const NFyaml::TNodeRef& value) {
+ out << value.EmitToCharArray().get();
+}
+
+template <>
+void Out<NFyaml::TJsonEmitter>(IOutputStream& out, const NFyaml::TJsonEmitter& value) {
+ out << value.EmitToCharArray().get();
+}