upgradeable types!
This commit is contained in:
@@ -16,6 +16,7 @@ namespace WriteTemplates
|
||||
constexpr char FileHeaderStart[] =
|
||||
R"END(#pragma once
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
namespace Gen
|
||||
{
|
||||
@@ -101,24 +102,115 @@ namespace Gen
|
||||
)END";
|
||||
constexpr char LoadFuncBodyStart1[] = R"END( bool Load(%s* obj, uint32_t count, Deserializer& serializer)
|
||||
{
|
||||
)END";
|
||||
constexpr char LoadFuncBodySetupStart2[] =
|
||||
R"END( const char* typeName = Meta::Metadata.TypeDefinitions[%s::TypeIdx].Name;
|
||||
|
||||
// Quick match
|
||||
int32_t matchedHashIdx =
|
||||
serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[%s::TypeIdx].Hash);
|
||||
if (matchedHashIdx >= 0)
|
||||
{
|
||||
assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0);
|
||||
bool isOk = true;
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
)END";
|
||||
constexpr char LoadFuncBodyQuickLoad2[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk;
|
||||
)END";
|
||||
constexpr char LoadFuncBodySetupEnd[] = R"END( }
|
||||
// if we're not ok here, something went really wrong
|
||||
assert(isOk);
|
||||
return isOk;
|
||||
}
|
||||
|
||||
// Failed to resolve hash, the type definition chaned since the file was saved! try to match by name.
|
||||
int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName);
|
||||
if (nameMatchIdx < 0)
|
||||
{
|
||||
// Name match failed, caller has to handle this and potentially skip some bytes
|
||||
return false;
|
||||
}
|
||||
|
||||
// Successfully matched name, but we need to follow the definition of the file now!
|
||||
const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx];
|
||||
|
||||
// Figure out new member mapping
|
||||
uint64_t WriteDestinations[64];
|
||||
for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i)
|
||||
{
|
||||
WriteDestinations[i] = UINT64_MAX;
|
||||
}
|
||||
for (uint32_t i = 0; i < matchedDef.ChildCount; ++i)
|
||||
{
|
||||
const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size};
|
||||
const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name;
|
||||
)END";
|
||||
constexpr char LoadFuncBodyMemberCheck4[] =
|
||||
R"END( if (bx::strCmp(memberName, "%s") == 0 && bx::strCmp(memberTypeName, "%s") == 0)
|
||||
{
|
||||
WriteDestinations[i] = offsetof(%s, %s);
|
||||
}
|
||||
)END";
|
||||
constexpr char LoadFuncBodyTypeUpgradeStart[] = R"END( }
|
||||
|
||||
// Start reading in file order, skipping things that we don't know by name and type
|
||||
bool isOk = true;
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
uint8_t* objBasePtr = reinterpret_cast<uint8_t*>(&obj[i]);
|
||||
|
||||
for (uint32_t j = 0; j < matchedDef.ChildCount; ++j)
|
||||
{
|
||||
const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]];
|
||||
const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size};
|
||||
if (WriteDestinations[j] == UINT64_MAX)
|
||||
{
|
||||
// Unknown member name or type changed
|
||||
serializer.Skip(childDef.Size);
|
||||
continue;
|
||||
}
|
||||
|
||||
)END";
|
||||
constexpr char LoadFuncBodyType3[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk;
|
||||
constexpr char LoadFuncBodyTypeUpgradeMember3[] = R"END( if (bx::strCmp(memberName, "%s") == 0)
|
||||
{
|
||||
auto* fieldPtr = reinterpret_cast<%s*>(objBasePtr + WriteDestinations[j]);
|
||||
isOk = Load(fieldPtr, %u, serializer) && isOk;
|
||||
continue;
|
||||
}
|
||||
)END";
|
||||
constexpr char LoadFuncBodyNative[] = R"END( isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
|
||||
)END";
|
||||
constexpr char LoadFuncBodyEnum2[] = R"END( %s& val = (%s&)obj[i];
|
||||
isOk = Load(&val, 1, serializer) && isOk;
|
||||
)END";
|
||||
constexpr char LoadFuncBodyEnd[] = R"END( }
|
||||
constexpr char LoadFuncBodyTypeUpgradeEnd[] = R"END( assert(false);
|
||||
}
|
||||
}
|
||||
assert(isOk);
|
||||
return isOk;
|
||||
}
|
||||
)END";
|
||||
constexpr char LoadFuncBodyNative[] = R"END( bool isOk = true;
|
||||
for (int32_t i = 0; i < count; ++i)
|
||||
{
|
||||
isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk;
|
||||
}
|
||||
return isOk;
|
||||
}
|
||||
)END";
|
||||
constexpr char LoadFuncBodyEnum2[] = R"END( bool isOk = true;
|
||||
for (int32_t i = 0; i < count; ++i)
|
||||
{
|
||||
%s& val = (%s&)obj[i];
|
||||
isOk = Load(&val, 1, serializer) && isOk;
|
||||
}
|
||||
return isOk;
|
||||
}
|
||||
)END";
|
||||
|
||||
constexpr char MetadataStart1[] = R"END(
|
||||
namespace Meta {
|
||||
struct StrRef
|
||||
{
|
||||
uint16_t Offset;
|
||||
uint16_t Size;
|
||||
};
|
||||
|
||||
struct TypeDef
|
||||
{
|
||||
uint32_t Size = 0;
|
||||
@@ -126,6 +218,7 @@ namespace Gen
|
||||
char Name[64]{"Dummy"};
|
||||
uint16_t ChildCount = 0;
|
||||
uint16_t ChildIndices[64]{0};
|
||||
StrRef MemberNameIndices[64]{0};
|
||||
};
|
||||
|
||||
struct EnumDef
|
||||
@@ -140,7 +233,7 @@ namespace Gen
|
||||
{
|
||||
)END";
|
||||
|
||||
constexpr char MetadataTypeEntry5[] = R"END( TypeDef{sizeof(%s), %u, "%s", %u, {%s}},
|
||||
constexpr char MetadataTypeEntry6[] = R"END( TypeDef{sizeof(%s), %u, "%s", %u, {%s}, {%s}},
|
||||
)END";
|
||||
constexpr char MetadataEnumStart1[] = R"END( };
|
||||
EnumDef EnumDefinitions[%u]
|
||||
@@ -148,7 +241,8 @@ namespace Gen
|
||||
)END";
|
||||
constexpr char MetadataEnumEntry2[] = R"END( EnumDef{sizeof(%s::Enum), %u},
|
||||
)END";
|
||||
constexpr char MetadataEnd[] = R"END( };
|
||||
constexpr char MetadataEnd1[] = R"END( };
|
||||
char MemberNameBuffer[64*64*64]{"%s"};
|
||||
};
|
||||
|
||||
constexpr MetadataTable Metadata;
|
||||
@@ -317,7 +411,6 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions)
|
||||
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyStart1, nameBuf);
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyEnum2, fieldBuf, fieldBuf);
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyEnd);
|
||||
}
|
||||
for (uint16_t typeIdx = 0; typeIdx < definitions.TypeCount; ++typeIdx)
|
||||
{
|
||||
@@ -329,13 +422,13 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions)
|
||||
Write(WriteTemplates::LoadFuncHeader1, typeName);
|
||||
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyStart1, typeName);
|
||||
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||
if ((int32_t)t.TypeFlags & (int32_t)Def::ETypeFlags::IsNative)
|
||||
{
|
||||
if (Def::IsFieldNative(definitions, t, fieldIdx))
|
||||
{
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyNative);
|
||||
}
|
||||
else
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyNative);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||
{
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyType3,
|
||||
t.FieldArraySizes[fieldIdx] > 0 ? "" : "&",
|
||||
@@ -346,30 +439,55 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions)
|
||||
WriteCpp(WriteTemplates::SaveFuncBodyEnd);
|
||||
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyStart1, typeName);
|
||||
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||
if ((int32_t)t.TypeFlags & (int32_t)Def::ETypeFlags::IsNative)
|
||||
{
|
||||
if (Def::IsFieldNative(definitions, t, fieldIdx))
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyNative);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteCpp(WriteTemplates::LoadFuncBodySetupStart2, typeName, typeName);
|
||||
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||
{
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyNative);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyType3,
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyQuickLoad2,
|
||||
t.FieldArraySizes[fieldIdx] > 0 ? "" : "&",
|
||||
t.FieldNames[fieldIdx],
|
||||
bx::max(1, t.FieldArraySizes[fieldIdx]));
|
||||
}
|
||||
WriteCpp(WriteTemplates::LoadFuncBodySetupEnd);
|
||||
char fieldTypeName[Def::MaxNameLength]{0};
|
||||
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||
{
|
||||
const char* fieldName = t.FieldNames[fieldIdx];
|
||||
PrintTypeName(fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions);
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyMemberCheck4, fieldName, fieldTypeName, typeName, fieldName);
|
||||
}
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeStart);
|
||||
for (uint32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
|
||||
{
|
||||
const char* fieldName = t.FieldNames[fieldIdx];
|
||||
PrintTypeName(fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions);
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeMember3,
|
||||
fieldName,
|
||||
fieldTypeName,
|
||||
bx::max(1, t.FieldArraySizes[fieldIdx]));
|
||||
}
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeEnd);
|
||||
}
|
||||
WriteCpp(WriteTemplates::LoadFuncBodyEnd);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
char MemberNameBuffer[64 * 64 * 64]{0};
|
||||
}
|
||||
void CppFileWriter::WriteMetadata(const Def::DefinitionFile& definitions)
|
||||
{
|
||||
uint32_t memberNameBufferIdx = 0;
|
||||
Write(WriteTemplates::MetadataStart1, definitions.TypeCount);
|
||||
for (uint16_t i = 0; i < definitions.TypeCount; ++i)
|
||||
{
|
||||
auto& type = definitions.Types[i];
|
||||
|
||||
char fieldStr[256]{0};
|
||||
for (int32_t j = 0; j < type.FieldCount; ++j)
|
||||
{
|
||||
@@ -378,16 +496,31 @@ void CppFileWriter::WriteMetadata(const Def::DefinitionFile& definitions)
|
||||
bx::snprintf(numBuf, sizeof(numBuf), "%u", type.FieldTypes[j].TypeIdx);
|
||||
bx::strCat(fieldStr, sizeof(fieldStr), numBuf);
|
||||
}
|
||||
|
||||
char typeStr[Def::MaxNameLength]{0};
|
||||
PrintTypeName(typeStr, sizeof(typeStr), {i, Def::EFieldType::DefinedClass}, definitions);
|
||||
Write(WriteTemplates::MetadataTypeEntry5, typeStr, type.Hash, type.Name, type.FieldCount, fieldStr);
|
||||
|
||||
char memberIdxStr[256]{0};
|
||||
for (int32_t j = 0; j < type.FieldCount; ++j)
|
||||
{
|
||||
if (j != 0) bx::strCat(memberIdxStr, sizeof(memberIdxStr), ", ");
|
||||
char numBuf[16]{0};
|
||||
bx::snprintf(numBuf, sizeof(numBuf), "{%u, %u}", memberNameBufferIdx, bx::strLen(type.FieldNames[j]));
|
||||
bx::strCat(memberIdxStr, sizeof(memberIdxStr), numBuf);
|
||||
|
||||
memberNameBufferIdx += bx::strCopy(&MemberNameBuffer[memberNameBufferIdx],
|
||||
sizeof(MemberNameBuffer) - memberNameBufferIdx,
|
||||
type.FieldNames[j]);
|
||||
}
|
||||
Write(
|
||||
WriteTemplates::MetadataTypeEntry6, typeStr, type.Hash, type.Name, type.FieldCount, fieldStr, memberIdxStr);
|
||||
}
|
||||
Write(WriteTemplates::MetadataEnumStart1, definitions.EnumCount);
|
||||
for (int32_t i = 0; i < definitions.EnumCount; ++i)
|
||||
{
|
||||
Write(WriteTemplates::MetadataEnumEntry2, definitions.Enums[i].Name, definitions.Enums[i].Hash);
|
||||
}
|
||||
Write(WriteTemplates::MetadataEnd);
|
||||
Write(WriteTemplates::MetadataEnd1, MemberNameBuffer);
|
||||
}
|
||||
|
||||
void CppFileWriter::GenerateCpp(const bx::FilePath& outDir, const Def::DefinitionFile& definitions)
|
||||
|
||||
@@ -69,10 +69,4 @@ namespace Def
|
||||
Def::Enum Enums[MaxTypes];
|
||||
int32_t EnumCount = 0;
|
||||
};
|
||||
|
||||
inline bool IsFieldNative(const DefinitionFile& definitions, const Type& type, int32_t fieldIdx)
|
||||
{
|
||||
return ((int32_t)definitions.Types[type.FieldTypes[fieldIdx].TypeIdx].TypeFlags &
|
||||
(int32_t)ETypeFlags::IsNative) > 0;
|
||||
}
|
||||
} // namespace Def
|
||||
|
||||
Reference in New Issue
Block a user