From 62b6d6792a04792587f19d8fdf4c34d251fcfce0 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Wed, 21 Feb 2018 21:18:59 -1000 Subject: [PATCH] Add ability to generate and specialize DNA class templates --- atdna/main.cpp | 2367 +++++++++++++----------------- atdna/test.cpp | 2 +- atdna/test.hpp | 50 +- include/athena/DNA.hpp | 45 + include/athena/DNAOp.hpp | 1002 ++++++++----- include/athena/DNAYaml.hpp | 26 +- include/athena/Global.hpp | 21 + include/athena/YAMLDocReader.hpp | 19 +- include/athena/YAMLDocWriter.hpp | 31 +- 9 files changed, 1866 insertions(+), 1697 deletions(-) diff --git a/atdna/main.cpp b/atdna/main.cpp index 6213ae1..c448569 100644 --- a/atdna/main.cpp +++ b/atdna/main.cpp @@ -118,7 +118,10 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor hasWrite = true; } if (hasRead && hasWrite) - baseDNA = rDecl->getQualifiedNameAsString(); + { + std::string templateStmt; + GetNestedTypeName(rDecl, templateStmt, baseDNA); + } return true; } } @@ -191,510 +194,6 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor return 0; } -#if 0 - std::string GetOpString(const clang::Type* theType, unsigned width, - const std::string& fieldName, bool writerPass, - const std::string& funcPrefix, bool& isDNATypeOut) - { - isDNATypeOut = false; - if (writerPass) - { - 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 ATHENA_DNA_WRITER ".writeBool(bool(" + fieldName + "));"; - } - else if (bType->isUnsignedInteger()) - { - if (width == 8) - return ATHENA_DNA_WRITER ".writeUByte(atUint8(" + fieldName + "));"; - else if (width == 16) - return ATHENA_DNA_WRITER ".writeUint16" + funcPrefix + "(atUint16(" + fieldName + "));"; - else if (width == 32) - return ATHENA_DNA_WRITER ".writeUint32" + funcPrefix + "(atUint32(" + fieldName + "));"; - else if (width == 64) - return ATHENA_DNA_WRITER ".writeUint64" + funcPrefix + "(atUint64(" + fieldName + "));"; - } - else if (bType->isSignedInteger()) - { - if (width == 8) - return ATHENA_DNA_WRITER ".writeByte(atInt8(" + fieldName + "));"; - else if (width == 16) - return ATHENA_DNA_WRITER ".writeInt16" + funcPrefix + "(atInt16(" + fieldName + "));"; - else if (width == 32) - return ATHENA_DNA_WRITER ".writeInt32" + funcPrefix + "(atInt32(" + fieldName + "));"; - else if (width == 64) - return ATHENA_DNA_WRITER ".writeInt64" + funcPrefix + "(atInt64(" + fieldName + "));"; - } - } - else if (theType->isBuiltinType()) - { - const clang::BuiltinType* bType = (clang::BuiltinType*)theType; - if (bType->isBooleanType()) - { - return ATHENA_DNA_WRITER ".writeBool(" + fieldName + ");"; - } - else if (bType->isUnsignedInteger()) - { - if (width == 8) - return ATHENA_DNA_WRITER ".writeUByte(" + fieldName + ");"; - else if (width == 16) - return ATHENA_DNA_WRITER ".writeUint16" + funcPrefix + "(" + fieldName + ");"; - else if (width == 32) - return ATHENA_DNA_WRITER ".writeUint32" + funcPrefix + "(" + fieldName + ");"; - else if (width == 64) - return ATHENA_DNA_WRITER ".writeUint64" + funcPrefix + "(" + fieldName + ");"; - } - else if (bType->isSignedInteger()) - { - if (width == 8) - return ATHENA_DNA_WRITER ".writeByte(" + fieldName + ");"; - else if (width == 16) - return ATHENA_DNA_WRITER ".writeInt16" + funcPrefix + "(" + fieldName + ");"; - else if (width == 32) - return ATHENA_DNA_WRITER ".writeInt32" + funcPrefix + "(" + fieldName + ");"; - else if (width == 64) - return ATHENA_DNA_WRITER ".writeInt64" + funcPrefix + "(" + fieldName + ");"; - } - else if (bType->isFloatingPoint()) - { - if (width == 32) - return ATHENA_DNA_WRITER ".writeFloat" + funcPrefix + "(" + fieldName + ");"; - else if (width == 64) - return ATHENA_DNA_WRITER ".writeDouble" + funcPrefix + "(" + fieldName + ");"; - } - } - 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) - { - if (width == 32) - return ATHENA_DNA_WRITER ".writeVec2f" + funcPrefix + "(" + fieldName + ");"; - else if (width == 64) - return ATHENA_DNA_WRITER ".writeVec2d" + funcPrefix + "(" + fieldName + ");"; - } - else if (vType->getNumElements() == 3) - { - if (width == 32) - return ATHENA_DNA_WRITER ".writeVec3f" + funcPrefix + "(" + fieldName + ");"; - else if (width == 64) - return ATHENA_DNA_WRITER ".writeVec3d" + funcPrefix + "(" + fieldName + ");"; - } - else if (vType->getNumElements() == 4) - { - if (width == 32) - return ATHENA_DNA_WRITER ".writeVec4f" + funcPrefix + "(" + fieldName + ");"; - else if (width == 64) - return ATHENA_DNA_WRITER ".writeVec4d" + funcPrefix + "(" + fieldName + ");"; - } - } - } - } - std::string baseDNA; - bool isYAML = false; - if (isDNARecord(rDecl, baseDNA, isYAML)) - { - isDNATypeOut = true; - return "write(" ATHENA_DNA_WRITER ");"; - } - } - } - else - { - if (theType->isEnumeralType()) - { - clang::EnumType* eType = (clang::EnumType*)theType; - clang::EnumDecl* eDecl = eType->getDecl(); - theType = eDecl->getIntegerType().getCanonicalType().getTypePtr(); - std::string qName = eDecl->getQualifiedNameAsString(); - - const clang::BuiltinType* bType = (clang::BuiltinType*)theType; - if (bType->isBooleanType()) - { - return qName + "(" ATHENA_DNA_READER ".readBool())"; - } - else if (bType->isUnsignedInteger()) - { - if (width == 8) - return qName + "(" ATHENA_DNA_READER ".readUByte())"; - else if (width == 16) - return qName + "(" ATHENA_DNA_READER ".readUint16" + funcPrefix + "())"; - else if (width == 32) - return qName + "(" ATHENA_DNA_READER ".readUint32" + funcPrefix + "())"; - else if (width == 64) - return qName + "(" ATHENA_DNA_READER ".readUint64" + funcPrefix + "())"; - } - else if (bType->isSignedInteger()) - { - if (width == 8) - return qName + "(" ATHENA_DNA_READER ".readByte()"; - else if (width == 16) - return qName + "(" ATHENA_DNA_READER ".readInt16" + funcPrefix + "())"; - else if (width == 32) - return qName + "(" ATHENA_DNA_READER ".readInt32" + funcPrefix + "())"; - else if (width == 64) - return qName + "(" ATHENA_DNA_READER ".readInt64" + funcPrefix + "())"; - } - } - else if (theType->isBuiltinType()) - { - const clang::BuiltinType* bType = (clang::BuiltinType*)theType; - if (bType->isBooleanType()) - { - return ATHENA_DNA_READER ".readBool()"; - } - else if (bType->isUnsignedInteger()) - { - if (width == 8) - return ATHENA_DNA_READER ".readUByte()"; - else if (width == 16) - return ATHENA_DNA_READER ".readUint16" + funcPrefix + "()"; - else if (width == 32) - return ATHENA_DNA_READER ".readUint32" + funcPrefix + "()"; - else if (width == 64) - return ATHENA_DNA_READER ".readUint64" + funcPrefix + "()"; - } - else if (bType->isSignedInteger()) - { - if (width == 8) - return ATHENA_DNA_READER ".readByte()"; - else if (width == 16) - return ATHENA_DNA_READER ".readInt16" + funcPrefix + "()"; - else if (width == 32) - return ATHENA_DNA_READER ".readInt32" + funcPrefix + "()"; - else if (width == 64) - return ATHENA_DNA_READER ".readInt64" + funcPrefix + "()"; - } - else if (bType->isFloatingPoint()) - { - if (width == 32) - return ATHENA_DNA_READER ".readFloat" + funcPrefix + "()"; - else if (width == 64) - return ATHENA_DNA_READER ".readDouble" + funcPrefix + "()"; - } - } - 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) - { - if (width == 32) - return ATHENA_DNA_READER ".readVec2f" + funcPrefix + "()"; - else if (width == 64) - return ATHENA_DNA_READER ".readVec2d" + funcPrefix + "()"; - } - else if (vType->getNumElements() == 3) - { - if (width == 32) - return ATHENA_DNA_READER ".readVec3f" + funcPrefix + "()"; - else if (width == 64) - return ATHENA_DNA_READER ".readVec3d" + funcPrefix + "()"; - } - else if (vType->getNumElements() == 4) - { - if (width == 32) - return ATHENA_DNA_READER ".readVec4f" + funcPrefix + "()"; - else if (width == 64) - return ATHENA_DNA_READER ".readVec4d" + funcPrefix + "()"; - } - } - } - } - std::string baseDNA; - bool isYAML = false; - if (isDNARecord(rDecl, baseDNA, isYAML)) - { - isDNATypeOut = true; - return "read(" ATHENA_DNA_READER ");"; - } - } - } - return std::string(); - } - - std::string GetYAMLString(const clang::Type* theType, unsigned width, - const std::string& fieldName, const std::string& bareFieldName, - bool writerPass, bool& isDNATypeOut) - { - isDNATypeOut = false; - if (writerPass) - { - 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 ATHENA_YAML_WRITER ".writeBool(\"" + bareFieldName + "\", bool(" + fieldName + "));"; - } - else if (bType->isUnsignedInteger()) - { - if (width == 8) - return ATHENA_YAML_WRITER ".writeUByte(\"" + bareFieldName + "\", atUint8(" + fieldName + "));"; - else if (width == 16) - return ATHENA_YAML_WRITER ".writeUint16(\"" + bareFieldName + "\", atUint16(" + fieldName + "));"; - else if (width == 32) - return ATHENA_YAML_WRITER ".writeUint32(\"" + bareFieldName + "\", atUint32(" + fieldName + "));"; - else if (width == 64) - return ATHENA_YAML_WRITER ".writeUint64(\"" + bareFieldName + "\", atUint64(" + fieldName + "));"; - } - else if (bType->isSignedInteger()) - { - if (width == 8) - return ATHENA_YAML_WRITER ".writeByte(\"" + bareFieldName + "\", atInt8(" + fieldName + "));"; - else if (width == 16) - return ATHENA_YAML_WRITER ".writeInt16(\"" + bareFieldName + "\", atInt16(" + fieldName + "));"; - else if (width == 32) - return ATHENA_YAML_WRITER ".writeInt32(\"" + bareFieldName + "\", atInt32(" + fieldName + "));"; - else if (width == 64) - return ATHENA_YAML_WRITER ".writeInt64(\"" + bareFieldName + "\", atInt64(" + fieldName + "));"; - } - } - else if (theType->isBuiltinType()) - { - const clang::BuiltinType* bType = (clang::BuiltinType*)theType; - if (bType->isBooleanType()) - { - return ATHENA_YAML_WRITER ".writeBool(\"" + bareFieldName + "\", " + fieldName + ");"; - } - else if (bType->isUnsignedInteger()) - { - if (width == 8) - return ATHENA_YAML_WRITER ".writeUByte(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 16) - return ATHENA_YAML_WRITER ".writeUint16(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 32) - return ATHENA_YAML_WRITER ".writeUint32(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 64) - return ATHENA_YAML_WRITER ".writeUint64(\"" + bareFieldName + "\", " + fieldName + ");"; - } - else if (bType->isSignedInteger()) - { - if (width == 8) - return ATHENA_YAML_WRITER ".writeByte(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 16) - return ATHENA_YAML_WRITER ".writeInt16(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 32) - return ATHENA_YAML_WRITER ".writeInt32(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 64) - return ATHENA_YAML_WRITER ".writeInt64(\"" + bareFieldName + "\", " + fieldName + ");"; - } - else if (bType->isFloatingPoint()) - { - if (width == 32) - return ATHENA_YAML_WRITER ".writeFloat(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 64) - return ATHENA_YAML_WRITER ".writeDouble(\"" + bareFieldName + "\", " + fieldName + ");"; - } - } - 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) - { - if (width == 32) - return ATHENA_YAML_WRITER ".writeVec2f(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 64) - return ATHENA_YAML_WRITER ".writeVec2d(\"" + bareFieldName + "\", " + fieldName + ");"; - } - else if (vType->getNumElements() == 3) - { - if (width == 32) - return ATHENA_YAML_WRITER ".writeVec3f(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 64) - return ATHENA_YAML_WRITER ".writeVec3d(\"" + bareFieldName + "\", " + fieldName + ");"; - } - else if (vType->getNumElements() == 4) - { - if (width == 32) - return ATHENA_YAML_WRITER ".writeVec4f(\"" + bareFieldName + "\", " + fieldName + ");"; - else if (width == 64) - return ATHENA_YAML_WRITER ".writeVec4d(\"" + bareFieldName + "\", " + fieldName + ");"; - } - } - } - } - std::string baseDNA; - bool isYAML = false; - if (isDNARecord(rDecl, baseDNA, isYAML)) - { - isDNATypeOut = true; - return "write(" ATHENA_YAML_WRITER ");"; - } - } - } - else - { - if (theType->isEnumeralType()) - { - clang::EnumType* eType = (clang::EnumType*)theType; - clang::EnumDecl* eDecl = eType->getDecl(); - theType = eDecl->getIntegerType().getCanonicalType().getTypePtr(); - std::string qName = eDecl->getQualifiedNameAsString(); - - const clang::BuiltinType* bType = (clang::BuiltinType*)theType; - if (bType->isBooleanType()) - { - return qName + "(" ATHENA_YAML_READER ".readBool(\"" + bareFieldName + "\"))"; - } - else if (bType->isUnsignedInteger()) - { - if (width == 8) - return qName + "(" ATHENA_YAML_READER ".readUByte(\"" + bareFieldName + "\"))"; - else if (width == 16) - return qName + "(" ATHENA_YAML_READER ".readUint16(\"" + bareFieldName + "\"))"; - else if (width == 32) - return qName + "(" ATHENA_YAML_READER ".readUint32(\"" + bareFieldName + "\"))"; - else if (width == 64) - return qName + "(" ATHENA_YAML_READER ".readUint64(\"" + bareFieldName + "\"))"; - } - else if (bType->isSignedInteger()) - { - if (width == 8) - return qName + "(" ATHENA_YAML_READER ".readByte(\"" + bareFieldName + "\"))"; - else if (width == 16) - return qName + "(" ATHENA_YAML_READER ".readInt16(\"" + bareFieldName + "\"))"; - else if (width == 32) - return qName + "(" ATHENA_YAML_READER ".readInt32(\"" + bareFieldName + "\"))"; - else if (width == 64) - return qName + "(" ATHENA_YAML_READER ".readInt64(\"" + bareFieldName + "\"))"; - } - } - else if (theType->isBuiltinType()) - { - const clang::BuiltinType* bType = (clang::BuiltinType*)theType; - if (bType->isBooleanType()) - { - return ATHENA_YAML_READER ".readBool(\"" + bareFieldName + "\")"; - } - else if (bType->isUnsignedInteger()) - { - if (width == 8) - return ATHENA_YAML_READER ".readUByte(\"" + bareFieldName + "\")"; - else if (width == 16) - return ATHENA_YAML_READER ".readUint16(\"" + bareFieldName + "\")"; - else if (width == 32) - return ATHENA_YAML_READER ".readUint32(\"" + bareFieldName + "\")"; - else if (width == 64) - return ATHENA_YAML_READER ".readUint64(\"" + bareFieldName + "\")"; - } - else if (bType->isSignedInteger()) - { - if (width == 8) - return ATHENA_YAML_READER ".readByte(\"" + bareFieldName + "\")"; - else if (width == 16) - return ATHENA_YAML_READER ".readInt16(\"" + bareFieldName + "\")"; - else if (width == 32) - return ATHENA_YAML_READER ".readInt32(\"" + bareFieldName + "\")"; - else if (width == 64) - return ATHENA_YAML_READER ".readInt64(\"" + bareFieldName + "\")"; - } - else if (bType->isFloatingPoint()) - { - if (width == 32) - return ATHENA_YAML_READER ".readFloat(\"" + bareFieldName + "\")"; - else if (width == 64) - return ATHENA_YAML_READER ".readDouble(\"" + bareFieldName + "\")"; - } - } - 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) - { - if (width == 32) - return ATHENA_YAML_READER ".readVec2f(\"" + bareFieldName + "\")"; - else if (width == 64) - return ATHENA_YAML_READER ".readVec2d(\"" + bareFieldName + "\")"; - } - else if (vType->getNumElements() == 3) - { - if (width == 32) - return ATHENA_YAML_READER ".readVec3f(\"" + bareFieldName + "\")"; - else if (width == 64) - return ATHENA_YAML_READER ".readVec3d(\"" + bareFieldName + "\")"; - } - else if (vType->getNumElements() == 4) - { - if (width == 32) - return ATHENA_YAML_READER ".readVec4f(\"" + bareFieldName + "\")"; - else if (width == 64) - return ATHENA_YAML_READER ".readVec4d(\"" + bareFieldName + "\")"; - } - } - } - } - std::string baseDNA; - bool isYAML = false; - if (isDNARecord(rDecl, baseDNA, isYAML)) - { - isDNATypeOut = true; - return "read(" ATHENA_YAML_READER ");"; - } - } - } - return std::string(); - } -#endif - static std::string GetFieldString(const std::string& fieldName) { size_t underscorePos = fieldName.find('_'); @@ -710,12 +209,12 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor std::string propIdExpr = "\"" + fieldStr + "\""; for (clang::Attr* attr : field->attrs()) { - if (clang::AnnotateAttr* annot = clang::dyn_cast(attr)) + if (clang::AnnotateAttr* annot = clang::dyn_cast_or_null(attr)) { - llvm::StringRef text_ref = annot->getAnnotation(); - if (text_ref.startswith_lower("rcrc32=")) + llvm::StringRef textRef = annot->getAnnotation(); + if (textRef.startswith_lower("rcrc32=")) { - unsigned long num = strtoul(text_ref.data() + 7, nullptr, 16); + unsigned long num = strtoul(textRef.data() + 7, nullptr, 16); std::string tmpS; llvm::raw_string_ostream s(tmpS); s << llvm::format("\"%s\", 0x%08X", fieldStr.c_str(), num); @@ -730,333 +229,556 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor static std::string GetOpString(const std::string& fieldName, const std::string& propIdExpr, int64_t endianVal) { - return "Do({" + propIdExpr + "}, " + fieldName + ", s)"; + return "({" + propIdExpr + "}, " + fieldName + ", s)"; } static std::string GetOpString(const std::string& fieldName, const std::string& propIdExpr) { - return "Do({" + propIdExpr + "}, " + fieldName + ", s)"; + return "({" + propIdExpr + "}, " + fieldName + ", s)"; } static std::string GetVectorOpString(const std::string& fieldName, const std::string& propIdExpr, const std::string& sizeExpr, int64_t endianVal) { - return "Do({" + propIdExpr + "}, " + fieldName + ", " + sizeExpr + ", s)"; + return "({" + propIdExpr + "}, " + fieldName + ", " + sizeExpr + ", s)"; } static std::string GetVectorOpString(const std::string& fieldName, const std::string& propIdExpr, const std::string& sizeExpr) { - return "Do({" + propIdExpr + "}, " + fieldName + ", " + sizeExpr + ", s)"; + return "({" + propIdExpr + "}, " + fieldName + ", " + sizeExpr + ", s)"; + } + + static void RecurseNestedTypeName(const clang::DeclContext* decl, std::string& templateStmt, std::string& qualType) + { + if (!decl) + return; + RecurseNestedTypeName(decl->getParent(), templateStmt, qualType); + if (const clang::CXXRecordDecl* rec = clang::dyn_cast_or_null(decl)) + { + if (!qualType.empty()) + qualType += "::"; + qualType += rec->getName(); + if (const clang::ClassTemplateDecl* ct = rec->getDescribedClassTemplate()) + { + templateStmt += "template <"; + qualType += '<'; + bool needsComma = false; + for (const clang::NamedDecl* parm : *ct->getTemplateParameters()) + { + if (const clang::TemplateTypeParmDecl* tpParm = + clang::dyn_cast_or_null(parm)) + { + if (needsComma) + { + templateStmt += ", "; + qualType += ", "; + } + templateStmt += "class "s + tpParm->getName().data(); + qualType += tpParm->getName(); + needsComma = true; + } + else if (const clang::NonTypeTemplateParmDecl* nonTypeParm = + clang::dyn_cast_or_null(parm)) + { + if (needsComma) + { + templateStmt += ", "; + qualType += ", "; + } + templateStmt += nonTypeParm->getType().getAsString() + ' ' + nonTypeParm->getName().data(); + qualType += nonTypeParm->getName(); + needsComma = true; + } + } + templateStmt += ">\n"; + qualType += '>'; + } + } + else if (const clang::NamedDecl* namedDecl = clang::dyn_cast_or_null(decl)) + { + if (!qualType.empty()) + qualType += "::"; + qualType += namedDecl->getName(); + } + } + + static void GetNestedTypeName(const clang::DeclContext* decl, std::string& templateStmt, std::string& qualType) + { + templateStmt.clear(); + qualType.clear(); + RecurseNestedTypeName(decl, templateStmt, qualType); + } + + static void RecurseNestedTypeSpecializations(const clang::DeclContext* decl, + std::vector>& specializations) + { + if (!decl) + { + specializations.emplace_back(); + return; + } + + std::vector> parentSpecializations; + RecurseNestedTypeSpecializations(decl->getParent(), parentSpecializations); + bool foundSpecializations = false; + if (const clang::CXXRecordDecl* rec = clang::dyn_cast_or_null(decl)) + { + if (const clang::ClassTemplateDecl* ct = rec->getDescribedClassTemplate()) + { + int numParms = 0; + for (const clang::NamedDecl* parm : *ct->getTemplateParameters()) + if (clang::dyn_cast_or_null(parm) || + clang::dyn_cast_or_null(parm)) + ++numParms; + + for (clang::Attr* attr : rec->attrs()) + { + if (clang::AnnotateAttr* annot = clang::dyn_cast_or_null(attr)) + { + llvm::StringRef textRef = annot->getAnnotation(); + if (textRef.startswith_lower("specparms=")) + { + llvm::SmallVector specParms; + textRef.substr(10).split(specParms, ','); + int numTuples = int(specParms.size()) / numParms; + for (const auto& parent : parentSpecializations) + { + for (int i = 0; i < numTuples; ++i) + { + if (parent.first.empty()) + specializations.emplace_back(std::string(rec->getName().data()) + '<', 1); + else + specializations.emplace_back(parent.first + "::" + rec->getName().data() + '<', + parent.second + 1); + bool needsComma = false; + for (auto it = specParms.begin() + i * numParms; + it != specParms.end() && it != specParms.begin() + (i + 1) * numParms; ++it) + { + StringRef trimmed = it->trim(); + if (needsComma) + specializations.back().first += ", "; + specializations.back().first += trimmed; + needsComma = true; + } + specializations.back().first += ">"; + } + } + foundSpecializations = true; + break; + } + } + } + } + } + + if (!foundSpecializations) + for (const auto& parent : parentSpecializations) + { + if (const clang::NamedDecl* namedDecl = clang::dyn_cast_or_null(decl)) + { + if (parent.first.empty()) + specializations.emplace_back(namedDecl->getName().data(), parent.second); + else + specializations.emplace_back(parent.first + "::" + namedDecl->getName().data(), parent.second); + } + else + specializations.push_back(parent); + } + } + + static std::vector> + GetNestedTypeSpecializations(const clang::DeclContext* decl) + { + std::vector> ret; + RecurseNestedTypeSpecializations(decl, ret); + return ret; } void emitEnumerateFunc(clang::CXXRecordDecl* decl, const std::string& baseDNA) { + std::string templateStmt; + std::string qualTypeStr; + GetNestedTypeName(decl, templateStmt, qualTypeStr); + + fileOut << templateStmt; fileOut << "template \nvoid " << - decl->getQualifiedNameAsString() << "::Enumerate(typename Op::StreamT& s)\n{\n"; + qualTypeStr << "::Enumerate(typename Op::StreamT& s)\n{\n"; if (baseDNA.size()) fileOut << " " << baseDNA << "::Enumerate(s);\n"; + enum class NodeType + { + Do, + DoSeek, + DoAlign + }; + struct OutputNode + { + NodeType m_type = NodeType::Do; + std::string m_fieldName; + std::string m_ioOp; + bool m_squelched = false; + OutputNode(NodeType type, const std::string& fieldName, const std::string& ioOp, bool squelched) + : m_type(type), m_fieldName(fieldName), m_ioOp(ioOp), m_squelched(squelched) {} + }; + std::vector outputNodes; + for (const clang::FieldDecl* field : decl->fields()) { clang::QualType qualType = field->getType(); const clang::Type* regType = qualType.getTypePtrOrNull(); if (!regType || regType->getTypeClass() == clang::Type::TemplateTypeParm) continue; - clang::TypeInfo regTypeInfo = context.getTypeInfo(qualType); 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 ; egetName(); + std::string propIdExpr = GetPropIdExpr(field, fieldName); + + if (regType->getTypeClass() == clang::Type::TemplateSpecialization) { - std::string fieldName; - if (isArray) + const clang::TemplateSpecializationType* tsType = (const clang::TemplateSpecializationType*)regType; + const clang::TemplateDecl* tsDecl = tsType->getTemplateName().getAsTemplateDecl(); + const clang::TemplateParameterList* classParms = tsDecl->getTemplateParameters(); + + if (!tsDecl->getName().compare("Value")) { - char subscript[16]; - snprintf(subscript, 16, "[%d]", e); - fieldName = field->getName().str() + subscript; - } - else - fieldName = field->getName(); - - std::string propIdExpr = GetPropIdExpr(field, fieldName); - - if (regType->getTypeClass() == clang::Type::TemplateSpecialization) - { - const clang::TemplateSpecializationType* tsType = (const clang::TemplateSpecializationType*)regType; - const clang::TemplateDecl* tsDecl = tsType->getTemplateName().getAsTemplateDecl(); - const clang::TemplateParameterList* classParms = tsDecl->getTemplateParameters(); - - if (!tsDecl->getName().compare("Value")) + llvm::APSInt endian(64, -1); + const clang::Expr* endianExpr = nullptr; + bool defaultEndian = true; + if (classParms->size() >= 2) { - llvm::APSInt endian(64, -1); - const clang::Expr* endianExpr = nullptr; - if (classParms->size() >= 2) + const clang::NamedDecl* endianParm = classParms->getParam(1); + if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) { - const clang::NamedDecl* endianParm = classParms->getParam(1); - if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) + const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; + const clang::Expr* defArg = nttParm->getDefaultArgument(); + endianExpr = defArg; + if (!defArg->isIntegerConstantExpr(endian, context)) { - const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; - const clang::Expr* defArg = nttParm->getDefaultArgument(); - endianExpr = defArg; - if (!defArg->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); - continue; - } - } - } - - for (const clang::TemplateArgument& arg : *tsType) - { - if (arg.getKind() == clang::TemplateArgument::Expression) - { - const clang::Expr* expr = arg.getAsExpr(); - endianExpr = expr; - if (!expr->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); - continue; - } - } - } - - int64_t endianVal = endian.getSExtValue(); - if (endianVal != 0 && endianVal != 1) - { - if (endianExpr) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); + diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); + continue; } + } + } + + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Expression) + { + const clang::Expr* expr = arg.getAsExpr(); + endianExpr = expr; + defaultEndian = false; + if (!expr->isIntegerConstantExpr(endian, context)) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); + continue; + } + } + } + + int64_t endianVal = endian.getSExtValue(); + if (endianVal != 0 && endianVal != 1) + { + if (endianExpr) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); + } + else + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + } + continue; + } + + std::string ioOp; + bool isDNAType = false; + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Type) + { + if (defaultEndian) + ioOp = GetOpString(fieldName, propIdExpr); else - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - } - continue; - } - - clang::QualType templateType; - std::string ioOp; - bool isDNAType = false; - const clang::TemplateArgument* typeArg = nullptr; - for (const clang::TemplateArgument& arg : *tsType) - { - if (arg.getKind() == clang::TemplateArgument::Type) - { - typeArg = &arg; - templateType = arg.getAsType().getCanonicalType(); ioOp = GetOpString(fieldName, propIdExpr, endianVal); - } } - - if (ioOp.empty()) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Unable to use type '" + tsDecl->getName().str() + "' with Athena"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - continue; - } - - fileOut << " " << ioOp << ";\n"; } - else if (!tsDecl->getName().compare("Vector")) + + if (ioOp.empty()) { - llvm::APSInt endian(64, -1); - const clang::Expr* endianExpr = nullptr; - if (classParms->size() >= 3) - { - const clang::NamedDecl* endianParm = classParms->getParam(2); - if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) - { - const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; - const clang::Expr* defArg = nttParm->getDefaultArgument(); - endianExpr = defArg; - if (!defArg->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); - continue; - } - } - } - - std::string sizeExpr; - const clang::TemplateArgument* sizeArg = nullptr; - size_t idx = 0; - bool bad = false; - for (const clang::TemplateArgument& arg : *tsType) - { - if (arg.getKind() == clang::TemplateArgument::Expression) - { - const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts(); - if (idx == 1) - { - sizeArg = &arg; - const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr; - 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(); - llvm::raw_string_ostream strStream(sizeExpr); - argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy()); - } - } - else if (idx == 2) - { - endianExpr = expr; - if (!expr->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); - bad = true; - break; - } - } - } - ++idx; - } - if (bad) - continue; - - int64_t endianVal = endian.getSExtValue(); - if (endianVal != 0 && endianVal != 1) - { - if (endianExpr) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); - } - else - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - } - continue; - } - - clang::QualType templateType; - std::string ioOp; - bool isDNAType = false; - const clang::TemplateArgument* typeArg = nullptr; - for (const clang::TemplateArgument& arg : *tsType) - { - if (arg.getKind() == clang::TemplateArgument::Type) - { - typeArg = &arg; - templateType = arg.getAsType().getCanonicalType(); - ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExpr, endianVal); - } - } - - if (ioOp.empty()) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Unable to use type '" + templateType.getAsString() + "' with Athena"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - continue; - } - - if (sizeExpr.empty()) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Unable to use count variable with Athena"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - continue; - } - - fileOut << " " << ioOp << ";\n"; - + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Unable to use type '" + tsDecl->getName().str() + "' with Athena"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + continue; } - else if (!tsDecl->getName().compare("Buffer")) + + outputNodes.emplace_back(NodeType::Do, fieldName, ioOp, false); + } + else if (!tsDecl->getName().compare("Vector")) + { + llvm::APSInt endian(64, -1); + const clang::Expr* endianExpr = nullptr; + bool defaultEndian = true; + if (classParms->size() >= 3) { - const clang::Expr* sizeExpr = nullptr; - std::string sizeExprStr; - for (const clang::TemplateArgument& arg : *tsType) + const clang::NamedDecl* endianParm = classParms->getParam(2); + if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) { - if (arg.getKind() == clang::TemplateArgument::Expression) + const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; + const clang::Expr* defArg = nttParm->getDefaultArgument(); + endianExpr = defArg; + if (!defArg->isIntegerConstantExpr(endian, context)) { - const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)arg.getAsExpr()->IgnoreImpCasts(); + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); + continue; + } + } + } + + std::string sizeExpr; + size_t idx = 0; + bool bad = false; + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Expression) + { + const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts(); + if (idx == 1) + { + const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr; 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); + + if (argExpr->getStmtClass() == clang::Stmt::DeclRefExprClass) + { + clang::DeclRefExpr* drExpr = (clang::DeclRefExpr*)argExpr; + std::string testName = drExpr->getFoundDecl()->getNameAsString(); + for (auto i=outputNodes.rbegin() ; i != outputNodes.rend() ; ++i) + { + if (i->m_fieldName == testName) + { + i->m_squelched = true; + break; + } + } + } + llvm::raw_string_ostream strStream(sizeExpr); argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy()); } } - } - if (sizeExprStr.empty()) - { - if (sizeExpr) + else if (idx == 2) { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(sizeExpr->getLocStart(), AthenaError); - diag.AddString("Unable to use size variable with Athena"); - diag.AddSourceRange(clang::CharSourceRange(sizeExpr->getSourceRange(), true)); + defaultEndian = false; + endianExpr = expr; + if (!expr->isIntegerConstantExpr(endian, context)) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); + bad = true; + break; + } } - else - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Unable to use size variable with Athena"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - } - continue; } - - std::string ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr); - - fileOut << " " << ioOp << ";\n"; + ++idx; } - else if (!tsDecl->getName().compare("String")) + if (bad) + continue; + + int64_t endianVal = endian.getSExtValue(); + if (endianVal != 0 && endianVal != 1) { - const clang::Expr* sizeExpr = nullptr; - std::string sizeExprStr; - for (const clang::TemplateArgument& arg : *tsType) + if (endianExpr) { - if (arg.getKind() == clang::TemplateArgument::Expression) + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); + } + else + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + } + continue; + } + + clang::QualType templateType; + std::string ioOp; + bool isDNAType = false; + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Type) + { + templateType = arg.getAsType().getCanonicalType(); + if (defaultEndian) + ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExpr); + else + ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExpr, endianVal); + } + } + + if (ioOp.empty()) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Unable to use type '" + templateType.getAsString() + "' with Athena"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + continue; + } + + if (sizeExpr.empty()) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Unable to use count variable with Athena"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + continue; + } + + outputNodes.emplace_back(NodeType::Do, fieldName, ioOp, false); + } + 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()); + } + } + } + if (sizeExprStr.empty()) + { + if (sizeExpr) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(sizeExpr->getLocStart(), AthenaError); + diag.AddString("Unable to use size variable with Athena"); + diag.AddSourceRange(clang::CharSourceRange(sizeExpr->getSourceRange(), true)); + } + else + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Unable to use size variable with Athena"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + } + continue; + } + + std::string ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr); + + outputNodes.emplace_back(NodeType::Do, fieldName, ioOp, false); + } + else if (!tsDecl->getName().compare("String")) + { + 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(); + llvm::raw_string_ostream strStream(sizeExprStr); + argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy()); + } + else if (expr->isIntegerConstantExpr(sizeLiteral, context)) + { + sizeExprStr = sizeLiteral.toString(10); + } + } + } + + std::string ioOp; + if (!sizeExprStr.empty()) + ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr); + else + ioOp = GetOpString(fieldName, propIdExpr); + + outputNodes.emplace_back(NodeType::Do, fieldName, ioOp, false); + } + else if (!tsDecl->getName().compare("WString")) + { + llvm::APSInt endian(64, -1); + const clang::Expr* endianExpr = nullptr; + bool defaultEndian = true; + if (classParms->size() >= 2) + { + const clang::NamedDecl* endianParm = classParms->getParam(1); + if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) + { + const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; + const clang::Expr* defArg = nttParm->getDefaultArgument(); + endianExpr = defArg; + if (!defArg->isIntegerConstantExpr(endian, context)) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); + continue; + } + } + } + + std::string sizeExprStr; + size_t idx = 0; + bool bad = false; + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Expression) + { + const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts(); + if (idx == 0) { - const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts(); - const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr; 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()); } @@ -1065,228 +787,190 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor sizeExprStr = sizeLiteral.toString(10); } } - } - - std::string ioOp; - if (!sizeExprStr.empty()) - ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr); - else - ioOp = GetOpString(fieldName, propIdExpr); - - fileOut << " " << ioOp << ";\n"; - } - else if (!tsDecl->getName().compare("WString")) - { - llvm::APSInt endian(64, -1); - const clang::Expr* endianExpr = nullptr; - if (classParms->size() >= 2) - { - const clang::NamedDecl* endianParm = classParms->getParam(1); - if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) + else if (idx == 1) { - const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; - const clang::Expr* defArg = nttParm->getDefaultArgument(); - endianExpr = defArg; - if (!defArg->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); - continue; - } - } - } - - const clang::Expr* sizeExpr = nullptr; - std::string sizeExprStr; - size_t idx = 0; - bool bad = false; - 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); - } - } - else if (idx == 1) - { - endianExpr = expr; - if (!expr->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); - bad = true; - break; - } - } - } - ++idx; - } - if (bad) - continue; - - int64_t endianVal = endian.getSExtValue(); - if (endianVal != 0 && endianVal != 1) - { - if (endianExpr) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); - } - else - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - } - continue; - } - - std::string ioOp; - if (!sizeExprStr.empty()) - ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr, endianVal); - else - ioOp = GetOpString(fieldName, propIdExpr, endianVal); - - fileOut << " " << ioOp << ";\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; - 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)) - { - offsetExprStr = offsetLiteral.toString(10); - } - } - else - { - directionExpr = expr; - if (!expr->isIntegerConstantExpr(direction, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); - diag.AddString("Unable to use non-constant direction expression in Athena"); - diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); - bad = true; - break; - } - } - } - ++idx; - } - if (bad) - continue; - - int64_t directionVal = direction.getSExtValue(); - if (directionVal < 0 || directionVal > 2) - { - if (directionExpr) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(directionExpr->getLocStart(), AthenaError); - diag.AddString("Direction parameter must be 'Begin', 'Current', or 'End'"); - diag.AddSourceRange(clang::CharSourceRange(directionExpr->getSourceRange(), true)); - } - else - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Direction parameter must be 'Begin', 'Current', or 'End'"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - } - continue; - } - - if (directionVal == 0) - fileOut << " DoSeek(" << offsetExprStr << ", Begin, s);\n"; - else if (directionVal == 1) - fileOut << " DoSeek(" << offsetExprStr << ", Current, s);\n"; - else if (directionVal == 2) - fileOut << " DoSeek(" << offsetExprStr << ", End, s);\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)) + defaultEndian = false; + endianExpr = expr; + if (!expr->isIntegerConstantExpr(endian, context)) { clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); - diag.AddString("Unable to use non-constant align expression in Athena"); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); bad = true; break; } } } - if (bad) - continue; + ++idx; + } + if (bad) + continue; - int64_t alignVal = align.getSExtValue(); - if (alignVal) + int64_t endianVal = endian.getSExtValue(); + if (endianVal != 0 && endianVal != 1) + { + if (endianExpr) { - fileOut << " DoAlign(" << alignVal << ", s);\n"; + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); } + else + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + } + continue; } - } + std::string ioOp; + if (!sizeExprStr.empty()) + { + if (defaultEndian) + ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr); + else + ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr, endianVal); + } + else + { + if (defaultEndian) + ioOp = GetOpString(fieldName, propIdExpr); + else + ioOp = GetOpString(fieldName, propIdExpr, endianVal); + } - else if (regType->getTypeClass() == clang::Type::Record) + outputNodes.emplace_back(NodeType::Do, fieldName, ioOp, false); + } + else if (!tsDecl->getName().compare("Seek")) { - const clang::CXXRecordDecl* cxxRDecl = regType->getAsCXXRecordDecl(); - std::string baseDNA; - if (cxxRDecl && isDNARecord(cxxRDecl, baseDNA)) - fileOut << " " << GetOpString(fieldName, propIdExpr) << ";\n"; - } + size_t idx = 0; + std::string offsetExprStr; + llvm::APSInt direction(64, 0); + const clang::Expr* directionExpr = nullptr; + bool bad = false; + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Expression) + { + const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts(); + if (!idx) + { + 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(); + llvm::raw_string_ostream strStream(offsetExprStr); + argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy()); + } + else if (expr->isIntegerConstantExpr(offsetLiteral, context)) + { + offsetExprStr = offsetLiteral.toString(10); + } + } + else + { + directionExpr = expr; + if (!expr->isIntegerConstantExpr(direction, context)) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); + diag.AddString("Unable to use non-constant direction expression in Athena"); + diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); + bad = true; + break; + } + } + } + ++idx; + } + if (bad) + continue; + int64_t directionVal = direction.getSExtValue(); + if (directionVal < 0 || directionVal > 2) + { + if (directionExpr) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(directionExpr->getLocStart(), AthenaError); + diag.AddString("Direction parameter must be 'Begin', 'Current', or 'End'"); + diag.AddSourceRange(clang::CharSourceRange(directionExpr->getSourceRange(), true)); + } + else + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Direction parameter must be 'Begin', 'Current', or 'End'"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + } + continue; + } + + if (directionVal == 0) + outputNodes.emplace_back(NodeType::DoSeek, fieldName, "("s + offsetExprStr + ", athena::Begin, s)", false); + else if (directionVal == 1) + outputNodes.emplace_back(NodeType::DoSeek, fieldName, "("s + offsetExprStr + ", athena::Current, s)", false); + else if (directionVal == 2) + outputNodes.emplace_back(NodeType::DoSeek, fieldName, "("s + offsetExprStr + ", athena::End, s)", false); + } + 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)) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); + diag.AddString("Unable to use non-constant align expression in Athena"); + diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); + bad = true; + break; + } + } + } + if (bad) + continue; + + int64_t alignVal = align.getSExtValue(); + if (alignVal) + { + outputNodes.emplace_back(NodeType::DoAlign, fieldName, "("s + align.toString(10, true) + ", s)", false); + } + } } + else if (regType->getTypeClass() == clang::Type::Record) + { + const clang::CXXRecordDecl* cxxRDecl = regType->getAsCXXRecordDecl(); + std::string baseDNA; + if (cxxRDecl && isDNARecord(cxxRDecl, baseDNA)) + outputNodes.emplace_back(NodeType::Do, fieldName, GetOpString(fieldName, propIdExpr), false); + } + } + + for (const OutputNode& node : outputNodes) + { + switch (node.m_type) + { + case NodeType::Do: + if (node.m_squelched) + fileOut << " DoSize" << node.m_ioOp << ";\n"; + else + fileOut << " Do" << node.m_ioOp << ";\n"; + break; + case NodeType::DoSeek: + fileOut << " DoSeek" << node.m_ioOp << ";\n"; + break; + case NodeType::DoAlign: + fileOut << " DoAlign" << node.m_ioOp << ";\n"; + break; + } } fileOut << "}\n\n"; @@ -1294,8 +978,13 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor void emitLookupFunc(clang::CXXRecordDecl* decl, const std::string& baseDNA) { + std::string templateStmt; + std::string qualTypeStr; + GetNestedTypeName(decl, templateStmt, qualTypeStr); + + fileOut << templateStmt; fileOut << "template \nbool " << - decl->getQualifiedNameAsString() << "::Lookup(uint64_t hash, typename Op::StreamT& s)\n{\n"; + qualTypeStr << "::Lookup(uint64_t hash, typename Op::StreamT& s)\n{\n"; if (baseDNA.size()) fileOut << " if (" << baseDNA << "::Lookup(hash, s))\n" @@ -1310,306 +999,350 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor const clang::Type* regType = qualType.getTypePtrOrNull(); if (!regType || regType->getTypeClass() == clang::Type::TemplateTypeParm) continue; - clang::TypeInfo regTypeInfo = context.getTypeInfo(qualType); 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 ; egetName(); + std::string propIdExpr = GetPropIdExpr(field, fieldName); + + if (regType->getTypeClass() == clang::Type::TemplateSpecialization) { - std::string fieldName; - if (isArray) + const clang::TemplateSpecializationType* tsType = (const clang::TemplateSpecializationType*)regType; + const clang::TemplateDecl* tsDecl = tsType->getTemplateName().getAsTemplateDecl(); + const clang::TemplateParameterList* classParms = tsDecl->getTemplateParameters(); + + if (!tsDecl->getName().compare("Value")) { - char subscript[16]; - snprintf(subscript, 16, "[%d]", e); - fieldName = field->getName().str() + subscript; - } - else - fieldName = field->getName(); - - std::string propIdExpr = GetPropIdExpr(field, fieldName); - - if (regType->getTypeClass() == clang::Type::TemplateSpecialization) - { - const clang::TemplateSpecializationType* tsType = (const clang::TemplateSpecializationType*)regType; - const clang::TemplateDecl* tsDecl = tsType->getTemplateName().getAsTemplateDecl(); - const clang::TemplateParameterList* classParms = tsDecl->getTemplateParameters(); - - if (!tsDecl->getName().compare("Value")) + llvm::APSInt endian(64, -1); + const clang::Expr* endianExpr = nullptr; + bool defaultEndian = true; + if (classParms->size() >= 2) { - llvm::APSInt endian(64, -1); - const clang::Expr* endianExpr = nullptr; - if (classParms->size() >= 2) + const clang::NamedDecl* endianParm = classParms->getParam(1); + if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) { - const clang::NamedDecl* endianParm = classParms->getParam(1); - if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) + const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; + const clang::Expr* defArg = nttParm->getDefaultArgument(); + endianExpr = defArg; + if (!defArg->isIntegerConstantExpr(endian, context)) { - const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; - const clang::Expr* defArg = nttParm->getDefaultArgument(); - endianExpr = defArg; - if (!defArg->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); - continue; - } - } - } - - for (const clang::TemplateArgument& arg : *tsType) - { - if (arg.getKind() == clang::TemplateArgument::Expression) - { - const clang::Expr* expr = arg.getAsExpr(); - endianExpr = expr; - if (!expr->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); - continue; - } - } - } - - int64_t endianVal = endian.getSExtValue(); - if (endianVal != 0 && endianVal != 1) - { - if (endianExpr) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); + diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); + continue; } + } + } + + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Expression) + { + const clang::Expr* expr = arg.getAsExpr(); + endianExpr = expr; + defaultEndian = false; + if (!expr->isIntegerConstantExpr(endian, context)) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); + continue; + } + } + } + + int64_t endianVal = endian.getSExtValue(); + if (endianVal != 0 && endianVal != 1) + { + if (endianExpr) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); + } + else + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + } + continue; + } + + std::string ioOp; + bool isDNAType = false; + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Type) + { + if (defaultEndian) + ioOp = GetOpString(fieldName, propIdExpr); else - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - } - continue; - } - - clang::QualType templateType; - std::string ioOp; - bool isDNAType = false; - const clang::TemplateArgument* typeArg = nullptr; - for (const clang::TemplateArgument& arg : *tsType) - { - if (arg.getKind() == clang::TemplateArgument::Type) - { - typeArg = &arg; - templateType = arg.getAsType().getCanonicalType(); ioOp = GetOpString(fieldName, propIdExpr, endianVal); - } } - - if (ioOp.empty()) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Unable to use type '" + tsDecl->getName().str() + "' with Athena"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - continue; - } - - fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" - << " " << ioOp << ";\n" - << " return true;\n"; - } - else if (!tsDecl->getName().compare("Vector")) + + if (ioOp.empty()) { - llvm::APSInt endian(64, -1); - const clang::Expr* endianExpr = nullptr; - if (classParms->size() >= 3) - { - const clang::NamedDecl* endianParm = classParms->getParam(2); - if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) - { - const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; - const clang::Expr* defArg = nttParm->getDefaultArgument(); - endianExpr = defArg; - if (!defArg->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); - continue; - } - } - } - - std::string sizeExpr; - const clang::TemplateArgument* sizeArg = nullptr; - size_t idx = 0; - bool bad = false; - for (const clang::TemplateArgument& arg : *tsType) - { - if (arg.getKind() == clang::TemplateArgument::Expression) - { - const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts(); - if (idx == 1) - { - sizeArg = &arg; - const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr; - 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(); - llvm::raw_string_ostream strStream(sizeExpr); - argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy()); - } - } - else if (idx == 2) - { - endianExpr = expr; - if (!expr->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); - bad = true; - break; - } - } - } - ++idx; - } - if (bad) - continue; - - int64_t endianVal = endian.getSExtValue(); - if (endianVal != 0 && endianVal != 1) - { - if (endianExpr) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); - } - else - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - } - continue; - } - - clang::QualType templateType; - std::string ioOp; - bool isDNAType = false; - const clang::TemplateArgument* typeArg = nullptr; - for (const clang::TemplateArgument& arg : *tsType) - { - if (arg.getKind() == clang::TemplateArgument::Type) - { - typeArg = &arg; - templateType = arg.getAsType().getCanonicalType(); - ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExpr, endianVal); - } - } - - if (ioOp.empty()) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Unable to use type '" + templateType.getAsString() + "' with Athena"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - continue; - } - - if (sizeExpr.empty()) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Unable to use count variable with Athena"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - continue; - } - - fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" - << " " << ioOp << ";\n" - << " return true;\n"; + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Unable to use type '" + tsDecl->getName().str() + "' with Athena"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + continue; } - else if (!tsDecl->getName().compare("Buffer")) + + fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" + << " Do" << ioOp << ";\n" + << " return true;\n"; + + } + else if (!tsDecl->getName().compare("Vector")) + { + llvm::APSInt endian(64, -1); + const clang::Expr* endianExpr = nullptr; + bool defaultEndian = true; + if (classParms->size() >= 3) { - const clang::Expr* sizeExpr = nullptr; - std::string sizeExprStr; - for (const clang::TemplateArgument& arg : *tsType) + const clang::NamedDecl* endianParm = classParms->getParam(2); + if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) { - if (arg.getKind() == clang::TemplateArgument::Expression) + const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; + const clang::Expr* defArg = nttParm->getDefaultArgument(); + endianExpr = defArg; + if (!defArg->isIntegerConstantExpr(endian, context)) { - const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)arg.getAsExpr()->IgnoreImpCasts(); + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); + continue; + } + } + } + + std::string sizeExpr; + size_t idx = 0; + bool bad = false; + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Expression) + { + const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts(); + if (idx == 1) + { + const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr; 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); + llvm::raw_string_ostream strStream(sizeExpr); argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy()); } } - } - if (sizeExprStr.empty()) - { - if (sizeExpr) + else if (idx == 2) { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(sizeExpr->getLocStart(), AthenaError); - diag.AddString("Unable to use size variable with Athena"); - diag.AddSourceRange(clang::CharSourceRange(sizeExpr->getSourceRange(), true)); + endianExpr = expr; + defaultEndian = false; + if (!expr->isIntegerConstantExpr(endian, context)) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); + bad = true; + break; + } } - else - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Unable to use size variable with Athena"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - } - continue; } - - std::string ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr); - - fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" - << " " << ioOp << ";\n" - << " return true;\n"; + ++idx; } - else if (!tsDecl->getName().compare("String")) + if (bad) + continue; + + int64_t endianVal = endian.getSExtValue(); + if (endianVal != 0 && endianVal != 1) { - const clang::Expr* sizeExpr = nullptr; - std::string sizeExprStr; - for (const clang::TemplateArgument& arg : *tsType) + if (endianExpr) { - if (arg.getKind() == clang::TemplateArgument::Expression) + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); + } + else + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + } + continue; + } + + clang::QualType templateType; + std::string ioOp; + bool isDNAType = false; + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Type) + { + templateType = arg.getAsType().getCanonicalType(); + if (defaultEndian) + ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExpr); + else + ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExpr, endianVal); + } + } + + if (ioOp.empty()) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Unable to use type '" + templateType.getAsString() + "' with Athena"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + continue; + } + + if (sizeExpr.empty()) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Unable to use count variable with Athena"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + continue; + } + + fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" + << " Do" << ioOp << ";\n" + << " return true;\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()); + } + } + } + if (sizeExprStr.empty()) + { + if (sizeExpr) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(sizeExpr->getLocStart(), AthenaError); + diag.AddString("Unable to use size variable with Athena"); + diag.AddSourceRange(clang::CharSourceRange(sizeExpr->getSourceRange(), true)); + } + else + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Unable to use size variable with Athena"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + } + continue; + } + + std::string ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr); + + fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" + << " Do" << ioOp << ";\n" + << " return true;\n"; + } + else if (!tsDecl->getName().compare("String")) + { + 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(); + llvm::raw_string_ostream strStream(sizeExprStr); + argExpr->printPretty(strStream, nullptr, context.getPrintingPolicy()); + } + else if (expr->isIntegerConstantExpr(sizeLiteral, context)) + { + sizeExprStr = sizeLiteral.toString(10); + } + } + } + + std::string ioOp; + if (!sizeExprStr.empty()) + ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr); + else + ioOp = GetOpString(fieldName, propIdExpr); + + fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" + << " Do" << ioOp << ";\n" + << " return true;\n"; + } + else if (!tsDecl->getName().compare("WString")) + { + llvm::APSInt endian(64, -1); + const clang::Expr* endianExpr = nullptr; + bool defaultEndian = true; + if (classParms->size() >= 2) + { + const clang::NamedDecl* endianParm = classParms->getParam(1); + if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) + { + const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; + const clang::Expr* defArg = nttParm->getDefaultArgument(); + endianExpr = defArg; + if (!defArg->isIntegerConstantExpr(endian, context)) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); + continue; + } + } + } + + std::string sizeExprStr; + size_t idx = 0; + bool bad = false; + for (const clang::TemplateArgument& arg : *tsType) + { + if (arg.getKind() == clang::TemplateArgument::Expression) + { + const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts(); + if (idx == 0) { - const clang::Expr* expr = arg.getAsExpr()->IgnoreImpCasts(); - const clang::UnaryExprOrTypeTraitExpr* uExpr = (clang::UnaryExprOrTypeTraitExpr*)expr; 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()); } @@ -1618,130 +1351,76 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor sizeExprStr = sizeLiteral.toString(10); } } + else if (idx == 1) + { + endianExpr = expr; + defaultEndian = false; + if (!expr->isIntegerConstantExpr(endian, context)) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); + bad = true; + break; + } + } } + ++idx; + } + if (bad) + continue; - std::string ioOp; - if (!sizeExprStr.empty()) + int64_t endianVal = endian.getSExtValue(); + if (endianVal != 0 && endianVal != 1) + { + if (endianExpr) + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); + } + else + { + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + } + continue; + } + + std::string ioOp; + if (!sizeExprStr.empty()) + { + if (defaultEndian) ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr); else - ioOp = GetOpString(fieldName, propIdExpr); - - fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" - << " " << ioOp << ";\n" - << " return true;\n"; - } - else if (!tsDecl->getName().compare("WString")) - { - llvm::APSInt endian(64, -1); - const clang::Expr* endianExpr = nullptr; - if (classParms->size() >= 2) - { - const clang::NamedDecl* endianParm = classParms->getParam(1); - if (endianParm->getKind() == clang::Decl::NonTypeTemplateParm) - { - const clang::NonTypeTemplateParmDecl* nttParm = (clang::NonTypeTemplateParmDecl*)endianParm; - const clang::Expr* defArg = nttParm->getDefaultArgument(); - endianExpr = defArg; - if (!defArg->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(defArg->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(defArg->getSourceRange(), true)); - continue; - } - } - } - - const clang::Expr* sizeExpr = nullptr; - std::string sizeExprStr; - size_t idx = 0; - bool bad = false; - 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); - } - } - else if (idx == 1) - { - endianExpr = expr; - if (!expr->isIntegerConstantExpr(endian, context)) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(expr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(expr->getSourceRange(), true)); - bad = true; - break; - } - } - } - ++idx; - } - if (bad) - continue; - - int64_t endianVal = endian.getSExtValue(); - if (endianVal != 0 && endianVal != 1) - { - if (endianExpr) - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(endianExpr->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(endianExpr->getSourceRange(), true)); - } - else - { - clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); - diag.AddString("Endian value must be 'BigEndian' or 'LittleEndian'"); - diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); - } - continue; - } - - std::string ioOp; - if (!sizeExprStr.empty()) ioOp = GetVectorOpString(fieldName, propIdExpr, sizeExprStr, endianVal); + } + else + { + if (defaultEndian) + ioOp = GetOpString(fieldName, propIdExpr); else ioOp = GetOpString(fieldName, propIdExpr, endianVal); - - fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" - << " " << ioOp << ";\n" - << " return true;\n"; } - } - else if (regType->getTypeClass() == clang::Type::Record) - { - const clang::CXXRecordDecl* cxxRDecl = regType->getAsCXXRecordDecl(); - std::string baseDNA; - if (cxxRDecl && isDNARecord(cxxRDecl, baseDNA)) - { - fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" - << " " << GetOpString(fieldName, propIdExpr) << ";\n" - << " return true;\n"; - } + fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" + << " Do" << ioOp << ";\n" + << " return true;\n"; } - } + else if (regType->getTypeClass() == clang::Type::Record) + { + const clang::CXXRecordDecl* cxxRDecl = regType->getAsCXXRecordDecl(); + std::string baseDNA; + if (cxxRDecl && isDNARecord(cxxRDecl, baseDNA)) + { + fileOut << " AT_PROP_CASE(" << propIdExpr << "):\n" + << " Do" << GetOpString(fieldName, propIdExpr) << ";\n" + << " return true;\n"; + } + } } fileOut << " default:\n return false;\n }\n}\n\n"; @@ -1767,6 +1446,28 @@ public: if (!isDNARecord(decl, baseDNA)) return true; + /* Determine if is is a YAML DNA */ + bool isYamlDNA = false; + for (const clang::CXXMethodDecl* method : decl->methods()) + if (method->getDeclName().isIdentifier() && + (!method->getName().compare(llvm::StringLiteral("read")) || + !method->getName().compare(llvm::StringLiteral("write"))) && method->getNumParams() == 1 && + method->getParamDecl(0)->getType().getAsString() == "athena::io::YAMLDocReader &") + { + isYamlDNA = true; + break; + } + + /* Determine if this is a regular DNA or PropDNA */ + bool isPropDNA = false; + for (const clang::Decl* d : decl->decls()) + if (const clang::FunctionTemplateDecl* m = clang::dyn_cast_or_null(d)) + if (!m->getName().compare(llvm::StringLiteral("Lookup"))) + { + isPropDNA = true; + break; + } + /* Make sure there isn't Delete meta type */ for (const clang::FieldDecl* field : decl->fields()) { @@ -1791,9 +1492,35 @@ public: } } + std::vector> specializations = GetNestedTypeSpecializations(decl); + emitEnumerateFunc(decl, baseDNA); - emitLookupFunc(decl, baseDNA); - fileOut << "AT_SPECIALIZE_DNA(" << decl->getQualifiedNameAsString() << ")\n\n"; + if (isPropDNA) + { + emitLookupFunc(decl, baseDNA); + for (const auto& specialization : specializations) + fileOut << "AT_SPECIALIZE_PROPDNA(" << specialization.first << ")\n"; + } + else if (isYamlDNA) + { + for (const auto& specialization : specializations) + fileOut << "AT_SPECIALIZE_DNA_YAML(" << specialization.first << ")\n"; + } + else + { + for (const auto& specialization : specializations) + fileOut << "AT_SPECIALIZE_DNA(" << specialization.first << ")\n"; + } + fileOut << "\n\n"; + + for (const auto& specialization : specializations) + { + for (int i = 0; i < specialization.second; ++i) + fileOut << "template <>\n"; + fileOut << "const char* " << specialization.first << + "::DNAType()\n{\n return \"" << specialization.first << "\";\n}\n"; + } + fileOut << "\n\n"; return true; } diff --git a/atdna/test.cpp b/atdna/test.cpp index c60faf6..64b768b 100644 --- a/atdna/test.cpp +++ b/atdna/test.cpp @@ -5,7 +5,7 @@ int main(int argc, const char** argv) { - TESTFile file = {}; + TESTFile file = {}; file.arrCount[0] = 2; file.array.push_back(42); file.array.push_back(64); diff --git a/atdna/test.hpp b/atdna/test.hpp index e32708c..7cbe8b6 100644 --- a/atdna/test.hpp +++ b/atdna/test.hpp @@ -3,26 +3,29 @@ using namespace athena; typedef io::DNA BigDNA; -struct TESTSubFile : public BigDNA +enum ETest : atUint8 +{ + ZERO, + ONE, + TWO, + THREE +}; + +template +struct AT_SPECIALIZE_PARMS(ETest::ZERO, ETest::ONE, ETest::TWO, ETest::THREE) +TESTSubFile : public BigDNA { AT_DECL_DNA - enum ETest : atUint8 - { - ZERO, - ONE, - TWO, - THREE - }; - Value varE; + Value varE = EVal; Value sub1; Value sub2; }; -struct TESTSubClassFile : public TESTSubFile +struct TESTSubClassFile : public TESTSubFile { AT_DECL_DNA Value sub3; - Value sub4; + Value sub4; }; struct TESTSubSubClassFile : public TESTSubClassFile @@ -32,11 +35,13 @@ struct TESTSubSubClassFile : public TESTSubClassFile Value sub6; }; -struct TESTFile : public BigDNA +template +struct AT_SPECIALIZE_PARMS(atUint16, 42, atUint32, 87, atUint32, 2) +TESTFile : public BigDNA { AT_DECL_DNA Value varBool; - AT_OVERRIDE_RCRC32(12345678) Value x4_var32; + AT_OVERRIDE_RCRC32(12345678) Value x4_var32 = Var32Val; AT_OVERRIDE_RCRC32(deadbabe) Value x8_var16; Value vec3; Value vec4; @@ -48,25 +53,32 @@ struct TESTFile : public BigDNA Value nestSub2; } nestedSubFile; - using TESTSubFileUsing = TESTSubFile; + using TESTSubFileUsing = TESTSubFile; TESTSubFileUsing subFile; Align<4> align; - struct TESTExplicitSubFile : public BigDNA + template + struct AT_SPECIALIZE_PARMS(atInt32, 36, atInt64, 96) + TESTTemplateSubFile : public BigDNA { AT_DECL_DNA - Value explSub1; - Value explSub2; - } explSubFile; + Value explSub1 = NestedVal; + Value explSub2 = Var32Val; + }; + TESTTemplateSubFile nestedTemplate1; + TESTTemplateSubFile nestedTemplate2; Value arrCount[2]; Vector array; + Value arrAltCount; + Vector arrayAlt; + Seek<21, Current> seek; Value arrCount2; - Vector array2; + Vector, DNA_COUNT(arrCount[1] + arrCount2)> array2; Value bufSz; Buffer buf; diff --git a/include/athena/DNA.hpp b/include/athena/DNA.hpp index b57110b..b166c4a 100644 --- a/include/athena/DNA.hpp +++ b/include/athena/DNA.hpp @@ -94,6 +94,51 @@ struct DNA * @brief Meta Template preventing atdna from emitting read/write implementations */ struct Delete {}; + + /* Bring fundamental operations into DNA subclasses for easier per-op overrides */ + using Read = athena::io::Read; + using Write = athena::io::Write; + using BinarySize = athena::io::BinarySize; + using PropCount = athena::io::PropCount; + using ReadYaml = athena::io::ReadYaml; + using WriteYaml = athena::io::WriteYaml; +}; + +/** + * @brief Virtual DNA wrapper for subclasses that utilize virtual method calls + * @tparam DNAE Default-endianness for contained DNA values + * + * Typically, static template-based DNA resolution is sufficient; however, formats + * with a tree of variously-typed data structures would benefit from having a vtable. + * + * Note: It's not recommended to implement these directly. Instead, use the AT_DECL_DNA or + * AT_DECL_EXPLCIT_DNA macro in the subclasses. Specializing the Enumerate method + * is the proper way to override individual I/O operations. Owners of the virtualized + * subclass will typically use a unique_ptr to reference the data; specializing their own + * Enumerate methods as such: + * + * template <> void MySubclass::Enumerate(typename Read::StreamT& r) + * { (Do stuff with `r`) } + */ +template +struct DNAV : DNA +{ + virtual ~DNAV() = default; + virtual void read(athena::io::IStreamReader& r) = 0; + virtual void write(athena::io::IStreamWriter& w) const = 0; + virtual void binarySize(size_t& s) const = 0; + virtual const char* DNATypeV() const = 0; +}; + +template +struct DNAVYaml : DNAV +{ + virtual ~DNAVYaml() = default; + virtual void read(athena::io::IStreamReader& r) = 0; + virtual void write(athena::io::IStreamWriter& w) const = 0; + virtual void binarySize(size_t& s) const = 0; + virtual void read(athena::io::YAMLDocReader& r) = 0; + virtual void write(athena::io::YAMLDocWriter& w) const = 0; }; /** Macro to supply count variable to atdna and mute it for other compilers */ diff --git a/include/athena/DNAOp.hpp b/include/athena/DNAOp.hpp index 23fa2ef..f60e924 100644 --- a/include/athena/DNAOp.hpp +++ b/include/athena/DNAOp.hpp @@ -3,7 +3,8 @@ #include "IStreamReader.hpp" #include "IStreamWriter.hpp" -#include "DNAYaml.hpp" +#include "YAMLDocReader.hpp" +#include "YAMLDocWriter.hpp" #include "ChecksumsLiterals.hpp" namespace athena::io @@ -50,6 +51,12 @@ constexpr PropId operator "" _propid(const char* s, size_t len) # define AT_OVERRIDE_RCRC32(rcrc32) #endif +#if defined(__atdna__) +# define AT_SPECIALIZE_PARMS(...) __attribute__((annotate("specparms=" #__VA_ARGS__))) +#else +# define AT_SPECIALIZE_PARMS(...) +#endif + enum class PropType { None, @@ -60,13 +67,49 @@ enum class PropType template static inline constexpr bool __IsPODType() { - return std::is_arithmetic::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value; + return std::is_arithmetic_v || + std::is_convertible_v || + std::is_convertible_v || + std::is_convertible_v || + std::is_convertible_v || + std::is_convertible_v || + std::is_convertible_v; +} + +template +static inline uint16_t __Read16(IStreamReader& r) +{ + return DNAE == Endian::Big ? r.readUint16Big() : r.readUint16Little(); +} + +template +static inline void __Write16(IStreamWriter& w, uint16_t v) +{ + DNAE == Endian::Big ? w.writeUint16Big(v) : w.writeUint16Little(v); +} + +template +static inline uint32_t __Read32(IStreamReader& r) +{ + return DNAE == Endian::Big ? r.readUint32Big() : r.readUint32Little(); +} + +template +static inline void __Write32(IStreamWriter& w, uint32_t v) +{ + DNAE == Endian::Big ? w.writeUint32Big(v) : w.writeUint32Little(v); +} + +template +static inline uint64_t __Read64(IStreamReader& r) +{ + return DNAE == Endian::Big ? r.readUint64Big() : r.readUint64Little(); +} + +template +static inline void __Write64(IStreamWriter& w, uint64_t v) +{ + DNAE == Endian::Big ? w.writeUint64Big(v) : w.writeUint64Little(v); } template @@ -98,30 +141,53 @@ struct BinarySize BinarySize::Do(id, var, s); } template - static typename std::enable_if_t && !__IsPODType()> + static typename std::enable_if_t<__IsDNARecord() && PropOp != PropType::None> Do(const PropId& id, T& var, StreamT& s) { - if (PropOp != PropType::None) - { - /* Accessed via Enumerate, header */ - s += 6; - var.template Enumerate>(s); - } - else - var.template Enumerate(s); + /* Accessed via Enumerate, header */ + s += 6; + var.template Enumerate>(s); } template - static void Do(const PropId& id, std::vector& vector, size_t count, StreamT& s) + static typename std::enable_if_t<__IsDNARecord() && PropOp == PropType::None> + Do(const PropId& id, T& var, StreamT& s) + { + var.template Enumerate>(s); + } + template + static typename std::enable_if_t> + Do(const PropId& id, T& var, StreamT& s) + { + for (auto& v : var) + BinarySize::Do, DNAE>(id, v, s); + } + template + static void DoSize(const PropId& id, T& var, StreamT& s) + { + BinarySize::Do(id, var, s); + } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& s) { for (T& v : vector) BinarySize::Do(id, v, s); } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& s) + { + /* libc++ specializes vector as a bitstream */ + s += vector.size(); + } static void Do(const PropId& id, std::unique_ptr& buf, size_t count, StreamT& s) { if (buf) s += count; } - static void Do(const PropId& id, std::string& str, StreamT& s) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& s) { s += str.size() + 1; } @@ -129,8 +195,9 @@ struct BinarySize { s += count; } - template - static void Do(const PropId& id, std::wstring& str, StreamT& s) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& s) { s += str.size() * 2 + 2; } @@ -158,40 +225,42 @@ struct BinarySize s = (s + amount-1) / amount * amount; } }; -template <> template <> inline void BinarySize::Do(const PropId& id, bool& var, BinarySize::StreamT& s) { s += 1; } -template <> template <> inline void BinarySize::Do(const PropId& id, atInt8& var, BinarySize::StreamT& s) { s += 1; } -template <> template <> inline void BinarySize::Do(const PropId& id, atUint8& var, BinarySize::StreamT& s) { s += 1; } -template <> template <> inline void BinarySize::Do(const PropId& id, atInt16& var, BinarySize::StreamT& s) { s += 2; } -template <> template <> inline void BinarySize::Do(const PropId& id, atUint16& var, BinarySize::StreamT& s) { s += 2; } -template <> template <> inline void BinarySize::Do(const PropId& id, atInt32& var, BinarySize::StreamT& s) { s += 4; } -template <> template <> inline void BinarySize::Do(const PropId& id, atUint32& var, BinarySize::StreamT& s) { s += 4; } -template <> template <> inline void BinarySize::Do(const PropId& id, atInt64& var, BinarySize::StreamT& s) { s += 8; } -template <> template <> inline void BinarySize::Do(const PropId& id, atUint64& var, BinarySize::StreamT& s) { s += 8; } -template <> template <> inline void BinarySize::Do(const PropId& id, float& var, BinarySize::StreamT& s) { s += 4; } -template <> template <> inline void BinarySize::Do(const PropId& id, double& var, BinarySize::StreamT& s) { s += 8; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec2f& var, BinarySize::StreamT& s) { s += 8; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec2d& var, BinarySize::StreamT& s) { s += 16; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec3f& var, BinarySize::StreamT& s) { s += 12; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec3d& var, BinarySize::StreamT& s) { s += 24; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec4f& var, BinarySize::StreamT& s) { s += 16; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec4d& var, BinarySize::StreamT& s) { s += 32; } -template <> template <> inline void BinarySize::Do(const PropId& id, bool& var, BinarySize::StreamT& s) { s += 1; } -template <> template <> inline void BinarySize::Do(const PropId& id, atInt8& var, BinarySize::StreamT& s) { s += 1; } -template <> template <> inline void BinarySize::Do(const PropId& id, atUint8& var, BinarySize::StreamT& s) { s += 1; } -template <> template <> inline void BinarySize::Do(const PropId& id, atInt16& var, BinarySize::StreamT& s) { s += 2; } -template <> template <> inline void BinarySize::Do(const PropId& id, atUint16& var, BinarySize::StreamT& s) { s += 2; } -template <> template <> inline void BinarySize::Do(const PropId& id, atInt32& var, BinarySize::StreamT& s) { s += 4; } -template <> template <> inline void BinarySize::Do(const PropId& id, atUint32& var, BinarySize::StreamT& s) { s += 4; } -template <> template <> inline void BinarySize::Do(const PropId& id, atInt64& var, BinarySize::StreamT& s) { s += 8; } -template <> template <> inline void BinarySize::Do(const PropId& id, atUint64& var, BinarySize::StreamT& s) { s += 8; } -template <> template <> inline void BinarySize::Do(const PropId& id, float& var, BinarySize::StreamT& s) { s += 4; } -template <> template <> inline void BinarySize::Do(const PropId& id, double& var, BinarySize::StreamT& s) { s += 8; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec2f& var, BinarySize::StreamT& s) { s += 8; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec2d& var, BinarySize::StreamT& s) { s += 16; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec3f& var, BinarySize::StreamT& s) { s += 12; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec3d& var, BinarySize::StreamT& s) { s += 24; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec4f& var, BinarySize::StreamT& s) { s += 16; } -template <> template <> inline void BinarySize::Do(const PropId& id, atVec4d& var, BinarySize::StreamT& s) { s += 32; } +#define __BINARY_SIZE_S(type, endian) template <> template <> inline void BinarySize::Do \ + (const PropId& id, type& var, BinarySize::StreamT& s) +__BINARY_SIZE_S(bool, Endian::Big) { s += 1; } +__BINARY_SIZE_S(atInt8, Endian::Big) { s += 1; } +__BINARY_SIZE_S(atUint8, Endian::Big) { s += 1; } +__BINARY_SIZE_S(atInt16, Endian::Big) { s += 2; } +__BINARY_SIZE_S(atUint16, Endian::Big) { s += 2; } +__BINARY_SIZE_S(atInt32, Endian::Big) { s += 4; } +__BINARY_SIZE_S(atUint32, Endian::Big) { s += 4; } +__BINARY_SIZE_S(atInt64, Endian::Big) { s += 8; } +__BINARY_SIZE_S(atUint64, Endian::Big) { s += 8; } +__BINARY_SIZE_S(float, Endian::Big) { s += 4; } +__BINARY_SIZE_S(double, Endian::Big) { s += 8; } +__BINARY_SIZE_S(atVec2f, Endian::Big) { s += 8; } +__BINARY_SIZE_S(atVec2d, Endian::Big) { s += 16; } +__BINARY_SIZE_S(atVec3f, Endian::Big) { s += 12; } +__BINARY_SIZE_S(atVec3d, Endian::Big) { s += 24; } +__BINARY_SIZE_S(atVec4f, Endian::Big) { s += 16; } +__BINARY_SIZE_S(atVec4d, Endian::Big) { s += 32; } +__BINARY_SIZE_S(bool, Endian::Little) { s += 1; } +__BINARY_SIZE_S(atInt8, Endian::Little) { s += 1; } +__BINARY_SIZE_S(atUint8, Endian::Little) { s += 1; } +__BINARY_SIZE_S(atInt16, Endian::Little) { s += 2; } +__BINARY_SIZE_S(atUint16, Endian::Little) { s += 2; } +__BINARY_SIZE_S(atInt32, Endian::Little) { s += 4; } +__BINARY_SIZE_S(atUint32, Endian::Little) { s += 4; } +__BINARY_SIZE_S(atInt64, Endian::Little) { s += 8; } +__BINARY_SIZE_S(atUint64, Endian::Little) { s += 8; } +__BINARY_SIZE_S(float, Endian::Little) { s += 4; } +__BINARY_SIZE_S(double, Endian::Little) { s += 8; } +__BINARY_SIZE_S(atVec2f, Endian::Little) { s += 8; } +__BINARY_SIZE_S(atVec2d, Endian::Little) { s += 16; } +__BINARY_SIZE_S(atVec3f, Endian::Little) { s += 12; } +__BINARY_SIZE_S(atVec3d, Endian::Little) { s += 24; } +__BINARY_SIZE_S(atVec4f, Endian::Little) { s += 16; } +__BINARY_SIZE_S(atVec4d, Endian::Little) { s += 32; } template struct PropCount @@ -205,7 +274,12 @@ struct PropCount s += 1; } template - static void Do(const PropId& id, std::vector& vector, size_t count, StreamT& s) + static void DoSize(const PropId& id, T& var, StreamT& s) + { + PropCount::Do(id, var, s); + } + template + static void Do(const PropId& id, std::vector& vector, const S& count, StreamT& s) { /* Only reports one level of properties */ s += 1; @@ -215,7 +289,9 @@ struct PropCount /* Only reports one level of properties */ s += 1; } - static void Do(const PropId& id, std::string& str, StreamT& s) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& s) { /* Only reports one level of properties */ s += 1; @@ -225,8 +301,9 @@ struct PropCount /* Only reports one level of properties */ s += 1; } - template - static void Do(const PropId& id, std::wstring& str, StreamT& s) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& s) { /* Only reports one level of properties */ s += 1; @@ -260,33 +337,47 @@ struct Read Read::Do(id, var, r); } template - static typename std::enable_if_t && !__IsPODType()> + static typename std::enable_if_t<__IsDNARecord() && PropOp == PropType::None> Do(const PropId& id, T& var, StreamT& r) { - if (PropOp != PropType::None) - { - /* Accessed via Lookup, no header */ - atUint16 propCount = T::DNAEndian == Endian::Big ? r.readUint16Big() : r.readUint16Little(); - for (atUint32 i = 0; i < propCount; ++i) - { - atUint64 hash; - if (PropOp == PropType::CRC64) - hash = T::DNAEndian == Endian::Big ? r.readUint64Big() : r.readUint64Little(); - else - hash = T::DNAEndian == Endian::Big ? r.readUint32Big() : r.readUint32Little(); - atInt64 size = T::DNAEndian == Endian::Big ? r.readUint16Big() : r.readUint16Little(); - atInt64 start = r.position(); - var.template Lookup>(hash, r); - atInt64 actualRead = r.position() - start; - if (actualRead != size) - r.seek(size - actualRead); - } - } - else - var.template Enumerate>(r); + var.template Enumerate>(r); } template - static void Do(const PropId& id, std::vector& vector, size_t count, StreamT& r) + static typename std::enable_if_t<__IsDNARecord() && PropOp != PropType::None> + Do(const PropId& id, T& var, StreamT& r) + { + /* Accessed via Lookup, no header */ + atUint16 propCount = __Read16(r); + for (atUint32 i = 0; i < propCount; ++i) + { + atUint64 hash; + if (PropOp == PropType::CRC64) + hash = __Read64(r); + else + hash = __Read32(r); + atInt64 size = __Read16(r); + atInt64 start = r.position(); + var.template Lookup>(hash, r); + atInt64 actualRead = r.position() - start; + if (actualRead != size) + r.seek(size - actualRead); + } + } + template + static typename std::enable_if_t> + Do(const PropId& id, T& var, StreamT& s) + { + for (auto& v : var) + Read::Do, DNAE>(id, v, s); + } + template + static void DoSize(const PropId& id, T& var, StreamT& s) + { + Read::Do(id, var, s); + } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& r) { vector.clear(); vector.reserve(count); @@ -296,12 +387,24 @@ struct Read Read::Do(id, vector.back(), r); } } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& r) + { + /* libc++ specializes vector as a bitstream */ + vector.clear(); + vector.reserve(count); + for (size_t i = 0; i < count; ++i) + vector.push_back(r.readBool()); + } static void Do(const PropId& id, std::unique_ptr& buf, size_t count, StreamT& r) { buf.reset(new atUint8[count]); r.readUBytesToBuf(buf.get(), count); } - static void Do(const PropId& id, std::string& str, StreamT& r) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& r) { str = r.readString(); } @@ -309,8 +412,9 @@ struct Read { str = r.readString(count); } - template - static void Do(const PropId& id, std::wstring& str, StreamT& r) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& r) { Read::Do(id, str, r); } @@ -328,44 +432,50 @@ struct Read r.seek((r.position() + amount-1) / amount * amount, athena::Begin); } }; -template <> template <> inline void Read::Do(const PropId& id, bool& var, Read::StreamT& r) { var = r.readBool(); } -template <> template <> inline void Read::Do(const PropId& id, atInt8& var, Read::StreamT& r) { var = r.readByte(); } -template <> template <> inline void Read::Do(const PropId& id, atUint8& var, Read::StreamT& r) { var = r.readUByte(); } -template <> template <> inline void Read::Do(const PropId& id, atInt16& var, Read::StreamT& r) { var = r.readInt16Big(); } -template <> template <> inline void Read::Do(const PropId& id, atUint16& var, Read::StreamT& r) { var = r.readUint16Big(); } -template <> template <> inline void Read::Do(const PropId& id, atInt32& var, Read::StreamT& r) { var = r.readInt32Big(); } -template <> template <> inline void Read::Do(const PropId& id, atUint32& var, Read::StreamT& r) { var = r.readUint32Big(); } -template <> template <> inline void Read::Do(const PropId& id, atInt64& var, Read::StreamT& r) { var = r.readInt64Big(); } -template <> template <> inline void Read::Do(const PropId& id, atUint64& var, Read::StreamT& r) { var = r.readUint64Big(); } -template <> template <> inline void Read::Do(const PropId& id, float& var, Read::StreamT& r) { var = r.readFloatBig(); } -template <> template <> inline void Read::Do(const PropId& id, double& var, Read::StreamT& r) { var = r.readDoubleBig(); } -template <> template <> inline void Read::Do(const PropId& id, atVec2f& var, Read::StreamT& r) { var = r.readVec2fBig(); } -template <> template <> inline void Read::Do(const PropId& id, atVec2d& var, Read::StreamT& r) { var = r.readVec2dBig(); } -template <> template <> inline void Read::Do(const PropId& id, atVec3f& var, Read::StreamT& r) { var = r.readVec3fBig(); } -template <> template <> inline void Read::Do(const PropId& id, atVec3d& var, Read::StreamT& r) { var = r.readVec3dBig(); } -template <> template <> inline void Read::Do(const PropId& id, atVec4f& var, Read::StreamT& r) { var = r.readVec4fBig(); } -template <> template <> inline void Read::Do(const PropId& id, atVec4d& var, Read::StreamT& r) { var = r.readVec4dBig(); } -template <> template <> inline void Read::Do(const PropId& id, std::wstring& str, StreamT& r) { str = r.readWStringBig(); } -template <> template <> inline void Read::Do(const PropId& id, std::wstring& str, size_t count, StreamT& r) { str = r.readWStringBig(count); } -template <> template <> inline void Read::Do(const PropId& id, bool& var, Read::StreamT& r) { var = r.readBool(); } -template <> template <> inline void Read::Do(const PropId& id, atInt8& var, Read::StreamT& r) { var = r.readByte(); } -template <> template <> inline void Read::Do(const PropId& id, atUint8& var, Read::StreamT& r) { var = r.readUByte(); } -template <> template <> inline void Read::Do(const PropId& id, atInt16& var, Read::StreamT& r) { var = r.readInt16Little(); } -template <> template <> inline void Read::Do(const PropId& id, atUint16& var, Read::StreamT& r) { var = r.readUint16Little(); } -template <> template <> inline void Read::Do(const PropId& id, atInt32& var, Read::StreamT& r) { var = r.readInt32Little(); } -template <> template <> inline void Read::Do(const PropId& id, atUint32& var, Read::StreamT& r) { var = r.readUint32Little(); } -template <> template <> inline void Read::Do(const PropId& id, atInt64& var, Read::StreamT& r) { var = r.readInt64Little(); } -template <> template <> inline void Read::Do(const PropId& id, atUint64& var, Read::StreamT& r) { var = r.readUint64Little(); } -template <> template <> inline void Read::Do(const PropId& id, float& var, Read::StreamT& r) { var = r.readFloatLittle(); } -template <> template <> inline void Read::Do(const PropId& id, double& var, Read::StreamT& r) { var = r.readDoubleLittle(); } -template <> template <> inline void Read::Do(const PropId& id, atVec2f& var, Read::StreamT& r) { var = r.readVec2fLittle(); } -template <> template <> inline void Read::Do(const PropId& id, atVec2d& var, Read::StreamT& r) { var = r.readVec2dLittle(); } -template <> template <> inline void Read::Do(const PropId& id, atVec3f& var, Read::StreamT& r) { var = r.readVec3fLittle(); } -template <> template <> inline void Read::Do(const PropId& id, atVec3d& var, Read::StreamT& r) { var = r.readVec3dLittle(); } -template <> template <> inline void Read::Do(const PropId& id, atVec4f& var, Read::StreamT& r) { var = r.readVec4fLittle(); } -template <> template <> inline void Read::Do(const PropId& id, atVec4d& var, Read::StreamT& r) { var = r.readVec4dLittle(); } -template <> template <> inline void Read::Do(const PropId& id, std::wstring& str, StreamT& r) { str = r.readWStringLittle(); } -template <> template <> inline void Read::Do(const PropId& id, std::wstring& str, size_t count, StreamT& r) { str = r.readWStringLittle(count); } +#define __READ_S(type, endian) template <> template <> inline void Read::Do \ + (const PropId& id, type& var, Read::StreamT& r) +#define __READ_WSTR_S(endian) template <> template <> inline void Read::Do \ + (const PropId& id, std::wstring& str, Read::StreamT& r) +#define __READ_WSTRC_S(endian) template <> template <> inline void Read::Do \ + (const PropId& id, std::wstring& str, size_t count, Read::StreamT& r) +__READ_S(bool, Endian::Big) { var = r.readBool(); } +__READ_S(atInt8, Endian::Big) { var = r.readByte(); } +__READ_S(atUint8, Endian::Big) { var = r.readUByte(); } +__READ_S(atInt16, Endian::Big) { var = r.readInt16Big(); } +__READ_S(atUint16, Endian::Big) { var = r.readUint16Big(); } +__READ_S(atInt32, Endian::Big) { var = r.readInt32Big(); } +__READ_S(atUint32, Endian::Big) { var = r.readUint32Big(); } +__READ_S(atInt64, Endian::Big) { var = r.readInt64Big(); } +__READ_S(atUint64, Endian::Big) { var = r.readUint64Big(); } +__READ_S(float, Endian::Big) { var = r.readFloatBig(); } +__READ_S(double, Endian::Big) { var = r.readDoubleBig(); } +__READ_S(atVec2f, Endian::Big) { var = r.readVec2fBig(); } +__READ_S(atVec2d, Endian::Big) { var = r.readVec2dBig(); } +__READ_S(atVec3f, Endian::Big) { var = r.readVec3fBig(); } +__READ_S(atVec3d, Endian::Big) { var = r.readVec3dBig(); } +__READ_S(atVec4f, Endian::Big) { var = r.readVec4fBig(); } +__READ_S(atVec4d, Endian::Big) { var = r.readVec4dBig(); } +__READ_WSTR_S(Endian::Big) { str = r.readWStringBig(); } +__READ_WSTRC_S(Endian::Big) { str = r.readWStringBig(count); } +__READ_S(bool, Endian::Little) { var = r.readBool(); } +__READ_S(atInt8, Endian::Little) { var = r.readByte(); } +__READ_S(atUint8, Endian::Little) { var = r.readUByte(); } +__READ_S(atInt16, Endian::Little) { var = r.readInt16Little(); } +__READ_S(atUint16, Endian::Little) { var = r.readUint16Little(); } +__READ_S(atInt32, Endian::Little) { var = r.readInt32Little(); } +__READ_S(atUint32, Endian::Little) { var = r.readUint32Little(); } +__READ_S(atInt64, Endian::Little) { var = r.readInt64Little(); } +__READ_S(atUint64, Endian::Little) { var = r.readUint64Little(); } +__READ_S(float, Endian::Little) { var = r.readFloatLittle(); } +__READ_S(double, Endian::Little) { var = r.readDoubleLittle(); } +__READ_S(atVec2f, Endian::Little) { var = r.readVec2fLittle(); } +__READ_S(atVec2d, Endian::Little) { var = r.readVec2dLittle(); } +__READ_S(atVec3f, Endian::Little) { var = r.readVec3fLittle(); } +__READ_S(atVec3d, Endian::Little) { var = r.readVec3dLittle(); } +__READ_S(atVec4f, Endian::Little) { var = r.readVec4fLittle(); } +__READ_S(atVec4d, Endian::Little) { var = r.readVec4dLittle(); } +__READ_WSTR_S(Endian::Little) { str = r.readWStringLittle(); } +__READ_WSTRC_S(Endian::Little) { str = r.readWStringLittle(count); } template struct Write @@ -380,9 +490,9 @@ struct Write { /* Accessed via Enumerate, header */ if (PropOp == PropType::CRC64) - DNAE == Endian::Big ? w.writeUint64Big(id.crc64) : w.writeUint64Little(id.crc64); + __Write64(w, id.crc64); else - DNAE == Endian::Big ? w.writeUint32Big(id.rcrc32) : w.writeUint32Little(id.rcrc32); + __Write32(w, id.rcrc32); size_t binarySize = 0; BinarySize::Do(id, var, binarySize); DNAE == Endian::Big ? w.writeUint16Big(atUint16(binarySize)) : w.writeUint16Little(atUint16(binarySize)); @@ -398,50 +508,74 @@ struct Write { /* Accessed via Enumerate, header */ if (PropOp == PropType::CRC64) - DNAE == Endian::Big ? w.writeUint64Big(id.crc64) : w.writeUint64Little(id.crc64); + __Write64(w, id.crc64); else - DNAE == Endian::Big ? w.writeUint32Big(id.rcrc32) : w.writeUint32Little(id.rcrc32); + __Write32(w, id.rcrc32); size_t binarySize = 0; BinarySize::Do(id, var, binarySize); - DNAE == Endian::Big ? w.writeUint16Big(atUint16(binarySize)) : w.writeUint16Little(atUint16(binarySize)); + __Write16(w, atUint16(binarySize)); } Write::Do(id, var, w); } template - static typename std::enable_if_t && !__IsPODType()> + static typename std::enable_if_t<__IsDNARecord() && PropOp != PropType::None> Do(const PropId& id, T& var, StreamT& w) { - if (PropOp != PropType::None) - { - /* Accessed via Enumerate, header */ - if (PropOp == PropType::CRC64) - T::DNAEndian == Endian::Big ? w.writeUint64Big(id.crc64) : w.writeUint64Little(id.crc64); - else - T::DNAEndian == Endian::Big ? w.writeUint32Big(id.rcrc32) : w.writeUint32Little(id.rcrc32); - size_t binarySize = 0; - var.template Enumerate>(binarySize); - T::DNAEndian == Endian::Big ? w.writeUint16Big(atUint16(binarySize)) : w.writeUint16Little(atUint16(binarySize)); - - size_t propCount = 0; - var.template Enumerate>(propCount); - T::DNAEndian == Endian::Big ? w.writeUint16Big(atUint16(propCount)) : w.writeUint16Little(atUint16(propCount)); - var.template Enumerate>(w); - } + /* Accessed via Enumerate, header */ + if (PropOp == PropType::CRC64) + __Write64(w, id.crc64); else - var.template Enumerate>(w); + __Write32(w, id.rcrc32); + size_t binarySize = 0; + var.template Enumerate>(binarySize); + __Write16(w, atUint16(binarySize)); + + size_t propCount = 0; + var.template Enumerate>(propCount); + __Write16(w, atUint16(propCount)); + var.template Enumerate>(w); } template - static void Do(const PropId& id, std::vector& vector, size_t count, StreamT& w) + static typename std::enable_if_t<__IsDNARecord() && PropOp == PropType::None> + Do(const PropId& id, T& var, StreamT& w) + { + var.template Enumerate>(w); + } + template + static typename std::enable_if_t> + Do(const PropId& id, T& var, StreamT& s) + { + for (auto& v : var) + Write::Do, DNAE>(id, v, s); + } + template + static void DoSize(const PropId& id, T& var, StreamT& s) + { + Write::Do(id, var, s); + } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& w) { for (T& v : vector) Write::Do(id, v, w); } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& w) + { + /* libc++ specializes vector as a bitstream */ + for (const T& v : vector) + w.writeBool(v); + } static void Do(const PropId& id, std::unique_ptr& buf, size_t count, StreamT& w) { if (buf) w.writeUBytes(buf.get(), count); } - static void Do(const PropId& id, std::string& str, StreamT& w) + template + static typename std::enable_if_t> + Do(const PropId& id, std::string& str, StreamT& w) { w.writeString(str); } @@ -449,8 +583,9 @@ struct Write { w.writeString(str, count); } - template - static void Do(const PropId& id, std::wstring& str, StreamT& w) + template + static typename std::enable_if_t> + Do(const PropId& id, std::wstring& str, StreamT& w) { Write::Do(id, str, w); } @@ -468,44 +603,50 @@ struct Write w.writeZeroTo((w.position() + amount-1) / amount * amount); } }; -template <> template <> inline void Write::Do(const PropId& id, bool& var, Write::StreamT& w) { w.writeBool(var); } -template <> template <> inline void Write::Do(const PropId& id, atInt8& var, Write::StreamT& w) { w.writeByte(var); } -template <> template <> inline void Write::Do(const PropId& id, atUint8& var, Write::StreamT& w) { w.writeUByte(var); } -template <> template <> inline void Write::Do(const PropId& id, atInt16& var, Write::StreamT& w) { w.writeInt16Big(var); } -template <> template <> inline void Write::Do(const PropId& id, atUint16& var, Write::StreamT& w) { w.writeUint16Big(var); } -template <> template <> inline void Write::Do(const PropId& id, atInt32& var, Write::StreamT& w) { w.writeInt32Big(var); } -template <> template <> inline void Write::Do(const PropId& id, atUint32& var, Write::StreamT& w) { w.writeUint32Big(var); } -template <> template <> inline void Write::Do(const PropId& id, atInt64& var, Write::StreamT& w) { w.writeInt64Big(var); } -template <> template <> inline void Write::Do(const PropId& id, atUint64& var, Write::StreamT& w) { w.writeUint64Big(var); } -template <> template <> inline void Write::Do(const PropId& id, float& var, Write::StreamT& w) { w.writeFloatBig(var); } -template <> template <> inline void Write::Do(const PropId& id, double& var, Write::StreamT& w) { w.writeDoubleBig(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec2f& var, Write::StreamT& w) { w.writeVec2fBig(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec2d& var, Write::StreamT& w) { w.writeVec2dBig(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec3f& var, Write::StreamT& w) { w.writeVec3fBig(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec3d& var, Write::StreamT& w) { w.writeVec3dBig(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec4f& var, Write::StreamT& w) { w.writeVec4fBig(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec4d& var, Write::StreamT& w) { w.writeVec4dBig(var); } -template <> template <> inline void Write::Do(const PropId& id, std::wstring& str, StreamT& w) { w.writeWStringBig(str); } -template <> template <> inline void Write::Do(const PropId& id, std::wstring& str, size_t count, StreamT& w) { w.writeWStringBig(str, count); } -template <> template <> inline void Write::Do(const PropId& id, bool& var, Write::StreamT& w) { w.writeBool(var); } -template <> template <> inline void Write::Do(const PropId& id, atInt8& var, Write::StreamT& w) { w.writeByte(var); } -template <> template <> inline void Write::Do(const PropId& id, atUint8& var, Write::StreamT& w) { w.writeUByte(var); } -template <> template <> inline void Write::Do(const PropId& id, atInt16& var, Write::StreamT& w) { w.writeInt16Little(var); } -template <> template <> inline void Write::Do(const PropId& id, atUint16& var, Write::StreamT& w) { w.writeUint16Little(var); } -template <> template <> inline void Write::Do(const PropId& id, atInt32& var, Write::StreamT& w) { w.writeInt32Little(var); } -template <> template <> inline void Write::Do(const PropId& id, atUint32& var, Write::StreamT& w) { w.writeUint32Little(var); } -template <> template <> inline void Write::Do(const PropId& id, atInt64& var, Write::StreamT& w) { w.writeInt64Little(var); } -template <> template <> inline void Write::Do(const PropId& id, atUint64& var, Write::StreamT& w) { w.writeUint64Little(var); } -template <> template <> inline void Write::Do(const PropId& id, float& var, Write::StreamT& w) { w.writeFloatLittle(var); } -template <> template <> inline void Write::Do(const PropId& id, double& var, Write::StreamT& w) { w.writeDoubleLittle(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec2f& var, Write::StreamT& w) { w.writeVec2fLittle(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec2d& var, Write::StreamT& w) { w.writeVec2dLittle(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec3f& var, Write::StreamT& w) { w.writeVec3fLittle(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec3d& var, Write::StreamT& w) { w.writeVec3dLittle(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec4f& var, Write::StreamT& w) { w.writeVec4fLittle(var); } -template <> template <> inline void Write::Do(const PropId& id, atVec4d& var, Write::StreamT& w) { w.writeVec4dLittle(var); } -template <> template <> inline void Write::Do(const PropId& id, std::wstring& str, StreamT& w) { w.writeWStringLittle(str); } -template <> template <> inline void Write::Do(const PropId& id, std::wstring& str, size_t count, StreamT& w) { w.writeWStringLittle(str, count); } +#define __WRITE_S(type, endian) template <> template <> inline void Write::Do \ + (const PropId& id, type& var, Write::StreamT& w) +#define __WRITE_WSTR_S(endian) template <> template <> inline void Write::Do \ + (const PropId& id, std::wstring& str, Write::StreamT& w) +#define __WRITE_WSTRC_S(endian) template <> template <> inline void Write::Do \ + (const PropId& id, std::wstring& str, size_t count, Write::StreamT& w) +__WRITE_S(bool, Endian::Big) { w.writeBool(var); } +__WRITE_S(atInt8, Endian::Big) { w.writeByte(var); } +__WRITE_S(atUint8, Endian::Big) { w.writeUByte(var); } +__WRITE_S(atInt16, Endian::Big) { w.writeInt16Big(var); } +__WRITE_S(atUint16, Endian::Big) { w.writeUint16Big(var); } +__WRITE_S(atInt32, Endian::Big) { w.writeInt32Big(var); } +__WRITE_S(atUint32, Endian::Big) { w.writeUint32Big(var); } +__WRITE_S(atInt64, Endian::Big) { w.writeInt64Big(var); } +__WRITE_S(atUint64, Endian::Big) { w.writeUint64Big(var); } +__WRITE_S(float, Endian::Big) { w.writeFloatBig(var); } +__WRITE_S(double, Endian::Big) { w.writeDoubleBig(var); } +__WRITE_S(atVec2f, Endian::Big) { w.writeVec2fBig(var); } +__WRITE_S(atVec2d, Endian::Big) { w.writeVec2dBig(var); } +__WRITE_S(atVec3f, Endian::Big) { w.writeVec3fBig(var); } +__WRITE_S(atVec3d, Endian::Big) { w.writeVec3dBig(var); } +__WRITE_S(atVec4f, Endian::Big) { w.writeVec4fBig(var); } +__WRITE_S(atVec4d, Endian::Big) { w.writeVec4dBig(var); } +__WRITE_WSTR_S(Endian::Big) { w.writeWStringBig(str); } +__WRITE_WSTRC_S(Endian::Big) { w.writeWStringBig(str, count); } +__WRITE_S(bool, Endian::Little) { w.writeBool(var); } +__WRITE_S(atInt8, Endian::Little) { w.writeByte(var); } +__WRITE_S(atUint8, Endian::Little) { w.writeUByte(var); } +__WRITE_S(atInt16, Endian::Little) { w.writeInt16Little(var); } +__WRITE_S(atUint16, Endian::Little) { w.writeUint16Little(var); } +__WRITE_S(atInt32, Endian::Little) { w.writeInt32Little(var); } +__WRITE_S(atUint32, Endian::Little) { w.writeUint32Little(var); } +__WRITE_S(atInt64, Endian::Little) { w.writeInt64Little(var); } +__WRITE_S(atUint64, Endian::Little) { w.writeUint64Little(var); } +__WRITE_S(float, Endian::Little) { w.writeFloatLittle(var); } +__WRITE_S(double, Endian::Little) { w.writeDoubleLittle(var); } +__WRITE_S(atVec2f, Endian::Little) { w.writeVec2fLittle(var); } +__WRITE_S(atVec2d, Endian::Little) { w.writeVec2dLittle(var); } +__WRITE_S(atVec3f, Endian::Little) { w.writeVec3fLittle(var); } +__WRITE_S(atVec3d, Endian::Little) { w.writeVec3dLittle(var); } +__WRITE_S(atVec4f, Endian::Little) { w.writeVec4fLittle(var); } +__WRITE_S(atVec4d, Endian::Little) { w.writeVec4dLittle(var); } +__WRITE_WSTR_S(Endian::Little) { w.writeWStringLittle(str); } +__WRITE_WSTRC_S(Endian::Little) { w.writeWStringLittle(str, count); } template struct ReadYaml @@ -526,28 +667,67 @@ struct ReadYaml ReadYaml::Do(id, var, r); } template - static typename std::enable_if_t && !__IsPODType()> + static typename std::enable_if_t<__IsDNARecord()> Do(const PropId& id, T& var, StreamT& r) { if (auto rec = r.enterSubRecord(id.name)) var.template Enumerate>(r); } template - static void Do(const PropId& id, std::vector& vector, size_t count, StreamT& r) + static typename std::enable_if_t> + Do(const PropId& id, T& var, StreamT& r) { + size_t _count; + if (auto __v = r.enterSubVector(id.name, _count)) + for (size_t i = 0; i < _count && i < std::extent_v; ++i) + ReadYaml::Do, DNAE>({}, var[i], r); + } + template + static void DoSize(const PropId& id, T& var, StreamT& s) + { + /* Squelch size field access */ + } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& r) + { + size_t _count; vector.clear(); - vector.reserve(count); - for (size_t i = 0; i < count; ++i) + if (auto __v = r.enterSubVector(id.name, _count)) { - vector.emplace_back(); - ReadYaml::Do(id, vector.back(), r); + vector.reserve(_count); + for (size_t i = 0; i < _count; ++i) + { + vector.emplace_back(); + ReadYaml::Do({}, vector.back(), r); + } } + /* Horrible reference abuse (but it works) */ + const_cast(count) = vector.size(); + } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& r) + { + /* libc++ specializes vector as a bitstream */ + size_t _count; + vector.clear(); + if (auto __v = r.enterSubVector(id.name, _count)) + { + vector.reserve(_count); + for (size_t i = 0; i < _count; ++i) + vector.push_back(r.readBool(nullptr)); + } + /* Horrible reference abuse (but it works) */ + const_cast(count) = vector.size(); } static void Do(const PropId& id, std::unique_ptr& buf, size_t count, StreamT& r) { buf = r.readUBytes(id.name); } - static void Do(const PropId& id, std::string& str, StreamT& r) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& r) { str = r.readString(id.name); } @@ -555,8 +735,9 @@ struct ReadYaml { str = r.readString(id.name); } - template - static void Do(const PropId& id, std::wstring& str, StreamT& r) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& r) { str = r.readWString(id.name); } @@ -568,40 +749,42 @@ struct ReadYaml static void DoSeek(atInt64 amount, SeekOrigin whence, StreamT& r) {} static void DoAlign(atInt64 amount, StreamT& r) {} }; -template <> template <> inline void ReadYaml::Do(const PropId& id, bool& var, ReadYaml::StreamT& r) { var = r.readBool(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atInt8& var, ReadYaml::StreamT& r) { var = r.readByte(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atUint8& var, ReadYaml::StreamT& r) { var = r.readUByte(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atInt16& var, ReadYaml::StreamT& r) { var = r.readInt16(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atUint16& var, ReadYaml::StreamT& r) { var = r.readUint16(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atInt32& var, ReadYaml::StreamT& r) { var = r.readInt32(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atUint32& var, ReadYaml::StreamT& r) { var = r.readUint32(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atInt64& var, ReadYaml::StreamT& r) { var = r.readInt64(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atUint64& var, ReadYaml::StreamT& r) { var = r.readUint64(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, float& var, ReadYaml::StreamT& r) { var = r.readFloat(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, double& var, ReadYaml::StreamT& r) { var = r.readDouble(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec2f& var, ReadYaml::StreamT& r) { var = r.readVec2f(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec2d& var, ReadYaml::StreamT& r) { var = r.readVec2d(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec3f& var, ReadYaml::StreamT& r) { var = r.readVec3f(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec3d& var, ReadYaml::StreamT& r) { var = r.readVec3d(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec4f& var, ReadYaml::StreamT& r) { var = r.readVec4f(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec4d& var, ReadYaml::StreamT& r) { var = r.readVec4d(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, bool& var, ReadYaml::StreamT& r) { var = r.readBool(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atInt8& var, ReadYaml::StreamT& r) { var = r.readByte(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atUint8& var, ReadYaml::StreamT& r) { var = r.readUByte(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atInt16& var, ReadYaml::StreamT& r) { var = r.readInt16(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atUint16& var, ReadYaml::StreamT& r) { var = r.readUint16(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atInt32& var, ReadYaml::StreamT& r) { var = r.readInt32(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atUint32& var, ReadYaml::StreamT& r) { var = r.readUint32(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atInt64& var, ReadYaml::StreamT& r) { var = r.readInt64(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atUint64& var, ReadYaml::StreamT& r) { var = r.readUint64(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, float& var, ReadYaml::StreamT& r) { var = r.readFloat(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, double& var, ReadYaml::StreamT& r) { var = r.readDouble(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec2f& var, ReadYaml::StreamT& r) { var = r.readVec2f(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec2d& var, ReadYaml::StreamT& r) { var = r.readVec2d(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec3f& var, ReadYaml::StreamT& r) { var = r.readVec3f(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec3d& var, ReadYaml::StreamT& r) { var = r.readVec3d(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec4f& var, ReadYaml::StreamT& r) { var = r.readVec4f(id.name); } -template <> template <> inline void ReadYaml::Do(const PropId& id, atVec4d& var, ReadYaml::StreamT& r) { var = r.readVec4d(id.name); } +#define __READ_YAML_S(type, endian) template <> template <> inline void ReadYaml::Do \ + (const PropId& id, type& var, ReadYaml::StreamT& r) +__READ_YAML_S(bool, Endian::Big) { var = r.readBool(id.name); } +__READ_YAML_S(atInt8, Endian::Big) { var = r.readByte(id.name); } +__READ_YAML_S(atUint8, Endian::Big) { var = r.readUByte(id.name); } +__READ_YAML_S(atInt16, Endian::Big) { var = r.readInt16(id.name); } +__READ_YAML_S(atUint16, Endian::Big) { var = r.readUint16(id.name); } +__READ_YAML_S(atInt32, Endian::Big) { var = r.readInt32(id.name); } +__READ_YAML_S(atUint32, Endian::Big) { var = r.readUint32(id.name); } +__READ_YAML_S(atInt64, Endian::Big) { var = r.readInt64(id.name); } +__READ_YAML_S(atUint64, Endian::Big) { var = r.readUint64(id.name); } +__READ_YAML_S(float, Endian::Big) { var = r.readFloat(id.name); } +__READ_YAML_S(double, Endian::Big) { var = r.readDouble(id.name); } +__READ_YAML_S(atVec2f, Endian::Big) { var = r.readVec2f(id.name); } +__READ_YAML_S(atVec2d, Endian::Big) { var = r.readVec2d(id.name); } +__READ_YAML_S(atVec3f, Endian::Big) { var = r.readVec3f(id.name); } +__READ_YAML_S(atVec3d, Endian::Big) { var = r.readVec3d(id.name); } +__READ_YAML_S(atVec4f, Endian::Big) { var = r.readVec4f(id.name); } +__READ_YAML_S(atVec4d, Endian::Big) { var = r.readVec4d(id.name); } +__READ_YAML_S(bool, Endian::Little) { var = r.readBool(id.name); } +__READ_YAML_S(atInt8, Endian::Little) { var = r.readByte(id.name); } +__READ_YAML_S(atUint8, Endian::Little) { var = r.readUByte(id.name); } +__READ_YAML_S(atInt16, Endian::Little) { var = r.readInt16(id.name); } +__READ_YAML_S(atUint16, Endian::Little) { var = r.readUint16(id.name); } +__READ_YAML_S(atInt32, Endian::Little) { var = r.readInt32(id.name); } +__READ_YAML_S(atUint32, Endian::Little) { var = r.readUint32(id.name); } +__READ_YAML_S(atInt64, Endian::Little) { var = r.readInt64(id.name); } +__READ_YAML_S(atUint64, Endian::Little) { var = r.readUint64(id.name); } +__READ_YAML_S(float, Endian::Little) { var = r.readFloat(id.name); } +__READ_YAML_S(double, Endian::Little) { var = r.readDouble(id.name); } +__READ_YAML_S(atVec2f, Endian::Little) { var = r.readVec2f(id.name); } +__READ_YAML_S(atVec2d, Endian::Little) { var = r.readVec2d(id.name); } +__READ_YAML_S(atVec3f, Endian::Little) { var = r.readVec3f(id.name); } +__READ_YAML_S(atVec3d, Endian::Little) { var = r.readVec3d(id.name); } +__READ_YAML_S(atVec4f, Endian::Little) { var = r.readVec4f(id.name); } +__READ_YAML_S(atVec4d, Endian::Little) { var = r.readVec4d(id.name); } template struct WriteYaml @@ -622,23 +805,49 @@ struct WriteYaml WriteYaml::Do(id, var, w); } template - static typename std::enable_if_t && !__IsPODType()> + static typename std::enable_if_t<__IsDNARecord()> Do(const PropId& id, T& var, StreamT& w) { if (auto rec = w.enterSubRecord(id.name)) var.template Enumerate>(w); } template - static void Do(const PropId& id, std::vector& vector, size_t count, StreamT& w) + static typename std::enable_if_t> + Do(const PropId& id, T& var, StreamT& w) { - for (T& v : vector) - WriteYaml::Do(id, v, w); + if (auto __v = w.enterSubVector(id.name)) + for (auto& v : var) + WriteYaml::Do, DNAE>({}, v, w); + } + template + static void DoSize(const PropId& id, T& var, StreamT& s) + { + /* Squelch size field access */ + } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& w) + { + if (auto __v = w.enterSubVector(id.name)) + for (T& v : vector) + WriteYaml::Do(id, v, w); + } + template + static typename std::enable_if_t> + Do(const PropId& id, std::vector& vector, const S& count, StreamT& w) + { + /* libc++ specializes vector as a bitstream */ + if (auto __v = w.enterSubVector(id.name)) + for (const T& v : vector) + w.writeBool(nullptr, v); } static void Do(const PropId& id, std::unique_ptr& buf, size_t count, StreamT& w) { w.writeUBytes(id.name, buf, count); } - static void Do(const PropId& id, std::string& str, StreamT& w) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& w) { w.writeString(id.name, str); } @@ -646,8 +855,9 @@ struct WriteYaml { w.writeString(id.name, str); } - template - static void Do(const PropId& id, std::wstring& str, StreamT& w) + template + static typename std::enable_if_t> + Do(const PropId& id, T& str, StreamT& w) { w.writeWString(id.name, str); } @@ -659,40 +869,42 @@ struct WriteYaml static void DoSeek(atInt64 amount, SeekOrigin whence, StreamT& w) {} static void DoAlign(atInt64 amount, StreamT& w) {} }; -template <> template <> inline void WriteYaml::Do(const PropId& id, bool& var, WriteYaml::StreamT& w) { w.writeBool(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atInt8& var, WriteYaml::StreamT& w) { w.writeByte(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atUint8& var, WriteYaml::StreamT& w) { w.writeUByte(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atInt16& var, WriteYaml::StreamT& w) { w.writeInt16(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atUint16& var, WriteYaml::StreamT& w) { w.writeUint16(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atInt32& var, WriteYaml::StreamT& w) { w.writeInt32(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atUint32& var, WriteYaml::StreamT& w) { w.writeUint32(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atInt64& var, WriteYaml::StreamT& w) { w.writeInt64(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atUint64& var, WriteYaml::StreamT& w) { w.writeUint64(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, float& var, WriteYaml::StreamT& w) { w.writeFloat(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, double& var, WriteYaml::StreamT& w) { w.writeDouble(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec2f& var, WriteYaml::StreamT& w) { w.writeVec2f(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec2d& var, WriteYaml::StreamT& w) { w.writeVec2d(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec3f& var, WriteYaml::StreamT& w) { w.writeVec3f(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec3d& var, WriteYaml::StreamT& w) { w.writeVec3d(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec4f& var, WriteYaml::StreamT& w) { w.writeVec4f(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec4d& var, WriteYaml::StreamT& w) { w.writeVec4d(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, bool& var, WriteYaml::StreamT& w) { w.writeBool(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atInt8& var, WriteYaml::StreamT& w) { w.writeByte(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atUint8& var, WriteYaml::StreamT& w) { w.writeUByte(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atInt16& var, WriteYaml::StreamT& w) { w.writeInt16(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atUint16& var, WriteYaml::StreamT& w) { w.writeUint16(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atInt32& var, WriteYaml::StreamT& w) { w.writeInt32(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atUint32& var, WriteYaml::StreamT& w) { w.writeUint32(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atInt64& var, WriteYaml::StreamT& w) { w.writeInt64(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atUint64& var, WriteYaml::StreamT& w) { w.writeUint64(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, float& var, WriteYaml::StreamT& w) { w.writeFloat(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, double& var, WriteYaml::StreamT& w) { w.writeDouble(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec2f& var, WriteYaml::StreamT& w) { w.writeVec2f(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec2d& var, WriteYaml::StreamT& w) { w.writeVec2d(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec3f& var, WriteYaml::StreamT& w) { w.writeVec3f(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec3d& var, WriteYaml::StreamT& w) { w.writeVec3d(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec4f& var, WriteYaml::StreamT& w) { w.writeVec4f(id.name, var); } -template <> template <> inline void WriteYaml::Do(const PropId& id, atVec4d& var, WriteYaml::StreamT& w) { w.writeVec4d(id.name, var); } +#define __WRITE_YAML_S(type, endian) template <> template <> inline void WriteYaml::Do \ + (const PropId& id, type& var, WriteYaml::StreamT& w) +__WRITE_YAML_S(bool, Endian::Big) { w.writeBool(id.name, var); } +__WRITE_YAML_S(atInt8, Endian::Big) { w.writeByte(id.name, var); } +__WRITE_YAML_S(atUint8, Endian::Big) { w.writeUByte(id.name, var); } +__WRITE_YAML_S(atInt16, Endian::Big) { w.writeInt16(id.name, var); } +__WRITE_YAML_S(atUint16, Endian::Big) { w.writeUint16(id.name, var); } +__WRITE_YAML_S(atInt32, Endian::Big) { w.writeInt32(id.name, var); } +__WRITE_YAML_S(atUint32, Endian::Big) { w.writeUint32(id.name, var); } +__WRITE_YAML_S(atInt64, Endian::Big) { w.writeInt64(id.name, var); } +__WRITE_YAML_S(atUint64, Endian::Big) { w.writeUint64(id.name, var); } +__WRITE_YAML_S(float, Endian::Big) { w.writeFloat(id.name, var); } +__WRITE_YAML_S(double, Endian::Big) { w.writeDouble(id.name, var); } +__WRITE_YAML_S(atVec2f, Endian::Big) { w.writeVec2f(id.name, var); } +__WRITE_YAML_S(atVec2d, Endian::Big) { w.writeVec2d(id.name, var); } +__WRITE_YAML_S(atVec3f, Endian::Big) { w.writeVec3f(id.name, var); } +__WRITE_YAML_S(atVec3d, Endian::Big) { w.writeVec3d(id.name, var); } +__WRITE_YAML_S(atVec4f, Endian::Big) { w.writeVec4f(id.name, var); } +__WRITE_YAML_S(atVec4d, Endian::Big) { w.writeVec4d(id.name, var); } +__WRITE_YAML_S(bool, Endian::Little) { w.writeBool(id.name, var); } +__WRITE_YAML_S(atInt8, Endian::Little) { w.writeByte(id.name, var); } +__WRITE_YAML_S(atUint8, Endian::Little) { w.writeUByte(id.name, var); } +__WRITE_YAML_S(atInt16, Endian::Little) { w.writeInt16(id.name, var); } +__WRITE_YAML_S(atUint16, Endian::Little) { w.writeUint16(id.name, var); } +__WRITE_YAML_S(atInt32, Endian::Little) { w.writeInt32(id.name, var); } +__WRITE_YAML_S(atUint32, Endian::Little) { w.writeUint32(id.name, var); } +__WRITE_YAML_S(atInt64, Endian::Little) { w.writeInt64(id.name, var); } +__WRITE_YAML_S(atUint64, Endian::Little) { w.writeUint64(id.name, var); } +__WRITE_YAML_S(float, Endian::Little) { w.writeFloat(id.name, var); } +__WRITE_YAML_S(double, Endian::Little) { w.writeDouble(id.name, var); } +__WRITE_YAML_S(atVec2f, Endian::Little) { w.writeVec2f(id.name, var); } +__WRITE_YAML_S(atVec2d, Endian::Little) { w.writeVec2d(id.name, var); } +__WRITE_YAML_S(atVec3f, Endian::Little) { w.writeVec3f(id.name, var); } +__WRITE_YAML_S(atVec3d, Endian::Little) { w.writeVec3d(id.name, var); } +__WRITE_YAML_S(atVec4f, Endian::Little) { w.writeVec4f(id.name, var); } +__WRITE_YAML_S(atVec4d, Endian::Little) { w.writeVec4d(id.name, var); } template static inline void __Do(const PropId& id, T& var, typename Op::StreamT& s) @@ -701,9 +913,15 @@ static inline void __Do(const PropId& id, T& var, typename Op::StreamT& s) } template -static inline void __Do(const PropId& id, std::vector& vector, size_t count, typename Op::StreamT& s) +static inline void __DoSize(const PropId& id, T& var, typename Op::StreamT& s) { - Op::template Do(id, vector, count, s); + Op::template DoSize(id, var, s); +} + +template +static inline void __Do(const PropId& id, std::vector& vector, const S& count, typename Op::StreamT& s) +{ + Op::template Do(id, vector, count, s); } template @@ -712,24 +930,12 @@ static inline void __Do(const PropId& id, std::unique_ptr& buf, size_ Op::Do(id, buf, count, s); } -template -static inline void __Do(const PropId& id, std::string& str, typename Op::StreamT& s) -{ - Op::Do(id, str, s); -} - template static inline void __Do(const PropId& id, std::string& str, size_t count, typename Op::StreamT& s) { Op::Do(id, str, count, s); } -template -static inline void __Do(const PropId& id, std::wstring& str, typename Op::StreamT& s) -{ - Op::template Do(id, str, s); -} - template static inline void __Do(const PropId& id, std::wstring& str, size_t count, typename Op::StreamT& s) { @@ -838,27 +1044,96 @@ static inline void __BinarySizeProp64(const T& obj, size_t& s) #define AT_DECL_DNA \ template \ -void Do(const athena::io::PropId& id, T& var, typename Op::StreamT& s) { athena::io::__Do(id, var, s); } \ +void Do(const athena::io::PropId& id, T& var, typename Op::StreamT& s) \ + { athena::io::__Do(id, var, s); } \ template \ -void Do(const athena::io::PropId& id, std::vector& var, size_t count, typename Op::StreamT& s) { athena::io::__Do(id, var, count, s); } \ +void DoSize(const athena::io::PropId& id, T& var, typename Op::StreamT& s) \ + { athena::io::__DoSize(id, var, s); } \ +template \ +void Do(const athena::io::PropId& id, std::vector& var, const S& count, typename Op::StreamT& s) \ + { athena::io::__Do(id, var, count, s); } \ template \ -void Do(const athena::io::PropId& id, std::unique_ptr& buf, size_t count, typename Op::StreamT& s) { athena::io::__Do(id, buf, count, s); } \ +void Do(const athena::io::PropId& id, std::unique_ptr& buf, size_t count, typename Op::StreamT& s) \ + { athena::io::__Do(id, buf, count, s); } \ template \ -void Do(const athena::io::PropId& id, std::string& str, typename Op::StreamT& s) { athena::io::__Do(id, str, s); } \ -template \ -void Do(const athena::io::PropId& id, std::string& str, size_t count, typename Op::StreamT& s) { athena::io::__Do(id, str, count, s); } \ +void Do(const athena::io::PropId& id, std::string& str, size_t count, typename Op::StreamT& s) \ + { athena::io::__Do(id, str, count, s); } \ template \ -void Do(const athena::io::PropId& id, std::wstring& str, typename Op::StreamT& s) { athena::io::__Do(id, str, s); } \ +void Do(const athena::io::PropId& id, std::wstring& str, size_t count, typename Op::StreamT& s) \ + { athena::io::__Do(id, str, count, s); } \ +template \ +void DoSeek(atInt64 delta, athena::SeekOrigin whence, typename Op::StreamT& s) \ + { athena::io::__DoSeek(delta, whence, s); } \ +template \ +void DoAlign(atInt64 amount, typename Op::StreamT& s) \ + { athena::io::__DoAlign(amount, s); } \ +template \ +void Enumerate(typename Op::StreamT& s); \ +static const char* DNAType(); \ +void read(athena::io::IStreamReader& r) { athena::io::__Read(*this, r); } \ +void write(athena::io::IStreamWriter& w) const { athena::io::__Write(*this, w); } \ +void binarySize(size_t& s) const { athena::io::__BinarySize(*this, s); } + +#define AT_DECL_DNA_YAML \ +AT_DECL_DNA \ +void read(athena::io::YAMLDocReader& r) { athena::io::__ReadYaml(*this, r); } \ +void write(athena::io::YAMLDocWriter& w) const { athena::io::__WriteYaml(*this, w); } + +#define AT_DECL_EXPLICIT_DNA \ +AT_DECL_DNA \ +Delete __d; + +#define AT_DECL_EXPLICIT_DNA_YAML \ +AT_DECL_DNA_YAML \ +Delete __d; + +#define AT_DECL_DNAV const char* DNATypeV() const {return DNAType();} + +#define AT_SPECIALIZE_DNA(...) \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::Read::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::Write::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::BinarySize::StreamT& s); + +#define AT_SPECIALIZE_DNA_YAML(...) \ +AT_SPECIALIZE_DNA(__VA_ARGS__) \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::ReadYaml::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::WriteYaml::StreamT& s); + +#define AT_DECL_PROPDNA \ +template \ +void Do(const athena::io::PropId& id, T& var, typename Op::StreamT& s) \ + { athena::io::__Do(id, var, s); } \ +template \ +void DoSize(const athena::io::PropId& id, T& var, typename Op::StreamT& s) \ + { athena::io::__DoSize(id, var, s); } \ +template \ +void Do(const athena::io::PropId& id, std::vector& var, const S& count, typename Op::StreamT& s) \ + { athena::io::__Do(id, var, count, s); } \ +template \ +void Do(const athena::io::PropId& id, std::unique_ptr& buf, size_t count, typename Op::StreamT& s) \ + { athena::io::__Do(id, buf, count, s); } \ +template \ +void Do(const athena::io::PropId& id, std::string& str, size_t count, typename Op::StreamT& s) \ + { athena::io::__Do(id, str, count, s); } \ template \ -void Do(const athena::io::PropId& id, std::wstring& str, size_t count, typename Op::StreamT& s) { athena::io::__Do(id, str, count, s); } \ +void Do(const athena::io::PropId& id, std::wstring& str, size_t count, typename Op::StreamT& s) \ + { athena::io::__Do(id, str, count, s); } \ template \ -void DoSeek(atInt64 delta, athena::SeekOrigin whence, typename Op::StreamT& s) { athena::io::__DoSeek(delta, whence, s); } \ +void DoSeek(atInt64 delta, athena::SeekOrigin whence, typename Op::StreamT& s) \ + { athena::io::__DoSeek(delta, whence, s); } \ template \ -void DoAlign(atInt64 amount, typename Op::StreamT& s) { athena::io::__DoAlign(amount, s); } \ +void DoAlign(atInt64 amount, typename Op::StreamT& s) \ + { athena::io::__DoAlign(amount, s); } \ template \ void Enumerate(typename Op::StreamT& s); \ template \ bool Lookup(uint64_t hash, typename Op::StreamT& s); \ +static const char* DNAType(); \ void read(athena::io::IStreamReader& r) { athena::io::__Read(*this, r); } \ void write(athena::io::IStreamWriter& w) const { athena::io::__Write(*this, w); } \ void binarySize(size_t& s) const { athena::io::__BinarySize(*this, s); } \ @@ -872,37 +1147,110 @@ void readProp64(athena::io::IStreamReader& r) { athena::io::__ReadProp64(*this, void writeProp64(athena::io::IStreamWriter& w) const { athena::io::__WriteProp64(*this, w); } \ void binarySizeProp64(size_t& s) const { athena::io::__BinarySizeProp64(*this, s); } \ -#define AT_SPECIALIZE_DNA(__Type) \ -template void __Type::Enumerate>(athena::io::Read::StreamT& s); \ -template void __Type::Enumerate>(athena::io::Write::StreamT& s); \ -template void __Type::Enumerate>(athena::io::BinarySize::StreamT& s); \ -template void __Type::Enumerate>(athena::io::ReadYaml::StreamT& s); \ -template void __Type::Enumerate>(athena::io::WriteYaml::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::Read::StreamT& s); \ -template void __Type::Enumerate>(athena::io::Read::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::Write::StreamT& s); \ -template void __Type::Enumerate>(athena::io::Write::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::BinarySize::StreamT& s); \ -template void __Type::Enumerate>(athena::io::BinarySize::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::PropCount::StreamT& s); \ -template void __Type::Enumerate>(athena::io::PropCount::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::ReadYaml::StreamT& s); \ -template void __Type::Enumerate>(athena::io::ReadYaml::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::WriteYaml::StreamT& s); \ -template void __Type::Enumerate>(athena::io::WriteYaml::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::Read::StreamT& s); \ -template void __Type::Enumerate>(athena::io::Read::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::Write::StreamT& s); \ -template void __Type::Enumerate>(athena::io::Write::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::BinarySize::StreamT& s); \ -template void __Type::Enumerate>(athena::io::BinarySize::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::PropCount::StreamT& s); \ -template void __Type::Enumerate>(athena::io::PropCount::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::ReadYaml::StreamT& s); \ -template void __Type::Enumerate>(athena::io::ReadYaml::StreamT& s); \ -template bool __Type::Lookup>(uint64_t hash, athena::io::WriteYaml::StreamT& s); \ -template void __Type::Enumerate>(athena::io::WriteYaml::StreamT& s); +#define AT_DECL_EXPLICIT_PROPDNA \ +AT_DECL_PROPDNA \ +Delete __d; -using namespace athena::io::literals; +#define AT_SPECIALIZE_PROPDNA(...) \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::Read::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::Write::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::BinarySize::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::ReadYaml::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::WriteYaml::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::Read::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::Read::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::Write::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::Write::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::BinarySize::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::BinarySize::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::PropCount::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::PropCount::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::ReadYaml::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::ReadYaml::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::WriteYaml::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::WriteYaml::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::Read::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::Read::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::Write::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::Write::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::BinarySize::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::BinarySize::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::PropCount::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::PropCount::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::ReadYaml::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::ReadYaml::StreamT& s); \ +template bool __VA_ARGS__::Lookup>\ + (uint64_t hash, athena::io::WriteYaml::StreamT& s); \ +template void __VA_ARGS__::Enumerate>\ + (athena::io::WriteYaml::StreamT& s); + +#define AT_SUBDECL_DNA \ +void _read(athena::io::IStreamReader& r); \ +void _write(athena::io::IStreamWriter& w) const; \ +void _binarySize(size_t& s) const; \ +void _read(athena::io::YAMLDocReader& r); \ +void _write(athena::io::YAMLDocWriter& w) const; + +#define AT_SUBDECL_DNA_YAML \ +AT_SUBDECL_DNA \ +void _read(athena::io::YAMLDocReader& r); \ +void _write(athena::io::YAMLDocWriter& w) const; + +#define AT_SUBSPECIALIZE_DNA(...) \ +template <> template <> \ +void __VA_ARGS__::Enumerate::BinarySize>(typename BinarySize::StreamT& s) \ +{ \ + _binarySize(s); \ +} \ +template <> template <> \ +void __VA_ARGS__::Enumerate::Read>(typename Read::StreamT& r) \ +{ \ + _read(r); \ +} \ +template <> template <> \ +void __VA_ARGS__::Enumerate::Write>(typename Write::StreamT& w) \ +{ \ + _write(w); \ +} + +#define AT_SUBSPECIALIZE_DNA_YAML(...) \ +template <> template <> \ +void __VA_ARGS__::Enumerate::ReadYaml>(typename ReadYaml::StreamT& r) \ +{ \ + _read(r); \ +} \ +template <> template <> \ +void __VA_ARGS__::Enumerate::WriteYaml>(typename WriteYaml::StreamT& w) \ +{ \ + _write(w); \ +} \ +AT_SUBSPECIALIZE_DNA(__VA_ARGS__) #endif // AT_OP_HPP diff --git a/include/athena/DNAYaml.hpp b/include/athena/DNAYaml.hpp index 8b5c120..a511cd7 100644 --- a/include/athena/DNAYaml.hpp +++ b/include/athena/DNAYaml.hpp @@ -10,10 +10,24 @@ namespace athena::io { +template +static inline const char* __GetDNAName(const T& dna, + typename std::enable_if_t()>* = 0) +{ + return dna.DNATypeV(); +} + +template +static inline const char* __GetDNAName(const T& dna, + typename std::enable_if_t()>* = 0) +{ + return dna.DNAType(); +} + template static inline std::string ToYAMLString(const T& dna) { - YAMLDocWriter docWriter(dna.DNAType()); + YAMLDocWriter docWriter(__GetDNAName(dna)); std::string res; yaml_emitter_set_output(docWriter.getEmitter(), (yaml_write_handler_t*)YAMLStdStringWriter, &res); @@ -52,7 +66,7 @@ static inline bool ValidateFromYAMLString(std::string_view str) template static inline bool ToYAMLStream(const T& dna, athena::io::IStreamWriter& fout) { - YAMLDocWriter docWriter(dna.DNAType()); + YAMLDocWriter docWriter(__GetDNAName(dna)); yaml_emitter_set_unicode(docWriter.getEmitter(), true); yaml_emitter_set_width(docWriter.getEmitter(), -1); @@ -65,12 +79,12 @@ template static inline bool ToYAMLStream(const T& dna, athena::io::IStreamWriter& fout, void(T::*fn)(YAMLDocWriter& out)const) { - YAMLDocWriter docWriter(dna.DNAType()); + YAMLDocWriter docWriter(__GetDNAName(dna)); yaml_emitter_set_unicode(docWriter.getEmitter(), true); yaml_emitter_set_width(docWriter.getEmitter(), -1); - (dna->*fn)(docWriter); + (dna.*fn)(docWriter); return docWriter.finish(&fout); } @@ -91,7 +105,7 @@ static inline bool FromYAMLStream(T& dna, athena::io::IStreamReader& fin, YAMLDocReader docReader; if (!docReader.parse(&fin)) return false; - (dna->*fn)(docReader); + (dna.*fn)(docReader); return true; } @@ -99,7 +113,7 @@ template static inline bool MergeToYAMLFile(const T& dna, const NameT& filename) { athena::io::FileReader r(filename); - YAMLDocWriter docWriter(dna.DNAType(), r.isOpen() ? &r : nullptr); + YAMLDocWriter docWriter(__GetDNAName(dna), r.isOpen() ? &r : nullptr); r.close(); dna.write(docWriter); diff --git a/include/athena/Global.hpp b/include/athena/Global.hpp index 8f87907..4f3ae1a 100644 --- a/include/athena/Global.hpp +++ b/include/athena/Global.hpp @@ -137,6 +137,27 @@ enum Endian Little, Big }; + +namespace io +{ +template +struct DNA; +template +struct DNAV; + +template +static inline constexpr bool __IsDNARecord() +{ + return std::is_base_of_v, T> || + std::is_base_of_v, T>; +} +template +static inline constexpr bool __IsDNAVRecord() +{ + return std::is_base_of_v, T> || + std::is_base_of_v, T>; +} +} } // Athena typedef void (*atEXCEPTION_HANDLER)(athena::error::Level level, const char* file, const char* function, int line, diff --git a/include/athena/YAMLDocReader.hpp b/include/athena/YAMLDocReader.hpp index 6fb581b..e6dc994 100644 --- a/include/athena/YAMLDocReader.hpp +++ b/include/athena/YAMLDocReader.hpp @@ -48,7 +48,8 @@ public: RecordRAII enterSubRecord(const char* name); template - void enumerate(const char* name, T& record) + void enumerate(const char* name, T& record, + typename std::enable_if_t<__IsDNARecord()>* = 0) { if (auto rec = enterSubRecord(name)) record.read(*this); @@ -70,10 +71,10 @@ public: template size_t enumerate(const char* name, std::vector& vector, - typename std::enable_if::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value>::type* = 0) + typename std::enable_if_t::value && + !std::is_same::value && + !std::is_same::value && + !std::is_same::value>* = 0) { size_t countOut; if (auto v = enterSubVector(name, countOut)) @@ -92,10 +93,10 @@ public: template size_t enumerate(const char* name, std::vector& vector, - typename std::enable_if::value || - std::is_same::value || - std::is_same::value || - std::is_same::value>::type* = 0) + typename std::enable_if_t::value || + std::is_same::value || + std::is_same::value || + std::is_same::value>* = 0) { size_t countOut; if (auto v = enterSubVector(name, countOut)) diff --git a/include/athena/YAMLDocWriter.hpp b/include/athena/YAMLDocWriter.hpp index 5b887b9..8e15199 100644 --- a/include/athena/YAMLDocWriter.hpp +++ b/include/athena/YAMLDocWriter.hpp @@ -39,7 +39,8 @@ public: RecordRAII enterSubRecord(const char* name); template - void enumerate(const char* name, T& record) + void enumerate(const char* name, T& record, + typename std::enable_if_t<__IsDNARecord()>* = 0) { if (auto rec = enterSubRecord(name)) record.write(*this); @@ -61,13 +62,13 @@ public: template void enumerate(const char* name, const std::vector& vector, - typename std::enable_if::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value && - !std::is_same::value>::type* = 0) + typename std::enable_if_t::value && + !std::is_same::value && + !std::is_same::value && + !std::is_same::value && + !std::is_same::value && + !std::is_same::value && + !std::is_same::value>* = 0) { if (auto v = enterSubVector(name)) for (const T& item : vector) @@ -77,13 +78,13 @@ public: template void enumerate(const char* name, const std::vector& vector, - typename std::enable_if::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value>::type* = 0) + typename std::enable_if_t::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value>* = 0) { if (auto v = enterSubVector(name)) for (T item : vector)