135 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			135 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								#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
							 |