YAML file merge call to avoid clobbering existing document nodes

This commit is contained in:
Jack Andersen 2018-01-22 18:38:39 -10:00
parent de55c9acdf
commit 42b97e0306
2 changed files with 74 additions and 11 deletions

View File

@ -12,16 +12,25 @@
#include <utf8proc.h>
#include "DNA.hpp"
#include "FileReader.hpp"
#include "FileWriter.hpp"
namespace athena::io
{
enum class YAMLNodeStyle
{
Any,
Flow,
Block
};
struct YAMLNode
{
yaml_node_type_t m_type;
std::string m_scalarString;
std::vector<std::unique_ptr<YAMLNode>> m_seqChildren;
std::vector<std::pair<std::string, std::unique_ptr<YAMLNode>>> m_mapChildren;
YAMLNodeStyle m_style = YAMLNodeStyle::Any;
YAMLNode(yaml_node_type_t type) : m_type(type) {}
inline const YAMLNode* findMapChild(std::string_view key) const
{
@ -30,6 +39,16 @@ struct YAMLNode
return item.second.get();
return nullptr;
}
inline void assignMapChild(std::string_view key, std::unique_ptr<YAMLNode>&& node)
{
for (auto& item : m_mapChildren)
if (!item.first.compare(key))
{
item.second = std::move(node);
return;
}
m_mapChildren.emplace_back(key, std::move(node));
}
};
template <typename RETURNTYPE>
@ -322,14 +341,14 @@ public:
class YAMLDocWriter
{
YAMLNode m_rootNode;
std::unique_ptr<YAMLNode> m_rootNode;
std::vector<YAMLNode*> m_subStack;
yaml_emitter_t m_emitter;
static bool RecursiveFinish(yaml_emitter_t* doc, const YAMLNode& node);
void _leaveSubRecord();
void _leaveSubVector();
public:
YAMLDocWriter(const char* classType);
YAMLDocWriter(const char* classType, athena::io::IStreamReader* reader = nullptr);
~YAMLDocWriter();
yaml_emitter_t* getEmitter() { return &m_emitter; }
@ -440,6 +459,8 @@ public:
void writeWString(const char* name, std::wstring_view val);
void writeU16String(const char* name, std::u16string_view val);
void writeU32String(const char* name, std::u32string_view val);
void setStyle(YAMLNodeStyle s);
};
int YAMLAthenaReader(athena::io::IStreamReader* reader,
@ -571,6 +592,20 @@ struct DNAYaml : DNA<DNAE>
return true;
}
template <typename NameT>
bool mergeToYAMLFile(const NameT& filename)
{
athena::io::FileReader r(filename);
YAMLDocWriter docWriter(DNATypeV(), r.isOpen() ? &r : nullptr);
r.close();
write(docWriter);
athena::io::FileWriter w(filename);
if (!w.isOpen())
return false;
return docWriter.finish(&w);
}
template<class DNASubtype>
static bool ValidateFromYAMLStream(athena::io::IStreamReader& fin)
{

View File

@ -508,7 +508,7 @@ int YAMLAthenaWriter(athena::io::IStreamWriter* writer,
return 1;
}
YAMLDocWriter::YAMLDocWriter(const char* classType) : m_rootNode(YAML_MAPPING_NODE)
YAMLDocWriter::YAMLDocWriter(const char* classType, athena::io::IStreamReader* reader)
{
if (!yaml_emitter_initialize(&m_emitter))
{
@ -518,12 +518,25 @@ YAMLDocWriter::YAMLDocWriter(const char* classType) : m_rootNode(YAML_MAPPING_NO
yaml_emitter_set_unicode(&m_emitter, true);
yaml_emitter_set_width(&m_emitter, -1);
m_subStack.emplace_back(&m_rootNode);
if (reader)
{
YAMLDocReader r;
r.parse(reader);
m_rootNode = r.releaseRootNode();
if (!m_rootNode)
m_rootNode = std::make_unique<YAMLNode>(YAML_MAPPING_NODE);
}
else
{
m_rootNode = std::make_unique<YAMLNode>(YAML_MAPPING_NODE);
}
m_subStack.emplace_back(m_rootNode.get());
if (classType)
{
YAMLNode* classVal = new YAMLNode(YAML_SCALAR_NODE);
classVal->m_scalarString.assign(classType);
m_rootNode.m_mapChildren.emplace_back("DNAType", std::unique_ptr<YAMLNode>(classVal));
m_rootNode->assignMapChild("DNAType", std::unique_ptr<YAMLNode>(classVal));
}
}
@ -545,7 +558,7 @@ bool YAMLDocWriter::finish(athena::io::IStreamWriter* fout)
event.data.document_start.implicit = true;
if (!yaml_emitter_emit(&m_emitter, &event))
goto err;
if (!RecursiveFinish(&m_emitter, m_rootNode))
if (!RecursiveFinish(&m_emitter, *m_rootNode))
return false;
event.type = YAML_DOCUMENT_END_EVENT;
event.data.document_end.implicit = true;
@ -570,7 +583,7 @@ YAMLDocWriter::RecordRAII YAMLDocWriter::enterSubRecord(const char* name)
return {};
YAMLNode* newNode = new YAMLNode(YAML_MAPPING_NODE);
if (curSub->m_type == YAML_MAPPING_NODE)
curSub->m_mapChildren.emplace_back(name?std::string(name):std::string(), std::unique_ptr<YAMLNode>(newNode));
curSub->assignMapChild(name?std::string(name):std::string(), std::unique_ptr<YAMLNode>(newNode));
else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(newNode);
m_subStack.push_back(newNode);
@ -615,7 +628,7 @@ YAMLDocWriter::VectorRAII YAMLDocWriter::enterSubVector(const char* name)
return {};
YAMLNode* newNode = new YAMLNode(YAML_SEQUENCE_NODE);
if (curSub->m_type == YAML_MAPPING_NODE)
curSub->m_mapChildren.emplace_back(name?std::string(name):std::string(), std::unique_ptr<YAMLNode>(newNode));
curSub->assignMapChild(name?std::string(name):std::string(), std::unique_ptr<YAMLNode>(newNode));
else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(newNode);
m_subStack.push_back(newNode);
@ -633,7 +646,7 @@ void YAMLDocWriter::writeVal(const char* name, const INTYPE& val)
{
YAMLNode* curSub = m_subStack.back();
if (curSub->m_type == YAML_MAPPING_NODE)
curSub->m_mapChildren.emplace_back(name?name:std::string(), std::move(ValToNode(val)));
curSub->assignMapChild(name?name:std::string(), std::move(ValToNode(val)));
else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(std::move(ValToNode(val)));
}
@ -655,7 +668,7 @@ void YAMLDocWriter::writeVal(const char* name, const INTYPE& val, size_t byteCou
{
YAMLNode* curSub = m_subStack.back();
if (curSub->m_type == YAML_MAPPING_NODE)
curSub->m_mapChildren.emplace_back(name?name:std::string(), std::move(ValToNode(val, byteCount)));
curSub->assignMapChild(name?name:std::string(), std::move(ValToNode(val, byteCount)));
else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(std::move(ValToNode(val, byteCount)));
}
@ -772,6 +785,11 @@ void YAMLDocWriter::writeU32String(const char* name, std::u32string_view val)
writeVal<std::u32string_view>(name, val);
}
void YAMLDocWriter::setStyle(YAMLNodeStyle s)
{
m_subStack.back()->m_style = s;
}
static inline void InsertNode(std::vector<YAMLNode*>& nodeStack,
std::unique_ptr<YAMLNode>& mapKey,
std::unique_ptr<YAMLNode>& retVal,
@ -793,7 +811,7 @@ static inline void InsertNode(std::vector<YAMLNode*>& nodeStack,
mapKey = std::move(newNode);
else
{
parent->m_mapChildren.emplace_back(std::move(mapKey->m_scalarString), std::move(newNode));
parent->assignMapChild(mapKey->m_scalarString, std::move(newNode));
mapKey.reset(nullptr);
}
}
@ -1227,6 +1245,11 @@ static inline yaml_scalar_style_t ScalarStyle(const YAMLNode& node)
static inline yaml_sequence_style_t SequenceStyle(const YAMLNode& node)
{
if (node.m_style == YAMLNodeStyle::Flow)
return YAML_FLOW_SEQUENCE_STYLE;
else if (node.m_style == YAMLNodeStyle::Block)
return YAML_BLOCK_SEQUENCE_STYLE;
size_t count = 0;
for (const auto& item : node.m_seqChildren)
{
@ -1243,6 +1266,11 @@ static inline yaml_sequence_style_t SequenceStyle(const YAMLNode& node)
static inline yaml_mapping_style_t MappingStyle(const YAMLNode& node)
{
if (node.m_style == YAMLNodeStyle::Flow)
return YAML_FLOW_MAPPING_STYLE;
else if (node.m_style == YAMLNodeStyle::Block)
return YAML_BLOCK_MAPPING_STYLE;
size_t count = 0;
for (const auto& item : node.m_mapChildren)
{