#include #include #include #include #include "yaml-cpp/exceptions.h" #include "yaml-cpp/node/detail/memory.h" #include "yaml-cpp/node/detail/node.h" // IWYU pragma: keep #include "yaml-cpp/node/detail/node_data.h" #include "yaml-cpp/node/detail/node_iterator.h" #include "yaml-cpp/node/ptr.h" #include "yaml-cpp/node/type.h" namespace YAML { namespace detail { YAML_CPP_API std::atomic node::m_amount{0}; const std::string& node_data::empty_scalar() { static const std::string svalue; return svalue; } node_data::node_data() : m_isDefined(false), m_mark(Mark::null_mark()), m_type(NodeType::Null), m_tag{}, m_style(EmitterStyle::Default), m_scalar{}, m_sequence{}, m_seqSize(0), m_map{}, m_undefinedPairs{} {} void node_data::mark_defined() { if (m_type == NodeType::Undefined) m_type = NodeType::Null; m_isDefined = true; } void node_data::set_mark(const Mark& mark) { m_mark = mark; } void node_data::set_type(NodeType::value type) { if (type == NodeType::Undefined) { m_type = type; m_isDefined = false; return; } m_isDefined = true; if (type == m_type) return; m_type = type; switch (m_type) { case NodeType::Null: break; case NodeType::Scalar: m_scalar.clear(); break; case NodeType::Sequence: reset_sequence(); break; case NodeType::Map: reset_map(); break; case NodeType::Undefined: assert(false); break; } } void node_data::set_tag(const std::string& tag) { m_tag = tag; } void node_data::set_style(EmitterStyle::value style) { m_style = style; } void node_data::set_null() { m_isDefined = true; m_type = NodeType::Null; } void node_data::set_scalar(const std::string& scalar) { m_isDefined = true; m_type = NodeType::Scalar; m_scalar = scalar; } // size/iterator std::size_t node_data::size() const { if (!m_isDefined) return 0; switch (m_type) { case NodeType::Sequence: compute_seq_size(); return m_seqSize; case NodeType::Map: compute_map_size(); return m_map.size() - m_undefinedPairs.size(); default: return 0; } return 0; } void node_data::compute_seq_size() const { while (m_seqSize < m_sequence.size() && m_sequence[m_seqSize]->is_defined()) m_seqSize++; } void node_data::compute_map_size() const { auto it = m_undefinedPairs.begin(); while (it != m_undefinedPairs.end()) { auto jt = std::next(it); if (it->first->is_defined() && it->second->is_defined()) m_undefinedPairs.erase(it); it = jt; } } const_node_iterator node_data::begin() const { if (!m_isDefined) return {}; switch (m_type) { case NodeType::Sequence: return const_node_iterator(m_sequence.begin()); case NodeType::Map: return const_node_iterator(m_map.begin(), m_map.end()); default: return {}; } } node_iterator node_data::begin() { if (!m_isDefined) return {}; switch (m_type) { case NodeType::Sequence: return node_iterator(m_sequence.begin()); case NodeType::Map: return node_iterator(m_map.begin(), m_map.end()); default: return {}; } } const_node_iterator node_data::end() const { if (!m_isDefined) return {}; switch (m_type) { case NodeType::Sequence: return const_node_iterator(m_sequence.end()); case NodeType::Map: return const_node_iterator(m_map.end(), m_map.end()); default: return {}; } } node_iterator node_data::end() { if (!m_isDefined) return {}; switch (m_type) { case NodeType::Sequence: return node_iterator(m_sequence.end()); case NodeType::Map: return node_iterator(m_map.end(), m_map.end()); default: return {}; } } // sequence void node_data::push_back(node& node, const shared_memory_holder& /* pMemory */) { if (m_type == NodeType::Undefined || m_type == NodeType::Null) { m_type = NodeType::Sequence; reset_sequence(); } if (m_type != NodeType::Sequence) throw BadPushback(); m_sequence.push_back(&node); } void node_data::insert(node& key, node& value, const shared_memory_holder& pMemory) { switch (m_type) { case NodeType::Map: break; case NodeType::Undefined: case NodeType::Null: case NodeType::Sequence: convert_to_map(pMemory); break; case NodeType::Scalar: throw BadSubscript(m_mark, key); } insert_map_pair(key, value); } // indexing node* node_data::get(node& key, const shared_memory_holder& /* pMemory */) const { if (m_type != NodeType::Map) { return nullptr; } for (const auto& it : m_map) { if (it.first->is(key)) return it.second; } return nullptr; } node& node_data::get(node& key, const shared_memory_holder& pMemory) { switch (m_type) { case NodeType::Map: break; case NodeType::Undefined: case NodeType::Null: case NodeType::Sequence: convert_to_map(pMemory); break; case NodeType::Scalar: throw BadSubscript(m_mark, key); } for (const auto& it : m_map) { if (it.first->is(key)) return *it.second; } node& value = pMemory->create_node(); insert_map_pair(key, value); return value; } bool node_data::remove(node& key, const shared_memory_holder& /* pMemory */) { if (m_type != NodeType::Map) return false; for (auto it = m_undefinedPairs.begin(); it != m_undefinedPairs.end();) { auto jt = std::next(it); if (it->first->is(key)) m_undefinedPairs.erase(it); it = jt; } auto it = std::find_if(m_map.begin(), m_map.end(), [&](std::pair j) { return (j.first->is(key)); }); if (it != m_map.end()) { m_map.erase(it); return true; } return false; } void node_data::reset_sequence() { m_sequence.clear(); m_seqSize = 0; } void node_data::reset_map() { m_map.clear(); m_undefinedPairs.clear(); } void node_data::insert_map_pair(node& key, node& value) { m_map.emplace_back(&key, &value); if (!key.is_defined() || !value.is_defined()) m_undefinedPairs.emplace_back(&key, &value); } void node_data::convert_to_map(const shared_memory_holder& pMemory) { switch (m_type) { case NodeType::Undefined: case NodeType::Null: reset_map(); m_type = NodeType::Map; break; case NodeType::Sequence: convert_sequence_to_map(pMemory); break; case NodeType::Map: break; case NodeType::Scalar: assert(false); break; } } void node_data::convert_sequence_to_map(const shared_memory_holder& pMemory) { assert(m_type == NodeType::Sequence); reset_map(); for (std::size_t i = 0; i < m_sequence.size(); i++) { std::stringstream stream; stream << i; node& key = pMemory->create_node(); key.set_scalar(stream.str()); insert_map_pair(key, *m_sequence[i]); } reset_sequence(); m_type = NodeType::Map; } } // namespace detail } // namespace YAML