Use RAII context management for YAML vectors and records

This commit is contained in:
Jack Andersen 2017-02-12 13:49:21 -10:00
parent 9ccf9f596b
commit 2a4fc3e3b3
3 changed files with 123 additions and 81 deletions

View File

@ -110,20 +110,18 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor<ATDNAEmitVisitor>
{ {
if (m_output) if (m_output)
{ {
if (m_fieldName.size())
out << " /* " << m_fieldName << " */\n"; out << " /* " << m_fieldName << " */\n";
switch (m_type) switch (m_type)
{ {
case Type::EnterSubVector: case Type::EnterSubVector:
if (!p) if (!p)
out << " size_t __" << m_fieldName << "Count;\n " ATHENA_YAML_READER ".enterSubVector(\"" << m_fieldName << "\", __" << m_fieldName << "Count);\n"; out << " size_t __" << m_fieldName << "Count;\n if (auto __v = " ATHENA_YAML_READER ".enterSubVector(\"" << m_fieldName << "\", __" << m_fieldName << "Count))\n {\n";
else else
out << " " ATHENA_YAML_WRITER ".enterSubVector(\"" << m_fieldName << "\");\n"; out << " if (auto __v = " ATHENA_YAML_WRITER ".enterSubVector(\"" << m_fieldName << "\"))\n {\n";
break; break;
case Type::LeaveSubVector: case Type::LeaveSubVector:
if (!p) out << " }\n";
out << " " ATHENA_YAML_READER ".leaveSubVector();\n";
else
out << " " ATHENA_YAML_WRITER ".leaveSubVector();\n";
break; break;
case Type::Value: case Type::Value:
if (!p) if (!p)

View File

@ -179,6 +179,8 @@ class YAMLDocReader
std::vector<int> m_seqTrackerStack; std::vector<int> m_seqTrackerStack;
yaml_parser_t m_parser; yaml_parser_t m_parser;
std::unique_ptr<YAMLNode> ParseEvents(athena::io::IStreamReader* reader); std::unique_ptr<YAMLNode> ParseEvents(athena::io::IStreamReader* reader);
void _leaveSubRecord();
void _leaveSubVector();
public: public:
YAMLDocReader(); YAMLDocReader();
@ -197,19 +199,40 @@ public:
inline const YAMLNode* getCurNode() const { return m_subStack.empty() ? nullptr : m_subStack.back(); } inline const YAMLNode* getCurNode() const { return m_subStack.empty() ? nullptr : m_subStack.back(); }
std::unique_ptr<YAMLNode> releaseRootNode() { return std::move(m_rootNode); } std::unique_ptr<YAMLNode> releaseRootNode() { return std::move(m_rootNode); }
bool enterSubRecord(const char* name); class RecordRAII
void leaveSubRecord(); {
friend class YAMLDocReader;
YAMLDocReader* m_r = nullptr;
RecordRAII(YAMLDocReader* r) : m_r(r) {}
RecordRAII() = default;
public:
operator bool() const { return m_r != nullptr; }
~RecordRAII() { if (m_r) m_r->_leaveSubRecord(); }
};
friend class RecordRAII;
RecordRAII enterSubRecord(const char* name);
template <class T> template <class T>
void enumerate(const char* name, T& record) void enumerate(const char* name, T& record)
{ {
enterSubRecord(name); if (auto rec = enterSubRecord(name))
record.read(*this); record.read(*this);
leaveSubRecord();
} }
bool enterSubVector(const char* name, size_t& countOut); class VectorRAII
void leaveSubVector(); {
friend class YAMLDocReader;
YAMLDocReader* m_r = nullptr;
VectorRAII(YAMLDocReader* r) : m_r(r) {}
VectorRAII() = default;
public:
operator bool() const { return m_r != nullptr; }
~VectorRAII() { if (m_r) m_r->_leaveSubVector(); }
};
friend class VectorRAII;
VectorRAII enterSubVector(const char* name, size_t& countOut);
template <class T> template <class T>
size_t enumerate(const char* name, std::vector<T>& vector, size_t enumerate(const char* name, std::vector<T>& vector,
@ -219,17 +242,17 @@ public:
!std::is_same<T, atVec4f>::value>::type* = 0) !std::is_same<T, atVec4f>::value>::type* = 0)
{ {
size_t countOut; size_t countOut;
enterSubVector(name, countOut); if (auto v = enterSubVector(name, countOut))
{
vector.clear(); vector.clear();
vector.reserve(countOut); vector.reserve(countOut);
for (size_t i=0 ; i<countOut ; ++i) for (size_t i=0 ; i<countOut ; ++i)
{ {
vector.emplace_back(); vector.emplace_back();
enterSubRecord(nullptr); if (auto rec = enterSubRecord(nullptr))
vector.back().read(*this); vector.back().read(*this);
leaveSubRecord();
} }
leaveSubVector(); }
return countOut; return countOut;
} }
@ -241,12 +264,13 @@ public:
std::is_same<T, atVec4f>::value>::type* = 0) std::is_same<T, atVec4f>::value>::type* = 0)
{ {
size_t countOut; size_t countOut;
enterSubVector(name, countOut); if (auto v = enterSubVector(name, countOut))
{
vector.clear(); vector.clear();
vector.reserve(countOut); vector.reserve(countOut);
for (size_t i=0 ; i<countOut ; ++i) for (size_t i=0 ; i<countOut ; ++i)
vector.push_back(readVal<T>(name)); vector.push_back(readVal<T>(name));
leaveSubVector(); }
return countOut; return countOut;
} }
@ -255,17 +279,17 @@ public:
std::function<void(YAMLDocReader&, T&)> readf) std::function<void(YAMLDocReader&, T&)> readf)
{ {
size_t countOut; size_t countOut;
enterSubVector(name, countOut); if (auto v = enterSubVector(name, countOut))
{
vector.clear(); vector.clear();
vector.reserve(countOut); vector.reserve(countOut);
for (size_t i=0 ; i<countOut ; ++i) for (size_t i=0 ; i<countOut ; ++i)
{ {
vector.emplace_back(); vector.emplace_back();
enterSubRecord(nullptr); if (auto rec = enterSubRecord(nullptr))
readf(*this, vector.back()); readf(*this, vector.back());
leaveSubRecord();
} }
leaveSubVector(); }
return countOut; return countOut;
} }
@ -299,6 +323,8 @@ class YAMLDocWriter
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 _leaveSubVector();
public: public:
YAMLDocWriter(const char* classType); YAMLDocWriter(const char* classType);
~YAMLDocWriter(); ~YAMLDocWriter();
@ -309,19 +335,40 @@ public:
inline YAMLNode* getCurNode() const { return m_subStack.empty() ? nullptr : m_subStack.back(); } inline YAMLNode* getCurNode() const { return m_subStack.empty() ? nullptr : m_subStack.back(); }
void enterSubRecord(const char* name); class RecordRAII
void leaveSubRecord(); {
friend class YAMLDocWriter;
YAMLDocWriter* m_w = nullptr;
RecordRAII(YAMLDocWriter* w) : m_w(w) {}
RecordRAII() = default;
public:
operator bool() const { return m_w != nullptr; }
~RecordRAII() { if (m_w) m_w->_leaveSubRecord(); }
};
friend class RecordRAII;
RecordRAII enterSubRecord(const char* name);
template <class T> template <class T>
void enumerate(const char* name, T& record) void enumerate(const char* name, T& record)
{ {
enterSubRecord(name); if (auto rec = enterSubRecord(name))
record.write(*this); record.write(*this);
leaveSubRecord();
} }
void enterSubVector(const char* name); class VectorRAII
void leaveSubVector(); {
friend class YAMLDocWriter;
YAMLDocWriter* m_w = nullptr;
VectorRAII(YAMLDocWriter* w) : m_w(w) {}
VectorRAII() = default;
public:
operator bool() const { return m_w != nullptr; }
~VectorRAII() { if (m_w) m_w->_leaveSubVector(); }
};
friend class VectorRAII;
VectorRAII enterSubVector(const char* name);
template <class T> template <class T>
void enumerate(const char* name, const std::vector<T>& vector, void enumerate(const char* name, const std::vector<T>& vector,
@ -333,14 +380,10 @@ public:
!std::is_same<T, atVec3d>::value && !std::is_same<T, atVec3d>::value &&
!std::is_same<T, atVec4d>::value>::type* = 0) !std::is_same<T, atVec4d>::value>::type* = 0)
{ {
enterSubVector(name); if (auto v = enterSubVector(name))
for (const T& item : vector) for (const T& item : vector)
{ if (auto rec = enterSubRecord(nullptr))
enterSubRecord(nullptr);
item.write(*this); item.write(*this);
leaveSubRecord();
}
leaveSubVector();
} }
template <class T> template <class T>
@ -353,24 +396,19 @@ public:
std::is_same<T, atVec3d>::value || std::is_same<T, atVec3d>::value ||
std::is_same<T, atVec4d>::value>::type* = 0) std::is_same<T, atVec4d>::value>::type* = 0)
{ {
enterSubVector(name); if (auto v = enterSubVector(name))
for (T item : vector) for (T item : vector)
writeVal<T>(nullptr, item); writeVal<T>(nullptr, item);
leaveSubVector();
} }
template <class T> template <class T>
void enumerate(const char* name, const std::vector<T>& vector, void enumerate(const char* name, const std::vector<T>& vector,
std::function<void(YAMLDocWriter&, const T&)> writef) std::function<void(YAMLDocWriter&, const T&)> writef)
{ {
enterSubVector(name); if (auto v = enterSubVector(name))
for (const T& item : vector) for (const T& item : vector)
{ if (auto rec = enterSubRecord(nullptr))
enterSubRecord(nullptr);
writef(*this, item); writef(*this, item);
leaveSubRecord();
}
leaveSubVector();
} }
template <typename INTYPE> template <typename INTYPE>

