diff options
author | jansenin <jansenin@yandex-team.com> | 2023-08-02 16:09:05 +0300 |
---|---|---|
committer | jansenin <jansenin@yandex-team.com> | 2023-08-02 16:09:05 +0300 |
commit | c0ca04d62a4ae68bf09193c3a9941d28bf343028 (patch) | |
tree | 39e0e887276bda21e6de99275b9c6e74c8b444d4 | |
parent | c1e8ecaf762b945d005bd42ed005e44c1604346d (diff) | |
download | ydb-c0ca04d62a4ae68bf09193c3a9941d28bf343028.tar.gz |
Add TNodeOps class, that contains common functionality of TNodeRef and TNode
-rw-r--r-- | library/cpp/yaml/fyamlcpp/fyamlcpp.cpp | 554 | ||||
-rw-r--r-- | library/cpp/yaml/fyamlcpp/fyamlcpp.h | 400 | ||||
-rw-r--r-- | library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp | 4 |
3 files changed, 601 insertions, 357 deletions
diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp index 8f9321a252..37ead18350 100644 --- a/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp +++ b/library/cpp/yaml/fyamlcpp/fyamlcpp.cpp @@ -6,9 +6,6 @@ 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 { @@ -262,276 +259,12 @@ 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_), ({ - TStringStream ss; - ss << "Node is not Scalar: " << Path(); - TFyamlEx(ss.Str()); - })); - size_t size; - const char* text = fy_node_get_scalar(Node_, &size); - return TString(text, size); -} - -TMark TNodeRef::BeginMark() const { - ENSURE_NODE_NOT_EMPTY(Node_); - std::unique_ptr<fy_document_iterator, void(*)(fy_document_iterator*)> it( - fy_document_iterator_create(), - &fy_document_iterator_destroy); - fy_document_iterator_node_start(it.get(), Node_); - auto deleter = [&](fy_event* fye){ fy_document_iterator_event_free(it.get(), fye); }; - std::unique_ptr<fy_event, decltype(deleter)> ev( - fy_document_iterator_body_next(it.get()), - deleter); - auto* mark = fy_event_start_mark(ev.get()); - - if (!mark) { - ythrow TFyamlEx("can't get begin mark for a node"); - } - - return TMark{ - mark->input_pos, - mark->line, - mark->column, - }; -} - -bool IsComplexType(ENodeType type) { - return type == ENodeType::Mapping || type == ENodeType::Sequence; -} - -fy_event_type GetOpenEventType(ENodeType type) { - switch(type) { - case ENodeType::Mapping: - return FYET_MAPPING_START; - case ENodeType::Sequence: - return FYET_SEQUENCE_START; - default: - Y_FAIL("Not a brackets type"); - } -} - -fy_event_type GetCloseEventType(ENodeType type) { - switch(type) { - case ENodeType::Mapping: - return FYET_MAPPING_END; - case ENodeType::Sequence: - return FYET_SEQUENCE_END; - default: - Y_FAIL("Not a brackets type"); - } -} - -TMark TNodeRef::EndMark() const { - ENSURE_NODE_NOT_EMPTY(Node_); - std::unique_ptr<fy_document_iterator, void(*)(fy_document_iterator*)> it( - fy_document_iterator_create(), - &fy_document_iterator_destroy); - fy_document_iterator_node_start(it.get(), Node_); - - auto deleter = [&](fy_event* fye){ fy_document_iterator_event_free(it.get(), fye); }; - std::unique_ptr<fy_event, decltype(deleter)> prevEv( - nullptr, - deleter); - std::unique_ptr<fy_event, decltype(deleter)> ev( - fy_document_iterator_body_next(it.get()), - deleter); - - if (IsComplexType(Type())) { - int openBrackets = 0; - if (ev->type == GetOpenEventType(Type())) { - ++openBrackets; - } - if (ev->type == GetCloseEventType(Type())) { - --openBrackets; - } - while (ev->type != GetCloseEventType(Type()) || openBrackets != 0) { - std::unique_ptr<fy_event, decltype(deleter)> cur( - fy_document_iterator_body_next(it.get()), - deleter); - if (cur == nullptr) { - break; - } - if (cur->type == GetOpenEventType(Type())) { - ++openBrackets; - } - if (cur->type == GetCloseEventType(Type())) { - --openBrackets; - } - if (fy_event_get_node_style(cur.get()) != FYNS_BLOCK) { - prevEv.reset(ev.release()); - ev.reset(cur.release()); - } - } - } - - auto* mark = fy_event_end_mark(ev.get()); - - if (!mark && prevEv) { - mark = fy_event_end_mark(prevEv.get()); - } - - if (!mark) { - ythrow TFyamlEx("can't get end mark for a node"); - } - - return TMark{ - mark->input_pos, - mark->line, - mark->column, - }; -} - -TMapping TNodeRef::Map() const { - ENSURE_NODE_NOT_EMPTY(Node_); - Y_ENSURE_EX(fy_node_is_mapping(Node_), ({ - TStringStream ss; - ss << "Node is not Mapping: " << Path(); - TFyamlEx(ss.Str()); - })); - return TMapping(*this); -} - -TSequence TNodeRef::Sequence() const { - ENSURE_NODE_NOT_EMPTY(Node_); - Y_ENSURE_EX(fy_node_is_sequence(Node_), ({ - TStringStream ss; - ss << "Node is not Sequence: " << Path(); - TFyamlEx(ss.Str()); - })); - 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::SetStyle(ENodeStyle style) { - ENSURE_NODE_NOT_EMPTY(Node_); - fy_node_set_style(Node_, (enum fy_node_style)style); -} - -ENodeStyle TNodeRef::Style() const { - ENSURE_NODE_NOT_EMPTY(Node_); - return (ENodeStyle)fy_node_get_style(Node_); -} - -void TNodeRef::SetUserData(NDetail::IBasicUserData* data) { - ENSURE_NODE_NOT_EMPTY(Node_); - fy_node_set_meta(Node_, data); -} +TNodeRef::TNodeRef(fy_node* node) + : Node_(node) +{} -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_); +fy_node* TNodeRef::NodeRawPointer() const { + return Node_; } TNode& TNode::operator=(fy_node* node) { @@ -903,7 +636,7 @@ void TDocument::InsertAt(const char* path, const TNodeRef& node) { TNodeRef TDocument::Buildf(const char* content) { ENSURE_DOCUMENT_NOT_EMPTY(Document_); - return fy_node_build_from_string(Document_.get(), content, strlen(content)); + return TNodeRef(fy_node_build_from_string(Document_.get(), content, strlen(content))); } void TDocument::Resolve() { @@ -936,7 +669,7 @@ void TDocument::SetParent(const TDocument& doc) { TNodeRef TDocument::Root() { ENSURE_DOCUMENT_NOT_EMPTY(Document_); - return fy_document_root(Document_.get()); + return TNodeRef(fy_document_root(Document_.get())); } void TDocument::SetRoot(const TNodeRef& node) { @@ -1039,6 +772,266 @@ std::optional<TDocument> TParser::NextDocument() { namespace NDetail { +fy_node* TNodeOpsBase::CreateReference(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + return fy_node_create_reference(node); +} + +fy_node* TNodeOpsBase::Copy(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + return fy_node_copy(fy_node_document(node), node); +} + +fy_node* TNodeOpsBase::Copy(fy_node* node, fy_document* 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)); + toUserdata.insert(fromUserdata.begin(), fromUserdata.end()); + return fy_node_copy(to, node); +} + +TString TNodeOpsBase::Path(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + char* path = fy_node_get_path(node); + + if (path) { + TString str(path); + free(path); + return str; + } + + return {}; +} + +ENodeType TNodeOpsBase::Type(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + return static_cast<ENodeType>(fy_node_get_type(node)); +} + +bool TNodeOpsBase::IsAlias(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + return fy_node_is_alias(node); +} + +fy_node* TNodeOpsBase::ResolveAlias(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + Y_VERIFY_DEBUG(IsAlias(node)); + return fy_node_resolve_alias(node); +} + +TString TNodeOpsBase::Scalar(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + Y_ENSURE_EX(fy_node_is_scalar(node), TFyamlEx() << "Node is not Scalar: " << Path(node)); + size_t size; + const char* text = fy_node_get_scalar(node, &size); + return TString(text, size); +} + +TMark TNodeOpsBase::BeginMark(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + std::unique_ptr<fy_document_iterator, void(*)(fy_document_iterator*)> it( + fy_document_iterator_create(), + &fy_document_iterator_destroy); + fy_document_iterator_node_start(it.get(), node); + auto deleter = [&](fy_event* fye){ fy_document_iterator_event_free(it.get(), fye); }; + std::unique_ptr<fy_event, decltype(deleter)> ev( + fy_document_iterator_body_next(it.get()), + deleter); + auto* mark = fy_event_start_mark(ev.get()); + + if (!mark) { + ythrow yexception() << "can't get begin mark for a node"; + } + + return TMark{ + mark->input_pos, + mark->line, + mark->column, + }; +} + +namespace { + +fy_event_type GetOpenEventType(ENodeType type) { + switch(type) { + case ENodeType::Mapping: + return FYET_MAPPING_START; + case ENodeType::Sequence: + return FYET_SEQUENCE_START; + default: + Y_FAIL("Not a brackets type"); + } +} + +fy_event_type GetCloseEventType(ENodeType type) { + switch(type) { + case ENodeType::Mapping: + return FYET_MAPPING_END; + case ENodeType::Sequence: + return FYET_SEQUENCE_END; + default: + Y_FAIL("Not a brackets type"); + } +} + +} // anonymous namespace + +TMark TNodeOpsBase::EndMark(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + std::unique_ptr<fy_document_iterator, void(*)(fy_document_iterator*)> it( + fy_document_iterator_create(), + &fy_document_iterator_destroy); + fy_document_iterator_node_start(it.get(), node); + + auto deleter = [&](fy_event* fye){ fy_document_iterator_event_free(it.get(), fye); }; + std::unique_ptr<fy_event, decltype(deleter)> prevEv( + nullptr, + deleter); + std::unique_ptr<fy_event, decltype(deleter)> ev( + fy_document_iterator_body_next(it.get()), + deleter); + + if (IsComplexType(Type(node))) { + int openBrackets = 0; + if (ev->type == GetOpenEventType(Type(node))) { + ++openBrackets; + } + if (ev->type == GetCloseEventType(Type(node))) { + --openBrackets; + } + while (ev->type != GetCloseEventType(Type(node)) || openBrackets != 0) { + std::unique_ptr<fy_event, decltype(deleter)> cur( + fy_document_iterator_body_next(it.get()), + deleter); + if (cur == nullptr) { + break; + } + if (cur->type == GetOpenEventType(Type(node))) { + ++openBrackets; + } + if (cur->type == GetCloseEventType(Type(node))) { + --openBrackets; + } + if (fy_event_get_node_style(cur.get()) != FYNS_BLOCK) { + prevEv.reset(ev.release()); + ev.reset(cur.release()); + } + } + } + + auto* mark = fy_event_end_mark(ev.get()); + + if (!mark && prevEv) { + mark = fy_event_end_mark(prevEv.get()); + } + + if (!mark) { + ythrow yexception() << "can't get end mark for a node"; + } + + return TMark{ + mark->input_pos, + mark->line, + mark->column, + }; +} + +fy_node* TNodeOpsBase::Map(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + Y_ENSURE_EX(fy_node_is_mapping(node), TFyamlEx() << "Node is not Mapping: " << Path(node)); + return node; +} + +fy_node* TNodeOpsBase::Sequence(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + Y_ENSURE_EX(fy_node_is_sequence(node), TFyamlEx() << "Node is not Sequence: " << Path(node)); + return node; +} + +void TNodeOpsBase::Insert(fy_node* thisNode, fy_node* node) { + ENSURE_NODE_NOT_EMPTY(node); + RethrowOnError(fy_node_insert(thisNode, node), thisNode); +} + +std::optional<TString> TNodeOpsBase::Tag(fy_node* node) 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 TNodeOpsBase::SetTag(fy_node* node, const TString& tag) { + ENSURE_NODE_NOT_EMPTY(node); + auto* str = new TString(std::move(tag)); + auto* data = new TUserDataHolder(UserData(node), str); + SetUserData(node, data); + RethrowOnError(fy_node_set_tag(node, str->c_str(), str->length()), node); +} + +bool TNodeOpsBase::RemoveTag(fy_node* node) { + ENSURE_NODE_NOT_EMPTY(node); + bool ret = fy_node_remove_tag(node); + ClearUserData(node); + return ret; +} + +bool TNodeOpsBase::HasAnchor(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + return fy_node_get_anchor(node) != nullptr; +} + +void TNodeOpsBase::SetAnchor(fy_node* node, const TString& anchor) { + auto* str = new TString(anchor); + auto* data = new TUserDataHolder(UserData(node), str); + SetUserData(node, data); + RethrowOnError(fy_node_set_anchor(node, str->c_str(), str->length()), node); +} + +bool TNodeOpsBase::DeepEqual(fy_node* thisNode, fy_node* other) { + ENSURE_NODE_NOT_EMPTY(thisNode); + ENSURE_NODE_NOT_EMPTY(other); + return fy_node_compare(thisNode, other); +} + +std::unique_ptr<char, void(*)(char*)> TNodeOpsBase::EmitToCharArray(fy_node* node) const { + std::unique_ptr<char, void(*)(char*)> res( + fy_emit_node_to_string( + node, + (fy_emitter_cfg_flags)(FYECF_DEFAULT)), &FreeChar); + return res; +} + +void TNodeOpsBase::SetStyle(fy_node* node, ENodeStyle style) { + ENSURE_NODE_NOT_EMPTY(node); + fy_node_set_style(node, (enum fy_node_style)style); +} + +ENodeStyle TNodeOpsBase::Style(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + return (ENodeStyle)fy_node_get_style(node); +} + +void TNodeOpsBase::SetUserData(fy_node* node, IBasicUserData* data) { + ENSURE_NODE_NOT_EMPTY(node); + fy_node_set_meta(node, data); +} + +IBasicUserData* TNodeOpsBase::UserData(fy_node* node) const { + ENSURE_NODE_NOT_EMPTY(node); + return reinterpret_cast<IBasicUserData* >(fy_node_get_meta(node)); +} + +void TNodeOpsBase::ClearUserData(fy_node* node) { + ENSURE_NODE_NOT_EMPTY(node); + fy_node_clear_meta(node); +} + void ThrowAllExceptionsIfAny(fy_diag* diag) { void* iter = nullptr; fy_diag_error* err = fy_diag_errors_iterate(diag, &iter); @@ -1093,11 +1086,14 @@ void RethrowOnError(bool isError, fy_diag* diag) { RethrowError(diag); } - void FreeChar(char* mem) { free(mem); } +bool IsComplexType(ENodeType type) { + return type == ENodeType::Mapping || type == ENodeType::Sequence; +} + } // namespace NDetail } // namespace NFyaml @@ -1116,3 +1112,11 @@ template <> void Out<NFyaml::TJsonEmitter>(IOutputStream& out, const NFyaml::TJsonEmitter& value) { out << value.EmitToCharArray().get(); } + +bool operator==(const fy_node* node1, const NFyaml::NDetail::TNodeOps<NFyaml::TNodeRef>& node2) { + return node2.Node() == node1; +} + +bool operator==(const fy_node* node1, const NFyaml::NDetail::TNodeOps<NFyaml::TNode>& node2) { + return node2.Node() == node1; +} diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp.h b/library/cpp/yaml/fyamlcpp/fyamlcpp.h index a6bdf56927..cb622bd146 100644 --- a/library/cpp/yaml/fyamlcpp/fyamlcpp.h +++ b/library/cpp/yaml/fyamlcpp/fyamlcpp.h @@ -10,6 +10,9 @@ #include <memory> #include <optional> +#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") + struct fy_parser; struct fy_node; struct fy_document; @@ -19,6 +22,18 @@ struct fy_node_pair; extern "C" struct fy_node *fy_node_buildf(struct fy_document *fyd, const char *fmt, ...); namespace NFyaml { + namespace NDetail { + template <class T> + class TNodeOps; + } + class TNodeRef; + class TNode; +} + +bool operator==(const fy_node* node1, const NFyaml::NDetail::TNodeOps<NFyaml::TNodeRef>& node2); +bool operator==(const fy_node* node1, const NFyaml::NDetail::TNodeOps<NFyaml::TNode>& node2); + +namespace NFyaml { struct TStringPtrHashT { size_t operator()(const TSimpleSharedPtr<TString>& str) const { @@ -81,6 +96,20 @@ enum class ENodeStyle { Alias, }; +class TNodeRef; +class TDocumentIterator; +class TDocument; +class TNode; +class TMappingIterator; +class TReverseMappingIterator; +class TMapping; +class TSequenceIterator; +class TReverseSequenceIterator; +class TSequence; +class TJsonEmitter; +class TParser; +struct TMark; + namespace NDetail { class IBasicUserData { @@ -113,60 +142,76 @@ void RethrowOnError(bool isError, fy_diag* diag); void FreeChar(char* mem); -} // namespace NDetail +bool IsComplexType(ENodeType type); -class TNodeRef; -class TDocumentIterator; -class TDocument; -class TNode; -class TMappingIterator; -class TReverseMappingIterator; -class TMapping; -class TSequenceIterator; -class TReverseSequenceIterator; -class TSequence; -class TJsonEmitter; -class TParser; -struct TMark; +class TNodeOpsBase { +protected: + TString Path(fy_node* node) const; -class TDocumentIterator { - friend class TDocument; -public: - TDocumentIterator(fy_document_iterator* iterator = nullptr); + ENodeType Type(fy_node* node) const; -protected: - std::unique_ptr<fy_document_iterator, void(*)(fy_document_iterator*)> Iterator_; -}; + fy_node* Copy(fy_node* node) const; -class TNodeRef { - friend class TDocument; - friend class TDocumentNodeIterator; - friend class TNode; - friend class TMapping; - friend class TMappingIterator; - friend class TReverseMappingIterator; - friend class TNodePairRef; - friend class TSequence; - friend class TSequenceIterator; - friend class TReverseSequenceIterator; - friend class TJsonEmitter; + fy_node* Copy(fy_node* node, fy_document* to) const; - TNodeRef(fy_node* node) - : Node_(node) - {} + bool IsAlias(fy_node* node) const; -public: - TNodeRef() = default; + fy_node* ResolveAlias(fy_node* node) const; - TNodeRef(const TNodeRef& other) { Node_ = other.Node_; } + fy_node* CreateReference(fy_node* node) const; - TNodeRef& operator=(const TNodeRef& other) { Node_ = other.Node_; return *this; } + fy_node* Sequence(fy_node* node) const; - TNodeRef& operator=(fy_node* node) { Node_ = node; return *this; } + fy_node* Map(fy_node* node) const; + + TString Scalar(fy_node* node) const; + + TMark BeginMark(fy_node* node) const; + + TMark EndMark(fy_node* node) const; + + void Insert(fy_node* thisNode, fy_node* node); + + std::optional<TString> Tag(fy_node* node) const; - bool operator==(const TNodeRef& other) const { return Node_ == other.Node_; } + void SetTag(fy_node* node, const TString& tag); - explicit operator bool() const { return Node_ != nullptr; } + bool RemoveTag(fy_node* node); + + bool HasAnchor(fy_node* node) const; + + void SetAnchor(fy_node* node, const TString& anchor); + + bool DeepEqual(fy_node* thisNode, fy_node* other); + + std::unique_ptr<char, void(*)(char*)> EmitToCharArray(fy_node* node) const; + + void SetStyle(fy_node* node, ENodeStyle style); + + ENodeStyle Style(fy_node* node) const; + +protected: + void SetUserData(fy_node* node, NDetail::IBasicUserData* data); + + NDetail::IBasicUserData* UserData(fy_node* node) const; + + void ClearUserData(fy_node* node); +}; + +template <class T> +class TNodeOps : public TNodeOpsBase { +friend class ::NFyaml::TNodeRef; + +public: + template <class OtherT> + bool operator==(const TNodeOps<OtherT>& other) const { return Node() == other.Node(); } + + bool operator==(const fy_node* node) const { return Node() == node; } + + friend bool ::operator==(const fy_node* node1, const TNodeOps<NFyaml::TNodeRef>& node2); + friend bool ::operator==(const fy_node* node1, const TNodeOps<NFyaml::TNode>& node2); + + explicit operator bool() const { return Node() != nullptr; } TString Path() const; @@ -194,7 +239,7 @@ public: void Insert(const TNodeRef& node); - bool Empty() const { return Node_ == nullptr; } + bool Empty() const { return Node() == nullptr; } std::optional<TString> Tag() const; @@ -215,41 +260,93 @@ public: ENodeStyle Style() const; protected: - fy_node* Node_ = nullptr; + const T& AsDerived() const; + + fy_node* Node() const; + + fy_node* Node(); void SetUserData(NDetail::IBasicUserData* data); + NDetail::IBasicUserData* UserData() const; + void ClearUserData(); }; -class TNode { +} // namespace NDetail + +class TDocumentIterator { + friend class TDocument; +public: + explicit TDocumentIterator(fy_document_iterator* iterator = nullptr); + +protected: + std::unique_ptr<fy_document_iterator, void(*)(fy_document_iterator*)> Iterator_; +}; + +class TNodeRef : public NDetail::TNodeOps<TNodeRef> { + friend class TNodeOps<TNodeRef>; + friend class TNodeOpsBase; friend class TDocument; friend class TDocumentNodeIterator; - friend class TNodeRef; + friend class TMapping; + friend class TMappingIterator; + friend class TReverseMappingIterator; + friend class TNodePairRef; friend class TSequence; + friend class TSequenceIterator; + friend class TReverseSequenceIterator; + friend class TJsonEmitter; - TNode& operator=(fy_node* node); public: - TNode(fy_node* node = nullptr); + TNodeRef() = default; + + template <class T> + TNodeRef(const TNodeOps<T>& other) : Node_(other.Node()) {} + + explicit TNodeRef(const TNodeRef& other) : Node_(other.Node_) {} + + TNodeRef(fy_node* node); + + TNodeRef& operator=(const TNodeRef& other) { Node_ = other.Node_; return *this; } + + TNodeRef& operator=(fy_node* node) { Node_ = node; return *this; } + +protected: + fy_node* Node_ = nullptr; - bool operator==(const TNode& other) const { return Node_ == other.Node_; } +private: + fy_node* NodeRawPointer() const; +}; + +class TNode : public NDetail::TNodeOps<TNode> { + friend class TNodeOps<TNode>; + +public: + TNode(fy_node* node = nullptr); - explicit operator bool() { return Node_ != nullptr; } + template <class T> + explicit TNode(const TNodeOps<T>& other) : Node_(other.Node_) {} - TNodeRef Ref() { return TNodeRef(Node_.get()); } + TNodeRef Ref() { return TNodeRef(*this); } private: std::shared_ptr<fy_node> Node_; + + TNode& operator=(fy_node* node); + + fy_node* NodeRawPointer() const { + return Node_.get(); + } }; class TNodePairRef { - friend class TMappingIterator; - friend class TReverseMappingIterator; - friend class TMapping; +friend class TMappingIterator; +friend class TReverseMappingIterator; +friend class TMapping; + public: - TNodePairRef(fy_node_pair* pair = nullptr) - : Pair_(pair) - {} + TNodePairRef(fy_node_pair* pair = nullptr) : Pair_(pair) {} bool operator==(const TNodePairRef& other) const { return Pair_ == other.Pair_; } @@ -272,7 +369,7 @@ private: class TMappingIterator { friend class TMapping; public: - TMappingIterator(const TNodeRef& node, bool end = false); + explicit TMappingIterator(const TNodeRef& node, bool end = false); TMappingIterator(const TMappingIterator& other) { Node_ = other.Node_; @@ -307,7 +404,7 @@ private: class TReverseMappingIterator { friend class TMapping; public: - TReverseMappingIterator(const TNodeRef& node, bool end = false); + explicit TReverseMappingIterator(const TNodeRef& node, bool end = false); TReverseMappingIterator(const TReverseMappingIterator& other) { Node_ = other.Node_; @@ -343,26 +440,27 @@ private: class TMapping : public TNodeRef { public: - explicit TMapping(const TNodeRef& node) + template <class T> + explicit TMapping(const TNodeOps<T>& node) : TNodeRef(node) { Y_VERIFY_DEBUG(Type() == ENodeType::Mapping); } TMappingIterator begin() const { - return TMappingIterator(Node_); + return TMappingIterator(*this); } TMappingIterator end() const { - return TMappingIterator(Node_, true); + return TMappingIterator(*this, true); } TReverseMappingIterator rbegin() const { - return TReverseMappingIterator(Node_); + return TReverseMappingIterator(*this); } TReverseMappingIterator rend() const { - return TReverseMappingIterator(Node_, true); + return TReverseMappingIterator(*this, true); } size_t size() const; @@ -397,7 +495,7 @@ public: class TSequenceIterator { friend class TSequence; public: - TSequenceIterator(const TNodeRef& node, bool end = false); + explicit TSequenceIterator(const TNodeRef& node, bool end = false); TSequenceIterator(const TSequenceIterator& other) { Node_ = other.Node_; @@ -443,7 +541,7 @@ private: class TReverseSequenceIterator { friend class TSequence; public: - TReverseSequenceIterator(const TNodeRef& node, bool end = false); + explicit TReverseSequenceIterator(const TNodeRef& node, bool end = false); TReverseSequenceIterator(const TReverseSequenceIterator& other) { Node_ = other.Node_; @@ -495,19 +593,19 @@ public: } TSequenceIterator begin() const { - return TSequenceIterator(Node_); + return TSequenceIterator(*this); } TSequenceIterator end() const { - return TSequenceIterator(Node_, true); + return TSequenceIterator(*this, true); } TReverseSequenceIterator rbegin() const { - return TReverseSequenceIterator(Node_); + return TReverseSequenceIterator(*this); } TReverseSequenceIterator rend() const { - return TReverseSequenceIterator(Node_, true); + return TReverseSequenceIterator(*this, true); } size_t size() const; @@ -537,7 +635,7 @@ class TDocumentNodeIterator : public TDocumentIterator { public: - TDocumentNodeIterator(TNodeRef&& node); + explicit TDocumentNodeIterator(TNodeRef&& node); TDocumentNodeIterator(const TDocumentNodeIterator& other) : TDocumentIterator(other.Iterator_.get()) @@ -573,14 +671,12 @@ private: }; class TDocument { - friend class TNode; - friend class TNodeRef; - friend class TJsonEmitter; + friend class NDetail::TNodeOps<TNodeRef>; + friend class NDetail::TNodeOps<TNode>; friend class TParser; - friend class TMapping; - TDocument(TString str, fy_document* doc = nullptr, fy_diag* diag = nullptr); - TDocument(fy_document* doc = nullptr, fy_diag* diag = nullptr); + explicit TDocument(TString str, fy_document* doc = nullptr, fy_diag* diag = nullptr); + explicit TDocument(fy_document* doc = nullptr, fy_diag* diag = nullptr); public: TDocument(TDocument&& other) @@ -667,8 +763,8 @@ private: class TJsonEmitter { public: - TJsonEmitter(TDocument& doc) : Node_(doc.Root()) {} - TJsonEmitter(const TNodeRef& node) : Node_(node) {} + explicit TJsonEmitter(TDocument& doc) : Node_(doc.Root()) {} + explicit TJsonEmitter(const TNodeRef& node) : Node_(node) {} std::unique_ptr<char, void(*)(char*)> EmitToCharArray() const; @@ -694,4 +790,148 @@ struct TMark { int Column; }; +namespace NDetail { + +template <class T> +TNode TNodeOps<T>::CreateReference() const { + return TNode(TNodeOpsBase::CreateReference(Node())); +} + +template <class T> +TNode TNodeOps<T>::Copy() const { + return TNode(TNodeOpsBase::Copy(Node())); +} + +template <class T> +TNode TNodeOps<T>::Copy(TDocument& to) const { + return TNode(TNodeOpsBase::Copy(Node(), to.Document_.get())); +} + +template <class T> +TString TNodeOps<T>::Path() const { + return TNodeOpsBase::Path(Node()); +} + +template <class T> +ENodeType TNodeOps<T>::Type() const { + return TNodeOpsBase::Type(Node()); +} + +template <class T> +bool TNodeOps<T>::IsAlias() const { + return TNodeOpsBase::IsAlias(Node()); +} + +template <class T> +TNodeRef TNodeOps<T>::ResolveAlias() const { + return TNodeRef(TNodeOpsBase::ResolveAlias(Node())); +} + +template <class T> +TString TNodeOps<T>::Scalar() const { + return TNodeOpsBase::Scalar(Node()); +} + +template <class T> +TMark TNodeOps<T>::BeginMark() const { + return TNodeOpsBase::BeginMark(Node()); +} + +template <class T> +TMark TNodeOps<T>::EndMark() const { + return TNodeOpsBase::EndMark(Node()); +} + +template <class T> +TMapping TNodeOps<T>::Map() const { + return TMapping(TNodeRef(TNodeOpsBase::Map(Node()))); +} + +template <class T> +TSequence TNodeOps<T>::Sequence() const { + return TSequence(TNodeRef(TNodeOpsBase::Sequence(Node()))); +} + +template <class T> +void TNodeOps<T>::Insert(const TNodeRef& node) { + return TNodeOpsBase::Insert(Node(), node.Node_); +} + +template <class T> +std::optional<TString> TNodeOps<T>::Tag() const { + return TNodeOpsBase::Tag(Node()); +} + +template <class T> +void TNodeOps<T>::SetTag(const TString& tag) { + return TNodeOpsBase::SetTag(Node(), tag); +} + +template <class T> +bool TNodeOps<T>::RemoveTag() { + return TNodeOpsBase::RemoveTag(Node()); +} + +template <class T> +bool TNodeOps<T>::HasAnchor() const { + return TNodeOpsBase::HasAnchor(Node()); +} + +template <class T> +void TNodeOps<T>::SetAnchor(const TString& anchor) { + return TNodeOpsBase::SetAnchor(Node(), anchor); +} + +template <class T> +bool TNodeOps<T>::DeepEqual(const TNodeRef& other) { + return TNodeOpsBase::DeepEqual(Node(), other.Node_); +} + +template <class T> +std::unique_ptr<char, void(*)(char*)> TNodeOps<T>::EmitToCharArray() const { + return TNodeOpsBase::EmitToCharArray(Node()); +} + +template <class T> +void TNodeOps<T>::SetStyle(ENodeStyle style) { + return TNodeOpsBase::SetStyle(Node(), style); +} + +template <class T> +ENodeStyle TNodeOps<T>::Style() const { + return TNodeOpsBase::Style(Node()); +} + +template <class T> +const T& TNodeOps<T>::AsDerived() const { + return static_cast<const T&>(*this); +} + +template <class T> +fy_node* TNodeOps<T>::Node() const { + return AsDerived().NodeRawPointer(); +} + +template <class T> +fy_node* TNodeOps<T>::Node() { + return AsDerived().NodeRawPointer(); +} + +template <class T> +void TNodeOps<T>::SetUserData(IBasicUserData* data) { + return TNodeOpsBase::SetUserData(Node(), data); +} + +template <class T> +IBasicUserData* TNodeOps<T>::UserData() const { + return TNodeOpsBase::UserData(Node()); +} + +template <class T> +void TNodeOps<T>::ClearUserData() { + return TNodeOpsBase::ClearUserData(Node()); +} + +} // namespace NDetail + } // namesapce NFyaml diff --git a/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp b/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp index 67e918a297..041a7028b3 100644 --- a/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp +++ b/library/cpp/yaml/fyamlcpp/fyamlcpp_ut.cpp @@ -162,8 +162,8 @@ x: b auto docNodeRef = doc->Root().Map().at("test"); auto node1 = item1NodeRef.Copy(*doc); auto node2 = item2NodeRef.Copy(*doc); - docNodeRef.Sequence().Append(node1.Ref()); - docNodeRef.Sequence().Append(node2.Ref()); + docNodeRef.Sequence().Append(node1); + docNodeRef.Sequence().Append(node2); item1.reset(); item2.reset(); } |