Merge pull request #38 from libAthena/binary-size

Added binarySize method for DNA
This commit is contained in:
Jack Andersen 2015-10-17 18:16:51 -10:00
commit e861691480
3 changed files with 498 additions and 36 deletions

View File

@ -21,6 +21,7 @@ static unsigned AthenaError = 0;
#define ATHENA_DNA_WRITER "__dna_writer"
#define ATHENA_YAML_READER "__dna_docin"
#define ATHENA_YAML_WRITER "__dna_docout"
#define ATHENA_SZ_ENUMERATE "__EnumerateSize"
#ifndef INSTALL_PREFIX
#define INSTALL_PREFIX /usr/local
@ -130,6 +131,70 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor<ATDNAEmitVisitor>
return false;
}
int64_t GetSizeValue(const clang::Type* theType, unsigned width)
{
if (theType->isEnumeralType())
{
clang::EnumType* eType = (clang::EnumType*)theType;
clang::EnumDecl* eDecl = eType->getDecl();
theType = eDecl->getIntegerType().getCanonicalType().getTypePtr();
const clang::BuiltinType* bType = (clang::BuiltinType*)theType;
if (bType->isBooleanType())
{
return 1;
}
else if (bType->isUnsignedInteger() || bType->isSignedInteger())
{
return width / 8;
}
}
else if (theType->isBuiltinType())
{
const clang::BuiltinType* bType = (clang::BuiltinType*)theType;
if (bType->isBooleanType())
{
return 1;
}
else if (bType->isUnsignedInteger() || bType->isSignedInteger() || bType->isFloatingPoint())
{
return width / 8;
}
}
else if (theType->isRecordType())
{
const clang::CXXRecordDecl* rDecl = theType->getAsCXXRecordDecl();
for (const clang::FieldDecl* field : rDecl->fields())
{
if (!field->getName().compare("clangVec"))
{
const clang::VectorType* vType = (clang::VectorType*)field->getType().getTypePtr();
if (vType->isVectorType())
{
const clang::BuiltinType* eType = (clang::BuiltinType*)vType->getElementType().getTypePtr();
const uint64_t width = context.getTypeInfo(eType).Width;
if (!eType->isBuiltinType() || !eType->isFloatingPoint() ||
(width != 32 && width != 64))
continue;
if (vType->getNumElements() == 2)
{
return width / 8 * 2;
}
else if (vType->getNumElements() == 3)
{
return width / 8 * 3;
}
else if (vType->getNumElements() == 4)
{
return width / 8 * 4;
}
}
}
}
}
return 0;
}
std::string GetOpString(const clang::Type* theType, unsigned width,
const std::string& fieldName, bool writerPass,
const std::string& funcPrefix, bool& isDNATypeOut)
@ -630,6 +695,356 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor<ATDNAEmitVisitor>
return std::string();
}
void emitSizeFuncs(clang::CXXRecordDecl* decl, const std::string& baseDNA)
{
int64_t podTotal = 0;
fileOut << "size_t " << decl->getQualifiedNameAsString() << "::binarySize(size_t __isz) const\n{\n";
if (baseDNA.size())
{
fileOut << " __isz = " << baseDNA << "::binarySize(__isz);\n";
}
for (const clang::FieldDecl* field : decl->fields())
{
clang::QualType qualType = field->getType();
clang::TypeInfo regTypeInfo = context.getTypeInfo(qualType);
const clang::Type* regType = qualType.getTypePtrOrNull();
while (regType->getTypeClass() == clang::Type::Elaborated ||
regType->getTypeClass() == clang::Type::Typedef)
regType = regType->getUnqualifiedDesugaredType();
/* Resolve constant array */
size_t arraySize = 1;
bool isArray = false;
if (regType->getTypeClass() == clang::Type::ConstantArray)
{
isArray = true;
const clang::ConstantArrayType* caType = (clang::ConstantArrayType*)regType;
arraySize = caType->getSize().getZExtValue();
qualType = caType->getElementType();
regTypeInfo = context.getTypeInfo(qualType);
regType = qualType.getTypePtrOrNull();
if (regType->getTypeClass() == clang::Type::Elaborated)
regType = regType->getUnqualifiedDesugaredType();
}
for (int e=0 ; e<arraySize ; ++e)
{
std::string fieldName;
if (isArray)
{
char subscript[16];
snprintf(subscript, 16, "[%d]", e);
fieldName = field->getName().str() + subscript;
}
else
fieldName = field->getName();
if (regType->getTypeClass() == clang::Type::TemplateSpecialization)
{
const clang::TemplateSpecializationType* tsType = (const clang::TemplateSpecializationType*)regType;
const clang::TemplateDecl* tsDecl = tsType->getTemplateName().getAsTemplateDecl();
if (!tsDecl->getName().compare("Value"))
{
clang::QualType templateType;
const clang::TemplateArgument* typeArg = nullptr;
size_t typeSize = 0;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Type)
{
typeArg = &arg;
templateType = arg.getAsType().getCanonicalType();
const clang::Type* type = arg.getAsType().getCanonicalType().getTypePtr();
typeSize = GetSizeValue(type, regTypeInfo.Width);
}
}
if (typeSize)
podTotal += typeSize;
else
fileOut << " __isz = " << fieldName << ".binarySize(__isz);\n";
}
else if (!tsDecl->getName().compare("Vector"))
{
clang::QualType templateType;
const clang::TemplateArgument* typeArg = nullptr;
size_t typeSize = 0;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Type)
{
typeArg = &arg;
templateType = arg.getAsType().getCanonicalType();
clang::TypeInfo typeInfo = context.getTypeInfo(templateType);
typeSize = GetSizeValue(templateType.getTypePtr(), typeInfo.Width);
}
}
if (typeSize)
fileOut << " __isz += " << fieldName << ".size() * " << typeSize << ";\n";
else
fileOut << " __isz = " ATHENA_SZ_ENUMERATE "(__isz, " << fieldName << ");\n";
}
else if (!tsDecl->getName().compare("Buffer"))
{
const clang::Expr* sizeExpr = nullptr;
std::string sizeExprStr;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Expression)
{
const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)arg.getAsExpr()->IgnoreImpCasts();
if (uExpr->getStmtClass() == clang::Stmt::UnaryExprOrTypeTraitExprClass &&
uExpr->getKind() == clang::UETT_SizeOf)
{
const clang::Expr* argExpr = uExpr->getArgumentExpr();
while (argExpr->getStmtClass() == clang::Stmt::ParenExprClass)
argExpr = ((clang::ParenExpr*)argExpr)->getSubExpr();
sizeExpr = argExpr;
llvm::raw_string_ostream strStream(sizeExprStr);
argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy());
}
}
}
fileOut << " __isz += (" << sizeExprStr << ");\n";
}
else if (!tsDecl->getName().compare("String"))
{
const clang::Expr* sizeExpr = nullptr;
std::string sizeExprStr;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Expression)
{
const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts();
const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr;
llvm::APSInt sizeLiteral;
if (expr->getStmtClass() == clang::Stmt::UnaryExprOrTypeTraitExprClass &&
uExpr->getKind() == clang::UETT_SizeOf)
{
const clang::Expr* argExpr = uExpr->getArgumentExpr();
while (argExpr->getStmtClass() == clang::Stmt::ParenExprClass)
argExpr = ((clang::ParenExpr*)argExpr)->getSubExpr();
sizeExpr = argExpr;
llvm::raw_string_ostream strStream(sizeExprStr);
argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy());
}
else if (expr->isIntegerConstantExpr(sizeLiteral, context))
{
sizeExprStr = sizeLiteral.toString(10);
}
}
}
if (sizeExprStr.size())
fileOut << " __isz += (" << sizeExprStr << ");\n";
else
fileOut << " __isz += " << fieldName << ".size() + 1;\n";
}
else if (!tsDecl->getName().compare("WString"))
{
const clang::Expr* sizeExpr = nullptr;
std::string sizeExprStr;
size_t idx = 0;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Expression)
{
const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts();
if (idx == 0)
{
llvm::APSInt sizeLiteral;
const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr;
if (expr->getStmtClass() == clang::Stmt::UnaryExprOrTypeTraitExprClass &&
uExpr->getKind() == clang::UETT_SizeOf)
{
const clang::Expr* argExpr = uExpr->getArgumentExpr();
while (argExpr->getStmtClass() == clang::Stmt::ParenExprClass)
argExpr = ((clang::ParenExpr*)argExpr)->getSubExpr();
sizeExpr = argExpr;
llvm::raw_string_ostream strStream(sizeExprStr);
argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy());
}
else if (expr->isIntegerConstantExpr(sizeLiteral, context))
{
sizeExprStr = sizeLiteral.toString(10);
}
}
}
++idx;
}
if (sizeExprStr.size())
fileOut << " __isz += (" << sizeExprStr << ") * 2;\n";
else
fileOut << " __isz += (" << fieldName << ".size() + 1) * 2;\n";
}
else if (!tsDecl->getName().compare("WStringAsString"))
{
const clang::Expr* sizeExpr = nullptr;
std::string sizeExprStr;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Expression)
{
const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts();
const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr;
llvm::APSInt sizeLiteral;
if (expr->getStmtClass() == clang::Stmt::UnaryExprOrTypeTraitExprClass &&
uExpr->getKind() == clang::UETT_SizeOf)
{
const clang::Expr* argExpr = uExpr->getArgumentExpr();
while (argExpr->getStmtClass() == clang::Stmt::ParenExprClass)
argExpr = ((clang::ParenExpr*)argExpr)->getSubExpr();
sizeExpr = argExpr;
llvm::raw_string_ostream strStream(sizeExprStr);
argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy());
}
else if (expr->isIntegerConstantExpr(sizeLiteral, context))
{
sizeExprStr = sizeLiteral.toString(10);
}
}
}
if (sizeExprStr.size())
fileOut << " __isz += (" << sizeExprStr << ") * 2;\n";
else
fileOut << " __isz += (" << fieldName << ".size() + 1) * 2;\n";
}
else if (!tsDecl->getName().compare("Seek"))
{
size_t idx = 0;
const clang::Expr* offsetExpr = nullptr;
std::string offsetExprStr;
llvm::APSInt direction(64, 0);
const clang::Expr* directionExpr = nullptr;
bool bad = false;
int64_t literal = 0;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Expression)
{
const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts();
if (!idx)
{
offsetExpr = expr;
const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr;
llvm::APSInt offsetLiteral;
if (expr->getStmtClass() == clang::Stmt::UnaryExprOrTypeTraitExprClass &&
uExpr->getKind() == clang::UETT_SizeOf)
{
const clang::Expr* argExpr = uExpr->getArgumentExpr();
while (argExpr->getStmtClass() == clang::Stmt::ParenExprClass)
argExpr = ((clang::ParenExpr*)argExpr)->getSubExpr();
offsetExpr = argExpr;
llvm::raw_string_ostream strStream(offsetExprStr);
argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy());
}
else if (expr->isIntegerConstantExpr(offsetLiteral, context))
{
literal = offsetLiteral.getSExtValue();
}
}
else
{
directionExpr = expr;
if (!expr->isIntegerConstantExpr(direction, context))
{
bad = true;
break;
}
}
}
++idx;
}
if (bad)
continue;
int64_t directionVal = direction.getSExtValue();
if (literal)
{
if (directionVal == 0)
{
podTotal = 0;
fileOut << " __isz = " << literal << ";\n";
}
else if (directionVal == 1)
podTotal += literal;
}
else
{
if (directionVal == 0)
{
podTotal = 0;
fileOut << " __isz = (" << offsetExprStr << ");\n";
}
else if (directionVal == 1)
fileOut << " __isz += (" << offsetExprStr << ");\n";
}
}
else if (!tsDecl->getName().compare("Align"))
{
llvm::APSInt align(64, 0);
bool bad = false;
for (const clang::TemplateArgument& arg : *tsType)
{
if (arg.getKind() == clang::TemplateArgument::Expression)
{
const clang::Expr* expr = arg.getAsExpr();
if (!expr->isIntegerConstantExpr(align, context))
{
bad = true;
break;
}
}
}
if (bad)
continue;
int64_t alignVal = align.getSExtValue();
if (alignVal)
{
fileOut << " __isz += " << podTotal << ";\n";
podTotal = 0;
if (align.isPowerOf2())
fileOut << " __isz = (__isz + " << alignVal-1 << ") & ~" << alignVal-1 << ";\n";
else
fileOut << " __isz = (__isz + " << alignVal-1 << ") / " << alignVal << " * " << alignVal << ";\n";
}
}
}
else if (regType->getTypeClass() == clang::Type::Record)
{
const clang::CXXRecordDecl* cxxRDecl = regType->getAsCXXRecordDecl();
std::string baseDNA;
bool isYAML = false;
if (cxxRDecl && isDNARecord(cxxRDecl, baseDNA, isYAML))
{
fileOut << " __isz = " << fieldName << ".binarySize(__isz);\n";
}
}
}
}
if (podTotal)
fileOut << " return __isz + " << podTotal << ";\n}\n\n";
else
fileOut << " return __isz;\n}\n\n";
}
void emitIOFuncs(clang::CXXRecordDecl* decl, const std::string& baseDNA)
{
/* Two passes - read then write */
@ -1789,6 +2204,7 @@ public:
emitIOFuncs(decl, baseDNA);
if (isYAML)
emitYAMLFuncs(decl, baseDNA);
emitSizeFuncs(decl, baseDNA);
return true;
}

