mirror of
https://github.com/RPCS3/yaml-cpp.git
synced 2026-01-31 01:25:20 +01:00
* Export YAML::detail::node::m_amount The internal header node/detail/node.h is included by public headers; YAML::detail::node is implemented in the header itself, and thus it gets inlined... except for its static m_amount class member, which is instantiated in the library only. Right now all the symbols of yaml-cpp are exported (nothing is hidden), so the linker will find node::m_amount in the yaml-cpp library. As solution/workaround, explicitly export YAML::detail::node::m_amount. * CMake: use GenerateExportHeader Make use of the GenerateExportHeader CMake module to generate the dll.h header with export macros. While the produced dll.h is different, the result should be the same, i.e. nothing changes for yaml-cpp or its users. * CMake: hide all the symbols by default Hide all the symbols that are not explicitly exported with YAML_CPP_API. This way the ABI will be way smaller, and only actually exposing the public classes/functions.
325 lines
7.0 KiB
C++
325 lines
7.0 KiB
C++
#include <algorithm>
|
|
#include <cassert>
|
|
#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 {
|
|
YAML_CPP_API std::atomic<size_t> 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<YAML::detail::node*, YAML::detail::node*> 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
|