| #include "nodeevents.h" | |
| #include "yaml-cpp/eventhandler.h" | |
| #include "yaml-cpp/mark.h" | |
| #include "yaml-cpp/node/detail/node.h" | |
| #include "yaml-cpp/node/detail/node_iterator.h" | |
| #include "yaml-cpp/node/node.h" | |
| #include "yaml-cpp/node/type.h" | |
| namespace YAML { | |
| void NodeEvents::AliasManager::RegisterReference(const detail::node& node) { | |
| m_anchorByIdentity.insert(std::make_pair(node.ref(), _CreateNewAnchor())); | |
| } | |
| anchor_t NodeEvents::AliasManager::LookupAnchor( | |
| const detail::node& node) const { | |
| auto it = m_anchorByIdentity.find(node.ref()); | |
| if (it == m_anchorByIdentity.end()) | |
| return 0; | |
| return it->second; | |
| } | |
| NodeEvents::NodeEvents(const Node& node) | |
| : m_pMemory(node.m_pMemory), m_root(node.m_pNode), m_refCount{} { | |
| if (m_root) | |
| Setup(*m_root); | |
| } | |
| void NodeEvents::Setup(const detail::node& node) { | |
| int& refCount = m_refCount[node.ref()]; | |
| refCount++; | |
| if (refCount > 1) | |
| return; | |
| if (node.type() == NodeType::Sequence) { | |
| for (auto element : node) | |
| Setup(*element); | |
| } else if (node.type() == NodeType::Map) { | |
| for (auto element : node) { | |
| Setup(*element.first); | |
| Setup(*element.second); | |
| } | |
| } | |
| } | |
| void NodeEvents::Emit(EventHandler& handler) { | |
| AliasManager am; | |
| handler.OnDocumentStart(Mark()); | |
| if (m_root) | |
| Emit(*m_root, handler, am); | |
| handler.OnDocumentEnd(); | |
| } | |
| void NodeEvents::Emit(const detail::node& node, EventHandler& handler, | |
| AliasManager& am) const { | |
| anchor_t anchor = NullAnchor; | |
| if (IsAliased(node)) { | |
| anchor = am.LookupAnchor(node); | |
| if (anchor) { | |
| handler.OnAlias(Mark(), anchor); | |
| return; | |
| } | |
| am.RegisterReference(node); | |
| anchor = am.LookupAnchor(node); | |
| } | |
| switch (node.type()) { | |
| case NodeType::Undefined: | |
| break; | |
| case NodeType::Null: | |
| handler.OnNull(Mark(), anchor); | |
| break; | |
| case NodeType::Scalar: | |
| handler.OnScalar(Mark(), node.tag(), anchor, node.scalar()); | |
| break; | |
| case NodeType::Sequence: | |
| handler.OnSequenceStart(Mark(), node.tag(), anchor, node.style()); | |
| for (auto element : node) | |
| Emit(*element, handler, am); | |
| handler.OnSequenceEnd(); | |
| break; | |
| case NodeType::Map: | |
| handler.OnMapStart(Mark(), node.tag(), anchor, node.style()); | |
| for (auto element : node) { | |
| Emit(*element.first, handler, am); | |
| Emit(*element.second, handler, am); | |
| } | |
| handler.OnMapEnd(); | |
| break; | |
| } | |
| } | |
| bool NodeEvents::IsAliased(const detail::node& node) const { | |
| auto it = m_refCount.find(node.ref()); | |
| return it != m_refCount.end() && it->second > 1; | |
| } | |
| } // namespace YAML |