diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.cpp b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.cpp index 516494b6..7cfddc4d 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.cpp +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.cpp @@ -189,13 +189,13 @@ bool MemberComputations::IsInRuntimeBlock() const return m_info->m_fast_file_block != nullptr && m_info->m_fast_file_block->m_type == FastFileBlockType::RUNTIME; } -bool MemberComputations::IsFirstMember() const +bool MemberComputations::IsFirstUsedMember() const { const auto parentUsedMembers = StructureComputations(m_info->m_parent).GetUsedMembers(); return !parentUsedMembers.empty() && parentUsedMembers[0] == m_info; } -bool MemberComputations::IsLastMember() const +bool MemberComputations::IsLastUsedMember() const { const auto parentUsedMembers = StructureComputations(m_info->m_parent).GetUsedMembers(); return !parentUsedMembers.empty() && parentUsedMembers[parentUsedMembers.size() - 1] == m_info; diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.h b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.h index 5ced8c26..2ab179f6 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.h +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.h @@ -25,8 +25,8 @@ public: [[nodiscard]] bool IsNotInDefaultNormalBlock() const; [[nodiscard]] bool IsInTempBlock() const; [[nodiscard]] bool IsInRuntimeBlock() const; - [[nodiscard]] bool IsFirstMember() const; - [[nodiscard]] bool IsLastMember() const; + [[nodiscard]] bool IsFirstUsedMember() const; + [[nodiscard]] bool IsLastUsedMember() const; [[nodiscard]] bool HasDynamicArraySize() const; [[nodiscard]] bool IsDynamicMember() const; [[nodiscard]] bool IsAfterPartialLoad() const; diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberDeclarationModifierComputations.cpp b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberDeclarationModifierComputations.cpp index f30e49ca..5f77f861 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberDeclarationModifierComputations.cpp +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberDeclarationModifierComputations.cpp @@ -56,6 +56,18 @@ DeclarationModifier* DeclarationModifierComputations::GetNextDeclarationModifier return nullptr; } +std::vector DeclarationModifierComputations::GetAllDeclarationModifiers() const +{ + const auto& declarationModifiers = m_information->m_member->m_type_declaration->m_declaration_modifiers; + std::vector all; + all.reserve(declarationModifiers.size()); + + for (const auto& mod : declarationModifiers) + all.emplace_back(mod.get()); + + return all; +} + std::vector DeclarationModifierComputations::GetFollowingDeclarationModifiers() const { std::vector following; diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberDeclarationModifierComputations.h b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberDeclarationModifierComputations.h index 256bff1e..4f1e7e70 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberDeclarationModifierComputations.h +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberDeclarationModifierComputations.h @@ -12,6 +12,7 @@ public: [[nodiscard]] DeclarationModifier* GetDeclarationModifier() const; [[nodiscard]] DeclarationModifier* GetNextDeclarationModifier() const; + [[nodiscard]] std::vector GetAllDeclarationModifiers() const; [[nodiscard]] std::vector GetFollowingDeclarationModifiers() const; [[nodiscard]] const std::vector& GetArrayIndices() const; [[nodiscard]] bool IsArray() const; diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.cpp b/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.cpp index 2d732aaf..87ee7576 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.cpp +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.cpp @@ -26,6 +26,18 @@ MemberInformation* StructureComputations::GetDynamicMember() const return nullptr; } +bool StructureComputations::HasNonDynamicMember() const +{ + for (const auto& member : m_info->m_ordered_members) + { + const MemberComputations memberComputations(member.get()); + if (!memberComputations.ShouldIgnore() && !memberComputations.IsAfterPartialLoad()) + return true; + } + + return false; +} + std::vector StructureComputations::GetUsedMembers() const { std::vector members; diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.h b/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.h index 3c1009e5..23cf1d9d 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.h +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.h @@ -9,6 +9,7 @@ public: [[nodiscard]] bool IsAsset() const; [[nodiscard]] MemberInformation* GetDynamicMember() const; + [[nodiscard]] bool HasNonDynamicMember() const; [[nodiscard]] std::vector GetUsedMembers() const; private: diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp index 0049413b..cc01f66c 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -70,6 +70,13 @@ namespace PrintFillStructMethodDeclaration(type->m_info); } } + for (const auto* type : m_env.m_used_types) + { + if (type->m_info && type->m_type == type->m_info->m_definition && StructureComputations(type->m_info).GetDynamicMember()) + { + PrintDynamicFillMethodDeclaration(type->m_info); + } + } } for (const auto* type : m_env.m_used_types) { @@ -174,6 +181,14 @@ namespace PrintFillStructMethod(type->m_info); } } + for (const auto* type : m_env.m_used_types) + { + if (type->m_info && type->m_type == type->m_info->m_definition && StructureComputations(type->m_info).GetDynamicMember()) + { + LINE("") + PrintDynamicFillMethod(*type->m_info); + } + } } for (const auto* type : m_env.m_used_types) { @@ -240,7 +255,12 @@ namespace void PrintFillStructMethodDeclaration(const StructureInformation* info) const { - LINEF("void FillStruct_{1}(const ZoneStreamFillReadAccessor& fillAccessor);", LoaderClassName(m_env.m_asset), MakeSafeTypeName(info->m_definition)) + LINEF("void FillStruct_{0}(const ZoneStreamFillReadAccessor& fillAccessor);", MakeSafeTypeName(info->m_definition)) + } + + void PrintDynamicFillMethodDeclaration(const StructureInformation* info) const + { + LINEF("size_t LoadDynamicFill_{0}(const ZoneStreamFillReadAccessor& parentFill);", MakeSafeTypeName(info->m_definition)) } void PrintHeaderPtrArrayLoadMethodDeclaration(const DataDefinition* def) const @@ -255,6 +275,7 @@ namespace void PrintHeaderLoadMethodDeclaration(const StructureInformation* info) const { + const StructureComputations computations(info); LINEF("void Load_{0}(bool atStreamStart);", MakeSafeTypeName(info->m_definition)) } @@ -563,21 +584,124 @@ namespace } } + void PrintFillStruct_Member_Condition_Struct(const StructureInformation& structInfo, const MemberInformation& member) + { + if (member.m_condition) + { + LINEF("if ({0})", MakeEvaluation(member.m_condition.get())) + LINE("{") + m_intendation++; + + PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); + + m_intendation--; + LINE("}") + } + else + { + + PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); + } + } + + void PrintFillStruct_Member_Condition_Union(const StructureInformation& structInfo, const MemberInformation& member) + { + const MemberComputations computations(&member); + + if (computations.IsFirstUsedMember()) + { + if (member.m_condition) + { + LINEF("if ({0})", MakeEvaluation(member.m_condition.get())) + LINE("{") + m_intendation++; + + PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); + + m_intendation--; + LINE("}") + } + else + { + PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); + } + } + else if (computations.IsLastUsedMember()) + { + if (member.m_condition) + { + LINEF("else if ({0})", MakeEvaluation(member.m_condition.get())) + LINE("{") + m_intendation++; + + PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); + + m_intendation--; + LINE("}") + } + else + { + LINE("else") + LINE("{") + m_intendation++; + + PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); + + m_intendation--; + LINE("}") + } + } + else + { + if (member.m_condition) + { + LINEF("else if ({0})", MakeEvaluation(member.m_condition.get())) + LINE("{") + m_intendation++; + + PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); + + m_intendation--; + LINE("}") + } + else + { + LINEF("#error Middle member of union2 must have condition ({0})", member.m_member->m_name) + } + } + } + void PrintFillStruct_Struct(const StructureInformation& info) { const auto* dynamicMember = StructureComputations(&info).GetDynamicMember(); - for (const auto& member : info.m_ordered_members) - { - const MemberComputations computations(member.get()); - if (computations.ShouldIgnore() || member.get() == dynamicMember) - continue; - PrintFillStruct_Member(info, *member, DeclarationModifierComputations(member.get()), 0u); - } - - // Always fill dynamic members last if (dynamicMember) - PrintFillStruct_Member(info, *dynamicMember, DeclarationModifierComputations(dynamicMember), 0u); + { + for (const auto& member : info.m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore() || member.get() == dynamicMember) + continue; + + PrintFillStruct_Member(info, *member, DeclarationModifierComputations(member.get()), 0u); + } + + if (info.m_definition->GetType() == DataDefinitionType::UNION) + PrintFillStruct_Member_Condition_Union(info, *dynamicMember); + else + PrintFillStruct_Member_Condition_Struct(info, *dynamicMember); + } + else + { + for (const auto& member : info.m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore()) + continue; + + PrintFillStruct_Member(info, *member, DeclarationModifierComputations(member.get()), 0u); + } + } } void PrintFillStructMethod(const StructureInformation* info) @@ -595,13 +719,197 @@ namespace LINE("}") } + void PrintDynamicOversize_DynamicMember(const StructureInformation& info, const MemberInformation& member) const + { + const MemberComputations memberComputations(&member); + const DeclarationModifierComputations modifier(&member); + + if (memberComputations.HasDynamicArraySize()) + { + LINEF("const auto dynamicArrayEntries = static_cast({0});", MakeEvaluation(modifier.GetDynamicArraySizeEvaluation())) + LINEF("m_stream.AppendToFill(dynamicArrayEntries * {0});", member.m_member->m_type_declaration->m_type->GetSize()) + LINEF("return dynamicArrayEntries * sizeof({0}{1}) + offsetof({2}, {3});", + MakeTypeDecl(member.m_member->m_type_declaration.get()), + MakeFollowingReferences(modifier.GetAllDeclarationModifiers()), + info.m_definition->GetFullName(), + member.m_member->m_name) + } + else if (member.m_type && StructureComputations(member.m_type).GetDynamicMember()) + { + LINEF("return LoadDynamicFill_{0}(fillAccessor.AtOffset({1})) + offsetof({2}, {3});", + MakeSafeTypeName(member.m_type->m_definition), + member.m_member->m_offset, + info.m_definition->GetFullName(), + member.m_member->m_name) + } + else + { + LINEF("m_stream.AppendToFill({0});", member.m_member->m_type_declaration->GetSize()) + LINEF("return sizeof({0}{1}) + offsetof({2}, {3});", + MakeTypeDecl(member.m_member->m_type_declaration.get()), + MakeFollowingReferences(modifier.GetAllDeclarationModifiers()), + info.m_definition->GetFullName(), + member.m_member->m_name) + } + } + + void DynamicOverSize_Struct_Condition(const StructureInformation& info, const MemberInformation& member) + { + if (member.m_condition) + { + LINEF("if ({0})", MakeEvaluation(member.m_condition.get())) + LINE("{") + m_intendation++; + + PrintFillStruct_Member(info, member, DeclarationModifierComputations(&member), 0u); + + m_intendation--; + LINE("}") + } + else + { + + PrintFillStruct_Member(info, member, DeclarationModifierComputations(&member), 0u); + } + } + + void PrintDynamicOversize_Struct(const StructureInformation& info) + { + const StructureComputations structureComputations(&info); + const auto dynamicMember = structureComputations.GetDynamicMember(); + + LINEF("const auto fillAccessor = m_stream.AppendToFill({0}).AtOffset(parentFill.Offset());", dynamicMember->m_member->m_offset) + LINE("") + + for (const auto& member : info.m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore() || computations.IsDynamicMember()) + continue; + + DynamicOverSize_Struct_Condition(info, *member); + } + + LINE("") + + PrintDynamicOversize_DynamicMember(info, *dynamicMember); + } + + void PrintDynamicOversize_Union(const StructureInformation& info) + { + LINE("const auto& fillAccessor = parentFill;") + + for (const auto& member : info.m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore()) + continue; + + if (computations.IsFirstUsedMember()) + { + LINE("") + if (member->m_condition) + { + LINEF("if ({0})", MakeEvaluation(member->m_condition.get())) + LINE("{") + m_intendation++; + + PrintDynamicOversize_DynamicMember(info, *member); + + m_intendation--; + LINE("}") + } + else + { + PrintDynamicOversize_DynamicMember(info, *member); + } + } + else if (computations.IsLastUsedMember()) + { + if (member->m_condition) + { + LINEF("else if ({0})", MakeEvaluation(member->m_condition.get())) + LINE("{") + m_intendation++; + + PrintDynamicOversize_DynamicMember(info, *member); + + m_intendation--; + LINE("}") + } + else + { + LINE("else") + LINE("{") + m_intendation++; + + PrintDynamicOversize_DynamicMember(info, *member); + + m_intendation--; + LINE("}") + } + } + else + { + if (member->m_condition) + { + LINEF("else if ({0})", MakeEvaluation(member->m_condition.get())) + LINE("{") + m_intendation++; + + PrintDynamicOversize_DynamicMember(info, *member); + + m_intendation--; + LINE("}") + } + else + { + LINEF("#error Middle member of union must have condition ({0})", member->m_member->m_name) + } + } + } + } + + void PrintDynamicFillMethod(const StructureInformation& info) + { + LINEF("size_t {0}::LoadDynamicFill_{1}(const ZoneStreamFillReadAccessor& parentFill)", + LoaderClassName(m_env.m_asset), + MakeSafeTypeName(info.m_definition)) + + LINE("{") + m_intendation++; + + LINEF("{0} temp{1};", info.m_definition->GetFullName(), MakeSafeTypeName(info.m_definition)) + LINEF("{0} = &temp{1};", MakeTypeVarName(info.m_definition), MakeSafeTypeName(info.m_definition)) + + if (info.m_definition->GetType() == DataDefinitionType::UNION) + { + PrintDynamicOversize_Union(info); + } + else + { + PrintDynamicOversize_Struct(info); + } + + m_intendation--; + LINE("}") + } + void PrintLoadPtrArrayMethod_Loading(const DataDefinition* def, const StructureInformation* info) const { - LINEF("*{0} = m_stream.{1}<{2}>({3});", - MakeTypePtrVarName(def), - m_env.m_architecture_mismatch ? "AllocOutOfBlock" : "Alloc", - def->GetFullName(), - def->GetAlignment()) + if (info && !info->m_has_matching_cross_platform_structure && StructureComputations(info).GetDynamicMember()) + { + LINEF("const auto allocSize = LoadDynamicFill_{0}(m_stream.LoadWithFill(0));", MakeSafeTypeName(def)) + LINEF("*{0} = static_cast<{1}*>(m_stream.AllocOutOfBlock({2}, allocSize));", MakeTypePtrVarName(def), def->GetFullName(), def->GetAlignment()) + } + else + { + LINEF("*{0} = m_stream.{1}<{2}>({3});", + MakeTypePtrVarName(def), + m_env.m_architecture_mismatch ? "AllocOutOfBlock" : "Alloc", + def->GetFullName(), + def->GetAlignment()) + } if (info && !info->m_is_leaf) { @@ -911,7 +1219,7 @@ namespace } } - void LoadMember_DynamicArray(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) const + void LoadMember_DynamicArray(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) { if (member->m_type && !member->m_type->m_is_leaf) { @@ -923,11 +1231,22 @@ namespace } else if (info->m_has_matching_cross_platform_structure) { + if (m_env.m_architecture_mismatch) + { + LINE("if (atStreamStart)") + m_intendation++; + } + LINEF("m_stream.Load<{0}{1}>({2}, {3});", MakeTypeDecl(member->m_member->m_type_declaration.get()), MakeFollowingReferences(modifier.GetFollowingDeclarationModifiers()), MakeMemberAccess(info, member, modifier), MakeEvaluation(modifier.GetDynamicArraySizeEvaluation())) + + if (m_env.m_architecture_mismatch) + { + m_intendation--; + } } } @@ -974,6 +1293,7 @@ namespace if (member->m_type && !member->m_type->m_is_leaf && !computations.IsInRuntimeBlock()) { LINEF("{0} = {1};", MakeTypeVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier)) + LINEF("Load_{0}(true);", MakeSafeTypeName(member->m_type->m_definition)) if (member->m_type->m_post_load_action) @@ -1000,7 +1320,7 @@ namespace void LoadMember_TypeCheck(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier, - const MemberLoadType loadType) const + const MemberLoadType loadType) { if (member->m_is_string) { @@ -1076,6 +1396,13 @@ namespace && ((member.m_type && !member.m_type->m_has_matching_cross_platform_structure) || loadType == MemberLoadType::POINTER_ARRAY); } + [[nodiscard]] bool + ShouldPreAllocDynamic(const MemberInformation& member, const DeclarationModifierComputations& modifier, const MemberLoadType loadType) const + { + return ShouldAllocOutOfBlock(member, loadType) && (modifier.IsSinglePointer() || modifier.IsPointerArray()) && member.m_type + && StructureComputations(member.m_type).GetDynamicMember(); + } + void LoadMember_Alloc(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier, @@ -1091,35 +1418,55 @@ namespace const auto followingReferences = MakeFollowingReferences(modifier.GetFollowingDeclarationModifiers()); const auto allocOutOfBlock = ShouldAllocOutOfBlock(*member, loadType); + const auto preAllocDynamic = ShouldPreAllocDynamic(*member, modifier, loadType); - LINE_STARTF("{0} = m_stream.", MakeMemberAccess(info, member, modifier)) - if (allocOutOfBlock) - LINE_MIDDLE("AllocOutOfBlock") - else - LINE_MIDDLE("Alloc") - - LINE_MIDDLEF("<{0}{1}>(", typeDecl, followingReferences) - - // This used to use `alignof()` to calculate alignment but due to inconsistencies between compilers and bugs discovered in MSVC - // (Alignment specified via `__declspec(align())` showing as correct via intellisense but is incorrect when compiled for types that have a larger - // alignment than the specified value) this was changed to make ZoneCodeGenerator calculate what is supposed to be used as alignment when - // allocating. This is more reliable when being used with different compilers and the value used can be seen in the source code directly - if (member->m_alloc_alignment) + if (preAllocDynamic) { - LINE_MIDDLE(MakeEvaluation(member->m_alloc_alignment.get())) + LINEF("const auto allocSize = LoadDynamicFill_{0}(m_stream.LoadWithFill(0));", MakeSafeTypeName(member->m_type->m_definition)) + LINE_STARTF("{0} = static_cast<{1}{2}*>(m_stream.AllocOutOfBlock(", MakeMemberAccess(info, member, modifier), typeDecl, followingReferences) + + if (member->m_alloc_alignment) + { + LINE_MIDDLE(MakeEvaluation(member->m_alloc_alignment.get())) + } + else + { + LINE_MIDDLEF("{0}", modifier.GetAlignment()) + } + + LINE_ENDF(", allocSize));", member->m_type->m_definition->GetFullName()) } else { - LINE_MIDDLEF("{0}", modifier.GetAlignment()) + LINE_STARTF("{0} = m_stream.", MakeMemberAccess(info, member, modifier)) + if (allocOutOfBlock) + LINE_MIDDLE("AllocOutOfBlock") + else + LINE_MIDDLE("Alloc") + + LINE_MIDDLEF("<{0}{1}>(", typeDecl, followingReferences) + + // This used to use `alignof()` to calculate alignment but due to inconsistencies between compilers and bugs discovered in MSVC + // (Alignment specified via `__declspec(align())` showing as correct via intellisense but is incorrect when compiled for types that have a + // larger alignment than the specified value) this was changed to make ZoneCodeGenerator calculate what is supposed to be used as alignment when + // allocating. This is more reliable when being used with different compilers and the value used can be seen in the source code directly + if (member->m_alloc_alignment) + { + LINE_MIDDLE(MakeEvaluation(member->m_alloc_alignment.get())) + } + else + { + LINE_MIDDLEF("{0}", modifier.GetAlignment()) + } + + if (allocOutOfBlock && modifier.IsArrayPointer()) + LINE_MIDDLEF(", {0}", MakeEvaluation(modifier.GetArrayPointerCountEvaluation())) + else if (allocOutOfBlock && modifier.IsPointerArray()) + LINE_MIDDLEF(", {0}", MakeEvaluation(modifier.GetPointerArrayCountEvaluation())) + + LINE_END(");") } - if (allocOutOfBlock && modifier.IsArrayPointer()) - LINE_MIDDLEF(", {0}", MakeEvaluation(modifier.GetArrayPointerCountEvaluation())) - else if (allocOutOfBlock && modifier.IsPointerArray()) - LINE_MIDDLEF(", {0}", MakeEvaluation(modifier.GetPointerArrayCountEvaluation())) - - LINE_END(");") - const MemberComputations computations(member); if (computations.IsInTempBlock()) { @@ -1380,7 +1727,7 @@ namespace { const MemberComputations computations(member); - if (computations.IsFirstMember()) + if (computations.IsFirstUsedMember()) { LINE("") if (member->m_condition) @@ -1399,7 +1746,7 @@ namespace LoadMember_Reference(info, member, DeclarationModifierComputations(member)); } } - else if (computations.IsLastMember()) + else if (computations.IsLastUsedMember()) { if (member->m_condition) { @@ -1464,13 +1811,18 @@ namespace { const StructureComputations computations(info); LINEF("void {0}::Load_{1}(const bool atStreamStart)", LoaderClassName(m_env.m_asset), info->m_definition->m_name) + LINE("{") m_intendation++; LINEF("assert({0} != nullptr);", MakeTypeVarName(info->m_definition)) const auto* dynamicMember = computations.GetDynamicMember(); - if (!(info->m_definition->GetType() == DataDefinitionType::UNION && dynamicMember)) + if (!info->m_has_matching_cross_platform_structure && dynamicMember && !info->m_non_embedded_reference_exists) + { + LINE("assert(!atStreamStart);") + } + else if (!(info->m_definition->GetType() == DataDefinitionType::UNION && dynamicMember)) { LINE("") LINE("if (atStreamStart)") @@ -1495,7 +1847,18 @@ namespace } else { - LINEF("FillStruct_{0}(m_stream.LoadWithFill({1}));", MakeSafeTypeName(info->m_definition), info->m_definition->GetSize()) + if (dynamicMember == nullptr) + { + LINEF("FillStruct_{0}(m_stream.LoadWithFill({1}));", MakeSafeTypeName(info->m_definition), info->m_definition->GetSize()) + } + else if (info->m_non_embedded_reference_exists) + { + LINEF("FillStruct_{0}(m_stream.GetLastFill());", MakeSafeTypeName(info->m_definition)) + } + else + { + LINE("assert(false);") + } } m_intendation--; } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp index f3426a67..f5add84c 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp @@ -655,7 +655,7 @@ namespace { const MemberComputations computations(member); - if (computations.IsFirstMember()) + if (computations.IsFirstUsedMember()) { LINE("") if (member->m_condition) @@ -674,7 +674,7 @@ namespace MarkMember_Reference(info, member, DeclarationModifierComputations(member)); } } - else if (computations.IsLastMember()) + else if (computations.IsLastUsedMember()) { if (member->m_condition) { diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index 44c5a98c..dc27cb35 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -874,7 +874,7 @@ namespace { const MemberComputations computations(member); - if (computations.IsFirstMember()) + if (computations.IsFirstUsedMember()) { LINE("") if (member->m_condition) @@ -893,7 +893,7 @@ namespace WriteMember_Reference(info, member, DeclarationModifierComputations(member)); } } - else if (computations.IsLastMember()) + else if (computations.IsLastUsedMember()) { if (member->m_condition) { diff --git a/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp b/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp index d0a16e10..19c9db93 100644 --- a/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp +++ b/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp @@ -175,7 +175,7 @@ void ContentLoader::Load() #ifdef ARCH_x86 m_stream.LoadDataRaw(&assetList, sizeof(assetList)); #else - auto fillAccessor = m_stream.LoadWithFill(16u); + const auto fillAccessor = m_stream.LoadWithFill(16u); varScriptStringList = &varXAssetList->stringList; fillAccessor.Fill(varScriptStringList->count, 0u); fillAccessor.FillPtr(varScriptStringList->strings, 4u); diff --git a/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp b/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp index a63425df..aedddf8e 100644 --- a/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp +++ b/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp @@ -11,11 +11,13 @@ #include #include -ZoneStreamFillReadAccessor::ZoneStreamFillReadAccessor(const void* dataBuffer, void* blockBuffer, const size_t bufferSize, const unsigned pointerByteCount) +ZoneStreamFillReadAccessor::ZoneStreamFillReadAccessor( + const void* dataBuffer, void* blockBuffer, const size_t bufferSize, const unsigned pointerByteCount, const size_t offset) : m_data_buffer(dataBuffer), m_block_buffer(blockBuffer), m_buffer_size(bufferSize), - m_pointer_byte_count(pointerByteCount) + m_pointer_byte_count(pointerByteCount), + m_offset(offset) { // Otherwise we cannot insert alias assert(m_pointer_byte_count <= sizeof(uintptr_t)); @@ -23,9 +25,17 @@ ZoneStreamFillReadAccessor::ZoneStreamFillReadAccessor(const void* dataBuffer, v ZoneStreamFillReadAccessor ZoneStreamFillReadAccessor::AtOffset(const size_t offset) const { - assert(offset < m_buffer_size); - return ZoneStreamFillReadAccessor( - static_cast(m_data_buffer) + offset, static_cast(m_block_buffer) + offset, m_buffer_size - offset, m_pointer_byte_count); + assert(offset <= m_buffer_size); + return ZoneStreamFillReadAccessor(static_cast(m_data_buffer) + offset, + static_cast(m_block_buffer) + offset, + m_buffer_size - offset, + m_pointer_byte_count, + m_offset + offset); +} + +size_t ZoneStreamFillReadAccessor::Offset() const +{ + return m_offset; } void ZoneStreamFillReadAccessor::InsertPointerRedirect(const uintptr_t aliasValue, const size_t offset) const @@ -117,7 +127,7 @@ namespace auto* block = m_block_stack.top(); - Align(align); + Align(*block, align); if (m_block_offsets[block->m_index] > block->m_buffer_size) throw BlockOverflowException(block); @@ -134,7 +144,7 @@ namespace auto* block = m_block_stack.top(); - Align(align); + Align(*block, align); if (m_block_offsets[block->m_index] > block->m_buffer_size) throw BlockOverflowException(block); @@ -163,23 +173,7 @@ namespace // Theoretically ptr should always be at the current block offset. assert(dst == &block->m_buffer[m_block_offsets[block->m_index]]); - switch (block->m_type) - { - case XBlockType::BLOCK_TYPE_TEMP: - case XBlockType::BLOCK_TYPE_NORMAL: - m_stream.Load(dst, size); - break; - - case XBlockType::BLOCK_TYPE_RUNTIME: - std::memset(dst, 0, size); - break; - - case XBlockType::BLOCK_TYPE_DELAY: - assert(false); - break; - } - - IncBlockPos(size); + LoadDataFromBlock(*block, dst, size); } else { @@ -218,7 +212,7 @@ namespace ZoneStreamFillReadAccessor LoadWithFill(const size_t size) override { - m_fill_buffer.reserve(size); + m_fill_buffer.resize(size); auto* dst = m_fill_buffer.data(); // If no block has been pushed, load raw @@ -227,65 +221,78 @@ namespace const auto* block = m_block_stack.top(); auto* blockBufferForFill = &block->m_buffer[m_block_offsets[block->m_index]]; - switch (block->m_type) - { - case XBlockType::BLOCK_TYPE_TEMP: - case XBlockType::BLOCK_TYPE_NORMAL: - m_stream.Load(dst, size); - break; + LoadDataFromBlock(*block, dst, size); - case XBlockType::BLOCK_TYPE_RUNTIME: - std::memset(dst, 0, size); - break; - - case XBlockType::BLOCK_TYPE_DELAY: - assert(false); - break; - } - - IncBlockPos(size); - - return ZoneStreamFillReadAccessor(dst, blockBufferForFill, size, m_pointer_byte_count); + return ZoneStreamFillReadAccessor(dst, blockBufferForFill, size, m_pointer_byte_count, 0); } m_stream.Load(dst, size); - return ZoneStreamFillReadAccessor(dst, nullptr, size, m_pointer_byte_count); + return ZoneStreamFillReadAccessor(dst, nullptr, size, m_pointer_byte_count, 0); + } + + ZoneStreamFillReadAccessor AppendToFill(const size_t appendSize) override + { + const auto appendOffset = m_fill_buffer.size(); + m_fill_buffer.resize(appendOffset + appendSize); + auto* dst = m_fill_buffer.data() + appendOffset; + + const auto newTotalSize = appendOffset + appendSize; + // If no block has been pushed, load raw + if (!m_block_stack.empty()) + { + const auto* block = m_block_stack.top(); + auto* blockBufferForFill = &block->m_buffer[m_block_offsets[block->m_index]] - appendOffset; + + LoadDataFromBlock(*block, dst, appendSize); + + return ZoneStreamFillReadAccessor(m_fill_buffer.data(), blockBufferForFill, newTotalSize, m_pointer_byte_count, 0); + } + + m_stream.Load(dst, appendSize); + return ZoneStreamFillReadAccessor(m_fill_buffer.data(), nullptr, newTotalSize, m_pointer_byte_count, 0); + } + + ZoneStreamFillReadAccessor GetLastFill() override + { + assert(!m_fill_buffer.empty()); + + if (!m_block_stack.empty()) + { + const auto* block = m_block_stack.top(); + auto* blockBufferForFill = &block->m_buffer[m_block_offsets[block->m_index]] - m_fill_buffer.size(); + + return ZoneStreamFillReadAccessor(m_fill_buffer.data(), blockBufferForFill, m_fill_buffer.size(), m_pointer_byte_count, 0); + } + + return ZoneStreamFillReadAccessor(m_fill_buffer.data(), nullptr, m_fill_buffer.size(), m_pointer_byte_count, 0); } void* InsertPointerNative() override { - m_block_stack.push(m_insert_block); - // Alignment of pointer should always be its size - Align(m_pointer_byte_count); + Align(*m_insert_block, m_pointer_byte_count); if (m_block_offsets[m_insert_block->m_index] + m_pointer_byte_count > m_insert_block->m_buffer_size) throw BlockOverflowException(m_insert_block); auto* ptr = static_cast(&m_insert_block->m_buffer[m_block_offsets[m_insert_block->m_index]]); - IncBlockPos(m_pointer_byte_count); - - m_block_stack.pop(); + IncBlockPos(*m_insert_block, m_pointer_byte_count); return ptr; } uintptr_t InsertPointerAliasLookup() override { - m_block_stack.push(m_insert_block); - // Alignment of pointer should always be its size - Align(m_pointer_byte_count); + Align(*m_insert_block, m_pointer_byte_count); if (m_block_offsets[m_insert_block->m_index] + m_pointer_byte_count > m_insert_block->m_buffer_size) throw BlockOverflowException(m_insert_block); auto* ptr = static_cast(&m_insert_block->m_buffer[m_block_offsets[m_insert_block->m_index]]); - IncBlockPos(m_pointer_byte_count); - - m_block_stack.pop(); + IncBlockPos(*m_insert_block, m_pointer_byte_count); const auto newLookupIndex = static_cast(m_alias_lookup.size()) + 1; m_alias_lookup.emplace_back(nullptr); @@ -410,24 +417,37 @@ namespace } private: - void IncBlockPos(const size_t size) + void LoadDataFromBlock(const XBlock& block, void* dst, const size_t size) { - assert(!m_block_stack.empty()); + switch (block.m_type) + { + case XBlockType::BLOCK_TYPE_TEMP: + case XBlockType::BLOCK_TYPE_NORMAL: + m_stream.Load(dst, size); + break; - if (m_block_stack.empty()) - return; + case XBlockType::BLOCK_TYPE_RUNTIME: + std::memset(dst, 0, size); + break; - const auto* block = m_block_stack.top(); - m_block_offsets[block->m_index] += size; + case XBlockType::BLOCK_TYPE_DELAY: + assert(false); + break; + } + + IncBlockPos(block, size); } - void Align(const unsigned align) + void IncBlockPos(const XBlock& block, const size_t size) { - assert(!m_block_stack.empty()); + m_block_offsets[block.m_index] += size; + } + void Align(const XBlock& block, const unsigned align) + { if (align > 0) { - const auto blockIndex = m_block_stack.top()->m_index; + const auto blockIndex = block.m_index; m_block_offsets[blockIndex] = utils::Align(m_block_offsets[blockIndex], static_cast(align)); } } diff --git a/src/ZoneLoading/Zone/Stream/ZoneInputStream.h b/src/ZoneLoading/Zone/Stream/ZoneInputStream.h index 260d6627..4f22c665 100644 --- a/src/ZoneLoading/Zone/Stream/ZoneInputStream.h +++ b/src/ZoneLoading/Zone/Stream/ZoneInputStream.h @@ -14,9 +14,10 @@ class ZoneStreamFillReadAccessor { public: - ZoneStreamFillReadAccessor(const void* dataBuffer, void* blockBuffer, size_t bufferSize, unsigned pointerByteCount); + ZoneStreamFillReadAccessor(const void* dataBuffer, void* blockBuffer, size_t bufferSize, unsigned pointerByteCount, size_t offset); [[nodiscard]] ZoneStreamFillReadAccessor AtOffset(size_t offset) const; + [[nodiscard]] size_t Offset() const; template void Fill(T& value, const size_t offset) const { @@ -48,6 +49,7 @@ private: void* m_block_buffer; size_t m_buffer_size; unsigned m_pointer_byte_count; + size_t m_offset; }; class ZoneInputStream : public IZoneStream @@ -104,6 +106,8 @@ public: virtual void LoadDataInBlock(void* dst, size_t size) = 0; virtual void LoadNullTerminated(void* dst) = 0; virtual ZoneStreamFillReadAccessor LoadWithFill(size_t size) = 0; + virtual ZoneStreamFillReadAccessor AppendToFill(size_t appendSize) = 0; + virtual ZoneStreamFillReadAccessor GetLastFill() = 0; template void Load(T* dst) {