#include "nodeevents.h" #include "yaml-cpp/node/node.h" #include "yaml-cpp/node/impl.h" #include "yaml-cpp/eventhandler.h" #include "yaml-cpp/mark.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 { AnchorByIdentity::const_iterator 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) { 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(detail::const_node_iterator it=node.begin();it!=node.end();++it) Setup(**it); } else if(node.type() == NodeType::Map) { for(detail::const_node_iterator it=node.begin();it!=node.end();++it) { Setup(*it->first); Setup(*it->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); for(detail::const_node_iterator it=node.begin();it!=node.end();++it) Emit(**it, handler, am); handler.OnSequenceEnd(); break; case NodeType::Map: handler.OnMapStart(Mark(), node.tag(), anchor); for(detail::const_node_iterator it=node.begin();it!=node.end();++it) { Emit(*it->first, handler, am); Emit(*it->second, handler, am); } handler.OnMapEnd(); break; } } bool NodeEvents::IsAliased(const detail::node& node) const { RefCount::const_iterator it = m_refCount.find(node.ref()); return it != m_refCount.end() && it->second > 1; } }