#include "slang-rtti-util.h" namespace Slang { /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiTypeFuncs Impls * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ struct ListFuncs { static void ctorArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); // We don't care about the element type, as we can just initialize them all as List // const ListRttiInfo* listRttiInfo = static_cast(rttiInfo); typedef List Type; Type* dst = (Type*)inDst; for (Index i = 0; i < count; ++i) { new (dst + i) Type; } } static void copyArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count) { SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); const ListRttiInfo* listRttiInfo = static_cast(rttiInfo); const auto elementType = listRttiInfo->m_elementType; // We need to get the type funcs auto typeFuncs = typeMap->getFuncsForType(elementType); SLANG_ASSERT(typeFuncs.isValid()); // We need a type that we can get information from the list from - List gives us the // functions we need. typedef List Type; Type* dst = (Type*)inDst; const Type* src = (const Type*)inSrc; for (Index i = 0; i < count; ++i) { auto& dstList = dst[i]; auto& srcList = src[i]; const Index srcCount = srcList.getCount(); if (srcCount > dstList.getCount()) { // Allocate new memory const Index dstCapacity = dstList.getCapacity(); void* oldBuffer = dstList.detachBuffer(); void* newBuffer = ::malloc(count * elementType->m_size); // Initialize it all first typeFuncs.ctorArray(typeMap, elementType, newBuffer, count); typeFuncs.copyArray(typeMap, elementType, newBuffer, oldBuffer, count); // Attach the new buffer dstList.attachBuffer((Byte*)newBuffer, count, count); // Free the old buffer if (oldBuffer) { typeFuncs.dtorArray(typeMap, elementType, oldBuffer, dstCapacity); ::free(oldBuffer); } } else { typeFuncs.copyArray( typeMap, elementType, dstList.getBuffer(), srcList.getBuffer(), srcCount); dstList.unsafeShrinkToCount(srcCount); } } } static void dtorArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) { SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); const ListRttiInfo* listRttiInfo = static_cast(rttiInfo); const auto elementType = listRttiInfo->m_elementType; // We need to get the type funcs auto typeFuncs = typeMap->getFuncsForType(elementType); SLANG_ASSERT(typeFuncs.isValid()); typedef List Type; Type* dst = (Type*)inDst; for (Index i = 0; i < count; ++i) { auto& dstList = dst[i]; const Index capacity = dstList.getCapacity(); Byte* buffer = dstList.detachBuffer(); if (buffer) { typeFuncs.dtorArray(typeMap, elementType, buffer, capacity); ::free(buffer); } } } static RttiTypeFuncs getFuncs() { RttiTypeFuncs funcs; funcs.copyArray = ©Array; funcs.dtorArray = &dtorArray; funcs.ctorArray = &ctorArray; return funcs; } }; struct StructFuncs { static void ctorArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) { SLANG_UNUSED(typeMap); SLANG_UNUSED(rttiInfo); SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); // We don't care about the element type, as we can just initialize them all as List // const ListRttiInfo* listRttiInfo = static_cast(rttiInfo); typedef List Type; Type* dst = (Type*)inDst; for (Index i = 0; i < count; ++i) { new (dst + i) Type; } } static void copyArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count) { SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); const ListRttiInfo* listRttiInfo = static_cast(rttiInfo); const auto elementType = listRttiInfo->m_elementType; // We need to get the type funcs auto typeFuncs = typeMap->getFuncsForType(elementType); SLANG_ASSERT(typeFuncs.isValid()); // We need a type that we can get information from the list from - List gives us the // functions we need. typedef List Type; Type* dst = (Type*)inDst; const Type* src = (const Type*)inSrc; for (Index i = 0; i < count; ++i) { auto& dstList = dst[i]; auto& srcList = src[i]; const Index srcCount = srcList.getCount(); if (srcCount > dstList.getCount()) { // Allocate new memory const Index dstCapacity = dstList.getCapacity(); void* oldBuffer = dstList.detachBuffer(); void* newBuffer = ::malloc(count * elementType->m_size); // Initialize it all first typeFuncs.ctorArray(typeMap, elementType, newBuffer, count); typeFuncs.copyArray(typeMap, elementType, newBuffer, oldBuffer, count); // Attach the new buffer dstList.attachBuffer((Byte*)newBuffer, count, count); // Free the old buffer if (oldBuffer) { typeFuncs.dtorArray(typeMap, elementType, oldBuffer, dstCapacity); ::free(oldBuffer); } } else { typeFuncs.copyArray( typeMap, elementType, dstList.getBuffer(), srcList.getBuffer(), srcCount); dstList.unsafeShrinkToCount(srcCount); } } } static void dtorArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) { SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List); const ListRttiInfo* listRttiInfo = static_cast(rttiInfo); const auto elementType = listRttiInfo->m_elementType; // We need to get the type funcs auto typeFuncs = typeMap->getFuncsForType(elementType); SLANG_ASSERT(typeFuncs.isValid()); typedef List Type; Type* dst = (Type*)inDst; for (Index i = 0; i < count; ++i) { auto& dstList = dst[i]; const Index capacity = dstList.getCapacity(); Byte* buffer = dstList.detachBuffer(); if (buffer) { typeFuncs.dtorArray(typeMap, elementType, buffer, capacity); ::free(buffer); } } } static RttiTypeFuncs getFuncs() { RttiTypeFuncs funcs; funcs.copyArray = ©Array; funcs.dtorArray = &dtorArray; funcs.ctorArray = &ctorArray; return funcs; } }; struct StructArrayFuncs { static void ctorArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) { return RttiUtil::ctorArray(typeMap, rttiInfo, inDst, rttiInfo->m_size, count); } static void copyArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count) { return RttiUtil::copyArray(typeMap, rttiInfo, inDst, inSrc, rttiInfo->m_size, count); } static void dtorArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, Index count) { return RttiUtil::dtorArray(typeMap, rttiInfo, inDst, rttiInfo->m_size, count); } static RttiTypeFuncs getFuncs() { RttiTypeFuncs funcs; funcs.copyArray = copyArray; funcs.dtorArray = dtorArray; funcs.ctorArray = ctorArray; return funcs; } }; /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ RttiTypeFuncs RttiUtil::getDefaultTypeFuncs(const RttiInfo* rttiInfo) { if (rttiInfo->isBuiltIn()) { switch (rttiInfo->m_size) { case 1: return GetRttiTypeFuncsForZeroPod::getFuncs(); case 2: return GetRttiTypeFuncsForZeroPod::getFuncs(); case 4: return GetRttiTypeFuncsForZeroPod::getFuncs(); case 8: return GetRttiTypeFuncsForZeroPod::getFuncs(); } return RttiTypeFuncs::makeEmpty(); } switch (rttiInfo->m_kind) { case RttiInfo::Kind::String: return GetRttiTypeFuncs::getFuncs(); case RttiInfo::Kind::UnownedStringSlice: return GetRttiTypeFuncs::getFuncs(); case RttiInfo::Kind::List: return ListFuncs::getFuncs(); case RttiInfo::Kind::Struct: case RttiInfo::Kind::Optional: return StructArrayFuncs::getFuncs(); default: break; } return RttiTypeFuncs::makeEmpty(); } /* static */ SlangResult RttiUtil::setInt(int64_t value, const RttiInfo* rttiInfo, void* dst) { SLANG_ASSERT(rttiInfo->isIntegral()); // We could check ranges are appropriate, but for now we just write. // Passing in rttiInfo allows for other more complex types to be econverted switch (rttiInfo->m_kind) { case RttiInfo::Kind::I32: *(int32_t*)dst = int32_t(value); break; case RttiInfo::Kind::U32: *(uint32_t*)dst = uint32_t(value); break; case RttiInfo::Kind::I64: *(int64_t*)dst = int64_t(value); break; case RttiInfo::Kind::U64: *(uint64_t*)dst = uint64_t(value); break; default: return SLANG_FAIL; } return SLANG_OK; } /* static */ int64_t RttiUtil::getInt64(const RttiInfo* rttiInfo, const void* src) { SLANG_ASSERT(rttiInfo->isIntegral()); switch (rttiInfo->m_kind) { case RttiInfo::Kind::I32: return *(const int32_t*)src; case RttiInfo::Kind::U32: return *(const uint32_t*)src; case RttiInfo::Kind::I64: return *(const int64_t*)src; case RttiInfo::Kind::U64: return *(const uint64_t*)src; default: break; } SLANG_ASSERT(!"Not integral!"); return -1; } /* static */ double RttiUtil::asDouble(const RttiInfo* rttiInfo, const void* src) { if (rttiInfo->isIntegral()) { return (double)getInt64(rttiInfo, src); } else if (rttiInfo->isFloat()) { switch (rttiInfo->m_kind) { case RttiInfo::Kind::F32: return *(const float*)src; case RttiInfo::Kind::F64: return *(const double*)src; default: break; } } SLANG_ASSERT(!"Cannot convert to float"); return 0.0; } /* static */ SlangResult RttiUtil::setFromDouble(double v, const RttiInfo* rttiInfo, void* dst) { if (rttiInfo->isIntegral()) { return setInt(int64_t(v), rttiInfo, dst); } else if (rttiInfo->isFloat()) { switch (rttiInfo->m_kind) { case RttiInfo::Kind::F32: *(float*)dst = float(v); return SLANG_OK; case RttiInfo::Kind::F64: *(double*)dst = v; return SLANG_OK; default: break; } } return SLANG_FAIL; } /* static */ bool RttiUtil::asBool(const RttiInfo* rttiInfo, const void* src) { if (rttiInfo->m_kind == RttiInfo::Kind::Bool) { return *(const bool*)src; } if (rttiInfo->isIntegral()) { return getInt64(rttiInfo, src) != 0; } else if (rttiInfo->isFloat()) { return asDouble(rttiInfo, src) != 0.0; } SLANG_ASSERT(!"Cannot convert to bool"); return false; } static int64_t _getIntDefaultValue(RttiDefaultValue value) { switch (value) { default: case RttiDefaultValue::Normal: return 0; case RttiDefaultValue::One: return 1; case RttiDefaultValue::MinusOne: return -1; } } static bool _isStructDefault(const StructRttiInfo* type, const void* src) { if (type->m_super) { if (!_isStructDefault(type->m_super, src)) { return false; } } const Byte* base = (const Byte*)src; const Index count = type->m_fieldCount; for (Index i = 0; i < count; ++i) { const auto& field = type->m_fields[i]; const RttiDefaultValue defaultValue = RttiDefaultValue(field.m_flags & uint8_t(RttiDefaultValue::Mask)); if (!RttiUtil::isDefault(defaultValue, field.m_type, base + field.m_offset)) { return false; } } return true; } /* static */ bool RttiUtil::isDefault( RttiDefaultValue defaultValue, const RttiInfo* rttiInfo, const void* src) { if (rttiInfo->isIntegral()) { const auto value = getInt64(rttiInfo, src); return _getIntDefaultValue(defaultValue) == value; } else if (rttiInfo->isFloat()) { const auto value = asDouble(rttiInfo, src); return _getIntDefaultValue(defaultValue) == value; } switch (rttiInfo->m_kind) { case RttiInfo::Kind::Invalid: return true; case RttiInfo::Kind::Bool: return *(const bool*)src == (_getIntDefaultValue(defaultValue) != 0); case RttiInfo::Kind::String: { return ((const String*)src)->getLength() == 0; } case RttiInfo::Kind::UnownedStringSlice: { return ((const UnownedStringSlice*)src)->getLength() == 0; } case RttiInfo::Kind::Struct: { return _isStructDefault(static_cast(rttiInfo), src); } case RttiInfo::Kind::Enum: { SLANG_ASSERT(!"Not implemented yet"); return false; } case RttiInfo::Kind::List: { const auto& v = *(const List*)src; return v.getCount() == 0; } case RttiInfo::Kind::Dictionary: { const auto& v = *(const Dictionary*)src; return v.getCount() == 0; } case RttiInfo::Kind::Other: { const OtherRttiInfo* otherRttiInfo = static_cast(rttiInfo); return otherRttiInfo->m_isDefaultFunc && otherRttiInfo->m_isDefaultFunc(rttiInfo, src); } case RttiInfo::Kind::Optional: { return *(const bool*)src == (_getIntDefaultValue(defaultValue) != 0); } default: { return false; } } } /* static */ SlangResult RttiUtil::setListCount( RttiTypeFuncsMap* typeMap, const RttiInfo* elementType, void* dst, Index count) { // NOTE! The following only works because List has capacity initialized members, and // setting the count if it is <= capacity just sets the count (ie things aren't released(!)). List& dstList = *(List*)dst; const Index oldCount = dstList.getCount(); if (oldCount == count) { return SLANG_OK; } if (count < oldCount) { dstList.unsafeShrinkToCount(count); return SLANG_OK; } const auto typeFuncs = typeMap->getFuncsForType(elementType); SLANG_ASSERT(typeFuncs.isValid()); const Index dstCapacity = dstList.getCapacity(); void* oldBuffer = dstList.detachBuffer(); void* newBuffer = ::malloc(count * elementType->m_size); // Initialize it all first typeFuncs.ctorArray(typeMap, elementType, newBuffer, count); typeFuncs.copyArray(typeMap, elementType, newBuffer, oldBuffer, oldCount); // Attach the new buffer dstList.attachBuffer((Byte*)newBuffer, count, count); // Free the old buffer if (oldBuffer) { typeFuncs.dtorArray(typeMap, elementType, oldBuffer, dstCapacity); ::free(oldBuffer); } return SLANG_OK; } /* static */ bool RttiUtil::canMemCpy(const RttiInfo* type) { switch (type->m_kind) { case RttiInfo::Kind::RefPtr: case RttiInfo::Kind::String: case RttiInfo::Kind::Invalid: { return false; } case RttiInfo::Kind::UnownedStringSlice: case RttiInfo::Kind::Ptr: case RttiInfo::Kind::Enum: { return true; } case RttiInfo::Kind::FixedArray: { const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast(type); return canMemCpy(fixedArrayRttiInfo->m_elementType); } case RttiInfo::Kind::Other: case RttiInfo::Kind::List: case RttiInfo::Kind::Dictionary: { return false; } case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast(type); do { // If all the fields can be zero inited, struct can be const auto fieldCount = structRttiInfo->m_fieldCount; const auto fields = structRttiInfo->m_fields; for (Index i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; if (!canMemCpy(field.m_type)) { return false; } } structRttiInfo = structRttiInfo->m_super; } while (structRttiInfo); return true; } case RttiInfo::Kind::Optional: { const OptionalRttiInfo* optionalRttiInfo = static_cast(type); return canMemCpy(optionalRttiInfo->m_elementType); } default: { return type->isBuiltIn(); } } } /* static */ bool RttiUtil::canZeroInit(const RttiInfo* type) { switch (type->m_kind) { case RttiInfo::Kind::Invalid: { return true; } case RttiInfo::Kind::String: { // As it stands we can zero init String, but if impl changes that might not // be true return true; } case RttiInfo::Kind::UnownedStringSlice: case RttiInfo::Kind::Ptr: case RttiInfo::Kind::RefPtr: case RttiInfo::Kind::Enum: { return true; } case RttiInfo::Kind::FixedArray: { const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast(type); return canZeroInit(fixedArrayRttiInfo->m_elementType); } case RttiInfo::Kind::Other: case RttiInfo::Kind::List: case RttiInfo::Kind::Dictionary: { return false; } case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast(type); do { // If all the fields can be zero inited, struct can be const auto fieldCount = structRttiInfo->m_fieldCount; const auto fields = structRttiInfo->m_fields; for (Index i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; if (!canZeroInit(field.m_type)) { return false; } } structRttiInfo = structRttiInfo->m_super; } while (structRttiInfo); return true; } case RttiInfo::Kind::Optional: { const OptionalRttiInfo* optionalRttiInfo = static_cast(type); return canZeroInit(optionalRttiInfo->m_elementType); } default: { return type->isBuiltIn(); } } } /* static */ bool RttiUtil::hasDtor(const RttiInfo* type) { switch (type->m_kind) { case RttiInfo::Kind::Invalid: { return false; } case RttiInfo::Kind::String: case RttiInfo::Kind::RefPtr: { return true; } case RttiInfo::Kind::UnownedStringSlice: case RttiInfo::Kind::Ptr: case RttiInfo::Kind::Enum: { return false; } case RttiInfo::Kind::FixedArray: { const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast(type); return hasDtor(fixedArrayRttiInfo->m_elementType); } case RttiInfo::Kind::Other: case RttiInfo::Kind::List: case RttiInfo::Kind::Dictionary: { return true; } case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast(type); do { // If all the fields can be zero inited, struct can be const auto fieldCount = structRttiInfo->m_fieldCount; const auto fields = structRttiInfo->m_fields; for (Index i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; if (hasDtor(field.m_type)) { return true; } } structRttiInfo = structRttiInfo->m_super; } while (structRttiInfo); return false; } case RttiInfo::Kind::Optional: { const OptionalRttiInfo* optionalRttiInfo = static_cast(type); return hasDtor(optionalRttiInfo->m_elementType); } default: { return !type->isBuiltIn(); } } } /* static */ void RttiUtil::ctorArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, ptrdiff_t stride, Index count) { if (count <= 0) { return; } Byte* dst = (Byte*)inDst; if (canZeroInit(rttiInfo)) { if (stride == rttiInfo->m_size) { ::memset(dst, 0, count * stride); } else { const size_t size = rttiInfo->m_size; for (Index i = 0; i < count; ++i, dst += stride) { ::memset(dst, 0, size); } } return; } switch (rttiInfo->m_kind) { case RttiInfo::Kind::FixedArray: { const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast(rttiInfo); if (fixedArrayRttiInfo->m_size == stride) { // It's contiguous do in one go ctorArray( typeMap, fixedArrayRttiInfo->m_elementType, dst, fixedArrayRttiInfo->m_elementType->m_size, fixedArrayRttiInfo->m_elementCount * count); } else { // Do it in array runs for (Index i = 0; i < count; ++i, dst += stride) { ctorArray( typeMap, fixedArrayRttiInfo->m_elementType, dst, fixedArrayRttiInfo->m_elementType->m_size, fixedArrayRttiInfo->m_elementCount); } } return; } case RttiInfo::Kind::List: case RttiInfo::Kind::Dictionary: case RttiInfo::Kind::Other: { auto funcs = typeMap->getFuncsForType(rttiInfo); SLANG_ASSERT(funcs.isValid()); const OtherRttiInfo* otherRttiInfo = static_cast(rttiInfo); if (otherRttiInfo->m_size == stride) { funcs.ctorArray(typeMap, rttiInfo, dst, count); } else { // Do it in array runs for (Index i = 0; i < count; ++i, dst += stride) { funcs.ctorArray(typeMap, rttiInfo, dst, 1); } } return; } case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast(rttiInfo); do { // If all the fields can be zero inited, struct can be const auto fieldCount = structRttiInfo->m_fieldCount; const auto fields = structRttiInfo->m_fields; for (Index i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; ctorArray(typeMap, field.m_type, dst + field.m_offset, stride, count); } structRttiInfo = structRttiInfo->m_super; } while (structRttiInfo); return; } case RttiInfo::Kind::Optional: { const OptionalRttiInfo* optionalRttiInfo = static_cast(rttiInfo); ctorArray(typeMap, GetRttiInfo::get(), dst, stride, count); ctorArray( typeMap, optionalRttiInfo->m_elementType, dst + optionalRttiInfo->m_valueOffset, stride, count); return; } } SLANG_ASSERT(!"Unexpected"); } /* static */ void RttiUtil::copyArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, const void* inSrc, ptrdiff_t stride, Index count) { if (count <= 0) { return; } const size_t size = rttiInfo->m_size; Byte* dst = (Byte*)inDst; const Byte* src = (const Byte*)inSrc; if (canMemCpy(rttiInfo)) { if (stride == ptrdiff_t(size)) { ::memcpy(dst, src, count * stride); } else { for (Index i = 0; i < count; ++i, dst += stride, src += stride) { ::memcpy(dst, src, size); } } return; } switch (rttiInfo->m_kind) { case RttiInfo::Kind::FixedArray: { const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast(rttiInfo); const auto elementType = fixedArrayRttiInfo->m_elementType; const auto elementSize = elementType->m_size; const auto elementCount = fixedArrayRttiInfo->m_elementCount; if (ptrdiff_t(size) == stride) { // It's contiguous do in one go copyArray(typeMap, elementType, dst, src, elementSize, elementCount * count); } else { // Do it in array runs for (Index i = 0; i < count; ++i, dst += stride, src += stride) { copyArray(typeMap, elementType, dst, src, elementSize, elementCount); } } return; } case RttiInfo::Kind::List: case RttiInfo::Kind::Dictionary: case RttiInfo::Kind::Other: { auto funcs = typeMap->getFuncsForType(rttiInfo); SLANG_ASSERT(funcs.isValid()); const OtherRttiInfo* otherRttiInfo = static_cast(rttiInfo); if (otherRttiInfo->m_size == stride) { funcs.copyArray(typeMap, rttiInfo, dst, src, count); } else { for (Index i = 0; i < count; ++i, dst += stride, src += stride) { funcs.copyArray(typeMap, rttiInfo, dst, src, 1); } } return; } case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast(rttiInfo); do { // If all the fields can be zero inited, struct can be const auto fieldCount = structRttiInfo->m_fieldCount; const auto fields = structRttiInfo->m_fields; for (Index i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; copyArray( typeMap, field.m_type, dst + field.m_offset, src + field.m_offset, stride, count); } structRttiInfo = structRttiInfo->m_super; } while (structRttiInfo); return; } case RttiInfo::Kind::Optional: { const OptionalRttiInfo* optionalRttiInfo = static_cast(rttiInfo); copyArray(typeMap, GetRttiInfo::get(), dst, src, stride, count); copyArray( typeMap, optionalRttiInfo->m_elementType, dst + optionalRttiInfo->m_valueOffset, src + optionalRttiInfo->m_valueOffset, stride, count); return; } } SLANG_ASSERT(!"Unexpected"); } /* static */ void RttiUtil::dtorArray( RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* inDst, ptrdiff_t stride, Index count) { if (count <= 0 || !hasDtor(rttiInfo)) { return; } const size_t size = rttiInfo->m_size; Byte* dst = (Byte*)inDst; switch (rttiInfo->m_kind) { case RttiInfo::Kind::FixedArray: { const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast(rttiInfo); const auto elementType = fixedArrayRttiInfo->m_elementType; const auto elementSize = elementType->m_size; const auto elementCount = fixedArrayRttiInfo->m_elementCount; if (ptrdiff_t(size) == stride) { // It's contiguous do in one go dtorArray(typeMap, elementType, dst, elementSize, elementCount * count); } else { // Do it in array runs for (Index i = 0; i < count; ++i, dst += stride) { dtorArray(typeMap, elementType, dst, elementSize, elementCount); } } return; } case RttiInfo::Kind::List: case RttiInfo::Kind::Dictionary: case RttiInfo::Kind::Other: { auto funcs = typeMap->getFuncsForType(rttiInfo); SLANG_ASSERT(funcs.isValid()); const OtherRttiInfo* otherRttiInfo = static_cast(rttiInfo); if (otherRttiInfo->m_size == stride) { funcs.dtorArray(typeMap, rttiInfo, dst, count); } else { for (Index i = 0; i < count; ++i, dst += stride) { funcs.dtorArray(typeMap, rttiInfo, dst, 1); } } return; } case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast(rttiInfo); do { // If all the fields can be zero inited, struct can be const auto fieldCount = structRttiInfo->m_fieldCount; const auto fields = structRttiInfo->m_fields; for (Index i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; dtorArray(typeMap, field.m_type, dst + field.m_offset, stride, count); } structRttiInfo = structRttiInfo->m_super; } while (structRttiInfo); return; } case RttiInfo::Kind::Optional: { const OptionalRttiInfo* optionalRttiInfo = static_cast(rttiInfo); dtorArray(typeMap, GetRttiInfo::get(), dst, stride, count); dtorArray( typeMap, optionalRttiInfo->m_elementType, dst + optionalRttiInfo->m_valueOffset, stride, count); return; } } SLANG_ASSERT(!"Unexpected"); } } // namespace Slang