text: #include <assert.h>
  #include <iterator>
  #include <sstream>
  
  #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 {
  
  std::string node_data::empty_scalar;
  
  node_data::node_data()
      : m_isDefined(false),
        m_mark(Mark::null_mark()),
        m_type(NodeType::Null),
        m_style(EmitterStyle::Default),
        m_seqSize(0) {}
  
  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 {
    kv_pairs::iterator it = m_undefinedPairs.begin();
    while (it != m_undefinedPairs.end()) {
      kv_pairs::iterator 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 const_node_iterator();
  
    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 const_node_iterator();
    }
  }
  
  node_iterator node_data::begin() {
    if (!m_isDefined)
      return node_iterator();
  
    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 node_iterator();
    }
  }
  
  const_node_iterator node_data::end() const {
    if (!m_isDefined)
      return const_node_iterator();
  
    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 const_node_iterator();
    }
  }
  
  node_iterator node_data::end() {
    if (!m_isDefined)
      return node_iterator();
  
    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 node_iterator();
    }
  }
  
  // sequence
  void node_data::push_back(node& node, 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, 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();
    }
  
    insert_map_pair(key, value);
  }
  
  // indexing
  node* node_data::get(node& key, shared_memory_holder /* pMemory */) const {
    if (m_type != NodeType::Map) {
      return NULL;
    }
  
    for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
      if (it->first->is(key))
        return it->second;
    }
  
    return NULL;
  }
  
  node& node_data::get(node& key, 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();
    }
  
    for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
      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, shared_memory_holder /* pMemory */) {
    if (m_type != NodeType::Map)
      return false;
  
    kv_pairs::iterator it = m_undefinedPairs.begin();
    while (it != m_undefinedPairs.end()) {
      kv_pairs::iterator jt = std::next(it);
      if (it->first->is(key))
        m_undefinedPairs.erase(it);
      it = jt;
    }
  
    for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) {
      if (it->first->is(key)) {
        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(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(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;
  }
  }
  }
  