View File

@ -44,6 +44,8 @@ struct WStringAsString;
template <Endian DNAE>
struct DNA
{
virtual ~DNA() {}
/**
* @brief Common virtual read function for all DNA types
*/
@ -52,6 +54,12 @@ struct DNA
* @brief Common virtual write function for all DNA types
*/
virtual void write(IStreamWriter&) const=0;
/**
* @brief Common virtual binary size computation for all DNA types
* @param __isz initial cumulative value to add result to
* @return Cumulative size
*/
virtual size_t binarySize(size_t __isz) const=0;
/**
* @brief Template type signaling atdna to capture the value where it's used
@ -121,6 +129,20 @@ struct DNA
* @brief Meta Template preventing atdna from emitting read/write implementations
*/
struct Delete {};
/**
* @brief Internal DNA helper for accumulating binarySize
* @param __isz initial size value
* @param v Vector to enumerate
* @return Cumulative total
*/
template <typename T>
static size_t __EnumerateSize(size_t __isz, const T& v)
{
for (const auto& val : v)
__isz = val.binarySize(__isz);
return __isz;
}
};
/**
@ -130,15 +152,19 @@ template <size_t sizeVar, Endian VE>
struct Buffer : public DNA<VE>, public std::unique_ptr<atUint8[]>
{
typename DNA<VE>::Delete expl;
inline void read(IStreamReader& reader)
void read(IStreamReader& reader)
{
reset(new atUint8[sizeVar]);
reader.readUBytesToBuf(get(), sizeVar);
}
inline void write(IStreamWriter& writer) const
void write(IStreamWriter& writer) const
{
writer.writeUBytes(get(), sizeVar);
}
size_t binarySize(size_t __isz) const
{
return __isz + sizeVar;
}
};
/**
@ -148,13 +174,15 @@ template <atInt32 sizeVar, Endian VE>
struct String : public DNA<VE>, public std::string
{
typename DNA<VE>::Delete expl;
inline void read(IStreamReader& reader)
void read(IStreamReader& reader)
{this->assign(std::move(reader.readString(sizeVar)));}
inline void write(IStreamWriter& writer) const
void write(IStreamWriter& writer) const
{writer.writeString(*this, sizeVar);}
inline std::string& operator=(const std::string& __str)
size_t binarySize(size_t __isz) const
{return __isz + ((sizeVar<0)?(this->size()+1):sizeVar);}
std::string& operator=(const std::string& __str)
{return this->assign(__str);}
inline std::string& operator=(std::string&& __str)
std::string& operator=(std::string&& __str)
{this->swap(__str); return *this;}
};
@ -165,19 +193,21 @@ template <atInt32 sizeVar, Endian VE>
struct WString : public DNA<VE>, public std::wstring
{
typename DNA<VE>::Delete expl;
inline void read(IStreamReader& reader)
void read(IStreamReader& reader)
{
reader.setEndian(VE);
this->assign(std::move(reader.readWString(sizeVar)));
}
inline void write(IStreamWriter& writer) const
void write(IStreamWriter& writer) const
{
writer.setEndian(VE);
writer.writeWString(*this, sizeVar);
}
inline std::wstring& operator=(const std::wstring& __str)
size_t binarySize(size_t __isz) const
{return __isz + (((sizeVar<0)?(this->size()+1):sizeVar)*2);}
std::wstring& operator=(const std::wstring& __str)
{return this->assign(__str);}
inline std::wstring& operator=(std::wstring&& __str)
std::wstring& operator=(std::wstring&& __str)
{this->swap(__str); return *this;}
};
@ -188,13 +218,15 @@ template <atInt32 sizeVar, Endian VE>
struct WStringAsString : public DNA<VE>, public std::string
{
typename DNA<VE>::Delete expl;
inline void read(IStreamReader& reader)
void read(IStreamReader& reader)
{*this = reader.readWStringAsString(sizeVar);}
inline void write(IStreamWriter& writer) const
void write(IStreamWriter& writer) const
{writer.writeStringAsWString(*this, sizeVar);}
inline std::string& operator=(const std::string& __str)
size_t binarySize(size_t __isz) const
{return __isz + (((sizeVar<0)?(this->size()+1):sizeVar)*2);}
std::string& operator=(const std::string& __str)
{return this->assign(__str);}
inline std::string& operator=(std::string&& __str)
std::string& operator=(std::string&& __str)
{this->swap(__str); return *this;}
};
@ -202,11 +234,13 @@ struct WStringAsString : public DNA<VE>, public std::string
#define DECL_DNA \
void read(Athena::io::IStreamReader&); \
void write(Athena::io::IStreamWriter&) const; \
size_t binarySize(size_t __isz) const;
/** Macro to automatically declare read/write methods and prevent outputting implementation */
#define DECL_EXPLICIT_DNA \
void read(Athena::io::IStreamReader&); \
void write(Athena::io::IStreamWriter&) const; \
size_t binarySize(size_t __isz) const; \
Delete __dna_delete;
/** Macro to supply count variable to atdna and mute it for other compilers */

