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)
{
out << " /* " << m_fieldName << " */\n";
if (m_fieldName.size())
out << " /* " << m_fieldName << " */\n";
switch (m_type)
{
case Type::EnterSubVector:
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
out << " " ATHENA_YAML_WRITER ".enterSubVector(\"" << m_fieldName << "\");\n";
out << " if (auto __v = " ATHENA_YAML_WRITER ".enterSubVector(\"" << m_fieldName << "\"))\n {\n";
break;
case Type::LeaveSubVector:
if (!p)
out << " " ATHENA_YAML_READER ".leaveSubVector();\n";
else
out << " " ATHENA_YAML_WRITER ".leaveSubVector();\n";
out << " }\n";
break;
case Type::Value:
if (!p)

View File

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

View File

@ -589,21 +589,22 @@ err:
return false;
}
void YAMLDocWriter::enterSubRecord(const char* name)
YAMLDocWriter::RecordRAII YAMLDocWriter::enterSubRecord(const char* name)
{
YAMLNode* curSub = m_subStack.back();
if (curSub->m_type != YAML_MAPPING_NODE &&
curSub->m_type != YAML_SEQUENCE_NODE)
return;
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));
else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(newNode);
m_subStack.push_back(newNode);
return RecordRAII{this};
}
void YAMLDocWriter::leaveSubRecord()
void YAMLDocWriter::_leaveSubRecord()
{
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();
if (curSub->m_type != YAML_MAPPING_NODE &&
curSub->m_type != YAML_SEQUENCE_NODE)
return;
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));
else if (curSub->m_type == YAML_SEQUENCE_NODE)
curSub->m_seqChildren.emplace_back(newNode);
m_subStack.push_back(newNode);
return VectorRAII{this};
}
void YAMLDocWriter::leaveSubVector()
void YAMLDocWriter::_leaveSubVector()
{
if (m_subStack.size() > 1)
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();
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());
if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE)
m_seqTrackerStack.push_back(0);
return true;
return RecordRAII{this};
}
else if (!name)
{
atError("Expected YAML sequence");
}
for (const auto& item : curSub->m_mapChildren)
{
@ -1034,13 +1040,13 @@ bool YAMLDocReader::enterSubRecord(const char* name)
m_subStack.push_back(item.second.get());
if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE)
m_seqTrackerStack.push_back(0);
return true;
return RecordRAII{this};
}
}
return false;
return {};
}
void YAMLDocReader::leaveSubRecord()
void YAMLDocReader::_leaveSubRecord()
{
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();
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_seqTrackerStack.push_back(0);
countOut = curSub->m_seqChildren.size();
return true;
return VectorRAII{this};
}
else
{
@ -1078,15 +1084,15 @@ bool YAMLDocReader::enterSubVector(const char* name, size_t& countOut)
}
m_subStack.push_back(nextSub);
m_seqTrackerStack.push_back(0);
return true;
return VectorRAII{this};
}
}
}
countOut = 0;
return false;
return {};
}
void YAMLDocReader::leaveSubVector()
void YAMLDocReader::_leaveSubVector()
{
if (m_subStack.size() > 1)
{