| #include <cassert> | |
| #include "nodebuilder.h" | |
| #include "yaml-cpp/node/detail/node.h" | |
| #include "yaml-cpp/node/impl.h" | |
| #include "yaml-cpp/node/node.h" | |
| #include "yaml-cpp/node/type.h" | |
| namespace YAML { | |
| struct Mark; | |
| NodeBuilder::NodeBuilder() | |
| : m_pMemory(new detail::memory_holder), | |
| m_pRoot(nullptr), | |
| m_stack{}, | |
| m_anchors{}, | |
| m_keys{}, | |
| m_mapDepth(0) { | |
| m_anchors.push_back(nullptr); // since the anchors start at 1 | |
| } | |
| NodeBuilder::~NodeBuilder() = default; | |
| Node NodeBuilder::Root() { | |
| if (!m_pRoot) | |
| return Node(); | |
| return Node(*m_pRoot, m_pMemory); | |
| } | |
| void NodeBuilder::OnDocumentStart(const Mark&) {} | |
| void NodeBuilder::OnDocumentEnd() {} | |
| void NodeBuilder::OnNull(const Mark& mark, anchor_t anchor) { | |
| detail::node& node = Push(mark, anchor); | |
| node.set_null(); | |
| Pop(); | |
| } | |
| void NodeBuilder::OnAlias(const Mark& /* mark */, anchor_t anchor) { | |
| detail::node& node = *m_anchors[anchor]; | |
| Push(node); | |
| Pop(); | |
| } | |
| void NodeBuilder::OnScalar(const Mark& mark, const std::string& tag, | |
| anchor_t anchor, const std::string& value) { | |
| detail::node& node = Push(mark, anchor); | |
| node.set_scalar(value); | |
| node.set_tag(tag); | |
| Pop(); | |
| } | |
| void NodeBuilder::OnSequenceStart(const Mark& mark, const std::string& tag, | |
| anchor_t anchor, EmitterStyle::value style) { | |
| detail::node& node = Push(mark, anchor); | |
| node.set_tag(tag); | |
| node.set_type(NodeType::Sequence); | |
| node.set_style(style); | |
| } | |
| void NodeBuilder::OnSequenceEnd() { Pop(); } | |
| void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag, | |
| anchor_t anchor, EmitterStyle::value style) { | |
| detail::node& node = Push(mark, anchor); | |
| node.set_type(NodeType::Map); | |
| node.set_tag(tag); | |
| node.set_style(style); | |
| m_mapDepth++; | |
| } | |
| void NodeBuilder::OnMapEnd() { | |
| assert(m_mapDepth > 0); | |
| m_mapDepth--; | |
| Pop(); | |
| } | |
| detail::node& NodeBuilder::Push(const Mark& mark, anchor_t anchor) { | |
| detail::node& node = m_pMemory->create_node(); | |
| node.set_mark(mark); | |
| RegisterAnchor(anchor, node); | |
| Push(node); | |
| return node; | |
| } | |
| void NodeBuilder::Push(detail::node& node) { | |
| const bool needsKey = | |
| (!m_stack.empty() && m_stack.back()->type() == NodeType::Map && | |
| m_keys.size() < m_mapDepth); | |
| m_stack.push_back(&node); | |
| if (needsKey) | |
| m_keys.emplace_back(&node, false); | |
| } | |
| void NodeBuilder::Pop() { | |
| assert(!m_stack.empty()); | |
| if (m_stack.size() == 1) { | |
| m_pRoot = m_stack[0]; | |
| m_stack.pop_back(); | |
| return; | |
| } | |
| detail::node& node = *m_stack.back(); | |
| m_stack.pop_back(); | |
| detail::node& collection = *m_stack.back(); | |
| if (collection.type() == NodeType::Sequence) { | |
| collection.push_back(node, m_pMemory); | |
| } else if (collection.type() == NodeType::Map) { | |
| assert(!m_keys.empty()); | |
| PushedKey& key = m_keys.back(); | |
| if (key.second) { | |
| collection.insert(*key.first, node, m_pMemory); | |
| m_keys.pop_back(); | |
| } else { | |
| key.second = true; | |
| } | |
| } else { | |
| assert(false); | |
| m_stack.clear(); | |
| } | |
| } | |
| void NodeBuilder::RegisterAnchor(anchor_t anchor, detail::node& node) { | |
| if (anchor) { | |
| assert(anchor == m_anchors.size()); | |
| m_anchors.push_back(&node); | |
| } | |
| } | |
| } // namespace YAML |