View File

@ -1049,6 +1049,8 @@ struct WStringAsStringYaml;
template <Endian DNAE>
struct DNAYaml : DNA<DNAE>
{
virtual ~DNAYaml() {}
virtual void toYAML(YAMLDocWriter& out) const=0;
virtual void fromYAML(YAMLDocReader& in)=0;
static const char* DNAType() {return nullptr;}
@ -1230,18 +1232,22 @@ template <size_t sizeVar, Endian VE>
struct BufferYaml : public DNAYaml<VE>, public std::unique_ptr<atUint8[]>
{
typename DNA<VE>::Delete expl;
inline void read(IStreamReader& reader)
void read(IStreamReader& reader)
{
reset(new atUint8[sizeVar]);
reader.readUBytesToBuf(get(), sizeVar);
}
inline void write(IStreamWriter& writer) const
void write(IStreamWriter& writer) const
{
writer.writeUBytes(get(), sizeVar);
}
inline void fromYAML(Athena::io::YAMLDocReader& reader)
size_t binarySize(size_t __isz) const
{
return __isz + sizeVar;
}
void fromYAML(Athena::io::YAMLDocReader& reader)
{*this = reader.readUBytes(nullptr);}
inline void toYAML(Athena::io::YAMLDocWriter& writer) const
void toYAML(Athena::io::YAMLDocWriter& writer) const
{writer.writeUBytes(nullptr, *this, sizeVar);}
};
@ -1249,17 +1255,19 @@ template <atInt32 sizeVar, Endian VE>
struct StringYaml : public DNAYaml<VE>, public std::string
{
typename DNA<VE>::Delete expl;
inline void read(IStreamReader& reader)
void read(IStreamReader& reader)
{this->assign(std::move(reader.readString(sizeVar)));}
inline void write(IStreamWriter& writer) const
void write(IStreamWriter& writer) const
{writer.writeString(*this, sizeVar);}
inline void fromYAML(Athena::io::YAMLDocReader& reader)
size_t binarySize(size_t __isz) const
{return __isz + ((sizeVar<0)?(this->size()+1):sizeVar);}
void fromYAML(Athena::io::YAMLDocReader& reader)
{this->assign(std::move(reader.readString(nullptr)));}
inline void toYAML(Athena::io::YAMLDocWriter& writer) const
void toYAML(Athena::io::YAMLDocWriter& writer) const
{writer.writeString(nullptr, *this);}
inline std::string& operator=(const std::string& __str)
std::string& operator=(const std::string& __str)
{return this->assign(__str);}
inline std::string& operator=(std::string&& __str)
std::string& operator=(std::string&& __str)
{this->swap(__str); return *this;}
};
@ -1267,23 +1275,25 @@ template <atInt32 sizeVar, Endian VE>
struct WStringYaml : public DNAYaml<VE>, public std::wstring
{
typename DNA<VE>::Delete expl;
inline void read(IStreamReader& reader)
void read(IStreamReader& reader)
{
reader.setEndian(VE);
this->assign(std::move(reader.readWString(sizeVar)));
}
inline void write(IStreamWriter& writer) const
void write(IStreamWriter& writer) const
{
writer.setEndian(VE);
writer.writeWString(*this, sizeVar);
}
inline void fromYAML(Athena::io::YAMLDocReader& reader)
size_t binarySize(size_t __isz) const
{return __isz + (((sizeVar<0)?(this->size()+1):sizeVar)*2);}
void fromYAML(Athena::io::YAMLDocReader& reader)
{this->assign(std::move(reader.readWString(nullptr)));}
inline void toYAML(Athena::io::YAMLDocWriter& writer) const
void toYAML(Athena::io::YAMLDocWriter& writer) const
{writer.writeWString(nullptr, *this);}
inline std::wstring& operator=(const std::wstring& __str)
std::wstring& operator=(const std::wstring& __str)
{return this->assign(__str);}
inline std::wstring& operator=(std::wstring&& __str)
std::wstring& operator=(std::wstring&& __str)
{this->swap(__str); return *this;}
};
@ -1291,17 +1301,19 @@ template <atInt32 sizeVar, Endian VE>
struct WStringAsStringYaml : public DNAYaml<VE>, public std::string
{
typename DNA<VE>::Delete expl;
inline void read(IStreamReader& reader)
void read(IStreamReader& reader)
{*this = reader.readWStringAsString(sizeVar);}
inline void write(IStreamWriter& writer) const
void write(IStreamWriter& writer) const
{writer.writeStringAsWString(*this, sizeVar);}
inline void fromYAML(Athena::io::YAMLDocReader& reader)
size_t binarySize(size_t __isz) const
{return __isz + (((sizeVar<0)?(this->size()+1):sizeVar)*2);}
void fromYAML(Athena::io::YAMLDocReader& reader)
{this->assign(std::move(reader.readString(nullptr)));}
inline void toYAML(Athena::io::YAMLDocWriter& writer) const
void toYAML(Athena::io::YAMLDocWriter& writer) const
{writer.writeString(nullptr, *this);}
inline std::string& operator=(const std::string& __str)
std::string& operator=(const std::string& __str)
{return this->assign(__str);}
inline std::string& operator=(std::string&& __str)
std::string& operator=(std::string&& __str)
{this->swap(__str); return *this;}
};