OpenAssetTools/src/ObjLoading/StructuredDataDef/Parsing/StructuredDataDefSizeCalculator.cpp

155 lines
5.1 KiB
C++

#include "StructuredDataDefSizeCalculator.h"
#include <cassert>
#include <sstream>
#include "Utils/Alignment.h"
#include "Utils/ClassUtils.h"
using namespace sdd;
SizeCalculationException::SizeCalculationException(std::string message)
: m_message(std::move(message))
{
}
const std::string& SizeCalculationException::Message() const
{
return m_message;
}
char const* SizeCalculationException::what() const
{
return m_message.c_str();
}
class StructuredDataDefSizeCalculatorInternal
{
CommonStructuredDataDef& m_def;
std::vector<CommonStructuredDataType> m_type_stack;
std::vector<bool> m_struct_in_calculation;
std::vector<bool> m_struct_calculated;
std::vector<bool> m_indexed_array_calculated;
std::vector<bool> m_enumed_array_calculated;
_NORETURN void ThrowCircularDependencyException(const size_t structIndex) const
{
assert(structIndex < m_def.m_structs.size());
std::ostringstream ss;
ss << "Circular dependencies detected: ";
auto foundDependencyChainStart = false;
for(const auto& type : m_type_stack)
{
if(foundDependencyChainStart)
{
if(type.m_category == CommonStructuredDataTypeCategory::STRUCT)
{
assert(type.m_info.type_index < m_def.m_structs.size());
ss << " -> " << m_def.m_structs[type.m_info.type_index]->m_name;
}
}
else if (type.m_category == CommonStructuredDataTypeCategory::STRUCT && type.m_info.type_index == structIndex)
{
foundDependencyChainStart = true;
ss << m_def.m_structs[structIndex]->m_name;
}
}
ss << " -> " << m_def.m_structs[structIndex]->m_name;
throw SizeCalculationException(ss.str());
}
void CalculateForStruct(const size_t index, CommonStructuredDataStruct& _struct)
{
if (m_struct_calculated[index])
return;
if (m_struct_in_calculation[index])
ThrowCircularDependencyException(index);
m_struct_in_calculation[index] = true;
m_type_stack.emplace_back(CommonStructuredDataTypeCategory::STRUCT, index);
auto currentOffset = 0u;
for(auto& property : _struct.m_properties)
{
CalculateForType(property.m_type);
currentOffset = utils::Align(currentOffset, property.m_type.GetAlignmentInBits());
// Currently set offset is the padding since the start of the struct
property.m_offset_in_bits += currentOffset;
currentOffset += property.m_type.GetSizeInBits(m_def);
}
currentOffset = utils::Align(currentOffset, 8u);
_struct.m_size_in_byte += currentOffset / 8;
m_struct_calculated[index] = true;
m_type_stack.pop_back();
}
void CalculateForIndexedArray(CommonStructuredDataIndexedArray& indexedArray)
{
CalculateForType(indexedArray.m_array_type);
indexedArray.m_element_size_in_bits = indexedArray.m_array_type.GetSizeInBits(m_def);
}
void CalculateForEnumedArray(CommonStructuredDataEnumedArray& enumedArray)
{
CalculateForType(enumedArray.m_array_type);
enumedArray.m_element_size_in_bits = enumedArray.m_array_type.GetSizeInBits(m_def);
}
void CalculateForType(const CommonStructuredDataType type)
{
switch (type.m_category)
{
case CommonStructuredDataTypeCategory::STRUCT:
assert(type.m_info.type_index < m_def.m_structs.size());
CalculateForStruct(type.m_info.type_index, *m_def.m_structs[type.m_info.type_index]);
break;
case CommonStructuredDataTypeCategory::INDEXED_ARRAY:
assert(type.m_info.type_index < m_def.m_indexed_arrays.size());
CalculateForIndexedArray(m_def.m_indexed_arrays[type.m_info.type_index]);
break;
case CommonStructuredDataTypeCategory::ENUM_ARRAY:
assert(type.m_info.type_index < m_def.m_enumed_arrays.size());
CalculateForEnumedArray(m_def.m_enumed_arrays[type.m_info.type_index]);
break;
default:
break;
}
}
public:
explicit StructuredDataDefSizeCalculatorInternal(CommonStructuredDataDef& def)
: m_def(def),
m_struct_in_calculation(def.m_structs.size()),
m_struct_calculated(def.m_structs.size()),
m_indexed_array_calculated(def.m_indexed_arrays.size()),
m_enumed_array_calculated(def.m_enumed_arrays.size())
{
}
void CalculateSizesAndOffsets()
{
auto index = 0u;
for (auto& _struct : m_def.m_structs)
CalculateForStruct(index++, *_struct);
for (auto& indexedArray : m_def.m_indexed_arrays)
CalculateForIndexedArray(indexedArray);
for (auto& enumedArray : m_def.m_enumed_arrays)
CalculateForEnumedArray(enumedArray);
}
};
void StructuredDataDefSizeCalculator::CalculateSizesAndOffsetsForDef(CommonStructuredDataDef& def)
{
StructuredDataDefSizeCalculatorInternal calculator(def);
calculator.CalculateSizesAndOffsets();
}