View File

@ -589,21 +589,22 @@ err:
return false; return false;
} }
void YAMLDocWriter::enterSubRecord(const char* name) YAMLDocWriter::RecordRAII YAMLDocWriter::enterSubRecord(const char* name)
{ {
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_type != YAML_SEQUENCE_NODE) curSub->m_type != YAML_SEQUENCE_NODE)
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->m_mapChildren.emplace_back(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);
return RecordRAII{this};
} }
void YAMLDocWriter::leaveSubRecord() void YAMLDocWriter::_leaveSubRecord()
{ {
if (m_subStack.size() > 1) if (m_subStack.size() > 1)
{ {
@ -633,21 +634,22 @@ void YAMLDocWriter::leaveSubRecord()
} }
} }
void YAMLDocWriter::enterSubVector(const char* name) YAMLDocWriter::VectorRAII YAMLDocWriter::enterSubVector(const char* name)
{ {
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_type != YAML_SEQUENCE_NODE) curSub->m_type != YAML_SEQUENCE_NODE)
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->m_mapChildren.emplace_back(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);
return VectorRAII{this};
} }
void YAMLDocWriter::leaveSubVector() void YAMLDocWriter::_leaveSubVector()
{ {
if (m_subStack.size() > 1) if (m_subStack.size() > 1)
m_subStack.pop_back(); m_subStack.pop_back();
@ -1016,7 +1018,7 @@ bool YAMLDocReader::ValidateClassType(const char* expectedType)
}); });
} }
bool YAMLDocReader::enterSubRecord(const char* name) YAMLDocReader::RecordRAII YAMLDocReader::enterSubRecord(const char* name)
{ {
YAMLNode* curSub = m_subStack.back(); YAMLNode* curSub = m_subStack.back();
if (curSub->m_type == YAML_SEQUENCE_NODE) if (curSub->m_type == YAML_SEQUENCE_NODE)
@ -1025,7 +1027,11 @@ bool YAMLDocReader::enterSubRecord(const char* name)
m_subStack.push_back(curSub->m_seqChildren[seqIdx++].get()); m_subStack.push_back(curSub->m_seqChildren[seqIdx++].get());
if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE) if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE)
m_seqTrackerStack.push_back(0); m_seqTrackerStack.push_back(0);
return true; return RecordRAII{this};
}
else if (!name)
{
atError("Expected YAML sequence");
} }
for (const auto& item : curSub->m_mapChildren) for (const auto& item : curSub->m_mapChildren)
{ {
@ -1034,13 +1040,13 @@ bool YAMLDocReader::enterSubRecord(const char* name)
m_subStack.push_back(item.second.get()); m_subStack.push_back(item.second.get());
if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE) if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE)
m_seqTrackerStack.push_back(0); m_seqTrackerStack.push_back(0);
return true; return RecordRAII{this};
} }
} }
return false; return {};
} }
void YAMLDocReader::leaveSubRecord() void YAMLDocReader::_leaveSubRecord()
{ {
if (m_subStack.size() > 1) if (m_subStack.size() > 1)
{ {
@ -1050,7 +1056,7 @@ void YAMLDocReader::leaveSubRecord()
} }
} }
bool YAMLDocReader::enterSubVector(const char* name, size_t& countOut) YAMLDocReader::VectorRAII YAMLDocReader::enterSubVector(const char* name, size_t& countOut)
{ {
YAMLNode* curSub = m_subStack.back(); YAMLNode* curSub = m_subStack.back();
if (!name && curSub->m_type == YAML_SEQUENCE_NODE) if (!name && curSub->m_type == YAML_SEQUENCE_NODE)
@ -1058,7 +1064,7 @@ bool YAMLDocReader::enterSubVector(const char* name, size_t& countOut)
m_subStack.push_back(curSub); m_subStack.push_back(curSub);
m_seqTrackerStack.push_back(0); m_seqTrackerStack.push_back(0);
countOut = curSub->m_seqChildren.size(); countOut = curSub->m_seqChildren.size();
return true; return VectorRAII{this};
} }
else else
{ {
@ -1078,15 +1084,15 @@ bool YAMLDocReader::enterSubVector(const char* name, size_t& countOut)
} }
m_subStack.push_back(nextSub); m_subStack.push_back(nextSub);
m_seqTrackerStack.push_back(0); m_seqTrackerStack.push_back(0);
return true; return VectorRAII{this};
} }
} }
} }
countOut = 0; countOut = 0;
return false; return {};
} }
void YAMLDocReader::leaveSubVector() void YAMLDocReader::_leaveSubVector()
{ {
if (m_subStack.size() > 1) if (m_subStack.size() > 1)
{ {