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 <utf8proc.h>
#include "DNA.hpp" #include "DNA.hpp"
#include "FileReader.hpp" #include "FileReader.hpp"
#include "FileWriter.hpp"
namespace athena::io namespace athena::io
{ {
enum class YAMLNodeStyle
{
Any,
Flow,
Block
};
struct YAMLNode struct YAMLNode
{ {
yaml_node_type_t m_type; yaml_node_type_t m_type;
std::string m_scalarString; std::string m_scalarString;
std::vector<std::unique_ptr<YAMLNode>> m_seqChildren; std::vector<std::unique_ptr<YAMLNode>> m_seqChildren;
std::vector<std::pair<std::string, std::unique_ptr<YAMLNode>>> m_mapChildren; 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) {} YAMLNode(yaml_node_type_t type) : m_type(type) {}
inline const YAMLNode* findMapChild(std::string_view key) const inline const YAMLNode* findMapChild(std::string_view key) const
{ {
@ -30,6 +39,16 @@ struct YAMLNode
return item.second.get(); return item.second.get();
return nullptr; 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> template <typename RETURNTYPE>
@ -322,14 +341,14 @@ public:
class YAMLDocWriter class YAMLDocWriter
{ {
YAMLNode m_rootNode; std::unique_ptr<YAMLNode> m_rootNode;
std::vector<YAMLNode*> m_subStack; std::vector<YAMLNode*> m_subStack;
yaml_emitter_t m_emitter; yaml_emitter_t m_emitter;
static bool RecursiveFinish(yaml_emitter_t* doc, const YAMLNode& node); static bool RecursiveFinish(yaml_emitter_t* doc, const YAMLNode& node);
void _leaveSubRecord(); void _leaveSubRecord();
void _leaveSubVector(); void _leaveSubVector();
public: public:
YAMLDocWriter(const char* classType); YAMLDocWriter(const char* classType, athena::io::IStreamReader* reader = nullptr);
~YAMLDocWriter(); ~YAMLDocWriter();
yaml_emitter_t* getEmitter() { return &m_emitter; } yaml_emitter_t* getEmitter() { return &m_emitter; }
@ -440,6 +459,8 @@ public:
void writeWString(const char* name, std::wstring_view val); void writeWString(const char* name, std::wstring_view val);
void writeU16String(const char* name, std::u16string_view val); void writeU16String(const char* name, std::u16string_view val);
void writeU32String(const char* name, std::u32string_view val); void writeU32String(const char* name, std::u32string_view val);
void setStyle(YAMLNodeStyle s);
}; };
int YAMLAthenaReader(athena::io::IStreamReader* reader, int YAMLAthenaReader(athena::io::IStreamReader* reader,
@ -571,6 +592,20 @@ struct DNAYaml : DNA<DNAE>
return true; 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> template<class DNASubtype>
static bool ValidateFromYAMLStream(athena::io::IStreamReader& fin) static bool ValidateFromYAMLStream(athena::io::IStreamReader& fin)
{ {

View File

@ -508,7 +508,7 @@ int YAMLAthenaWriter(athena::io::IStreamWriter* writer,
return 1; 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)) 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_unicode(&m_emitter, true);
yaml_emitter_set_width(&m_emitter, -1); 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) if (classType)
{ {
YAMLNode* classVal = new YAMLNode(YAML_SCALAR_NODE); YAMLNode* classVal = new YAMLNode(YAML_SCALAR_NODE);
classVal->m_scalarString.assign(classType); 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; event.data.document_start.implicit = true;
if (!yaml_emitter_emit(&m_emitter, &event)) if (!yaml_emitter_emit(&m_emitter, &event))
goto err; goto err;
if (!RecursiveFinish(&m_emitter, m_rootNode)) if (!RecursiveFinish(&m_emitter, *m_rootNode))
return false; return false;
event.type = YAML_DOCUMENT_END_EVENT; event.type = YAML_DOCUMENT_END_EVENT;
event.data.document_end.implicit = true; event.data.document_end.implicit = true;
@ -570,7 +583,7 @@ YAMLDocWriter::RecordRAII YAMLDocWriter::enterSubRecord(const char* name)
return {}; return {};
YAMLNode* newNode = new YAMLNode(YAML_MAPPING_NODE); YAMLNode* newNode = new YAMLNode(YAML_MAPPING_NODE);
if (curSub->m_type == 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) else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(newNode); curSub->m_seqChildren.emplace_back(newNode);
m_subStack.push_back(newNode); m_subStack.push_back(newNode);
@ -615,7 +628,7 @@ YAMLDocWriter::VectorRAII YAMLDocWriter::enterSubVector(const char* name)
return {}; return {};
YAMLNode* newNode = new YAMLNode(YAML_SEQUENCE_NODE); YAMLNode* newNode = new YAMLNode(YAML_SEQUENCE_NODE);
if (curSub->m_type == 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) else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(newNode); curSub->m_seqChildren.emplace_back(newNode);
m_subStack.push_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(); YAMLNode* curSub = m_subStack.back();
if (curSub->m_type == YAML_MAPPING_NODE) 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) else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(std::move(ValToNode(val))); 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(); YAMLNode* curSub = m_subStack.back();
if (curSub->m_type == YAML_MAPPING_NODE) 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) else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(std::move(ValToNode(val, byteCount))); 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); 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, static inline void InsertNode(std::vector<YAMLNode*>& nodeStack,
std::unique_ptr<YAMLNode>& mapKey, std::unique_ptr<YAMLNode>& mapKey,
std::unique_ptr<YAMLNode>& retVal, std::unique_ptr<YAMLNode>& retVal,
@ -793,7 +811,7 @@ static inline void InsertNode(std::vector<YAMLNode*>& nodeStack,
mapKey = std::move(newNode); mapKey = std::move(newNode);
else 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); 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) 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; size_t count = 0;
for (const auto& item : node.m_seqChildren) 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) 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; size_t count = 0;
for (const auto& item : node.m_mapChildren) for (const auto& item : node.m_mapChildren)
{ {