summaryrefslogtreecommitdiffstats
path: root/source/core/slang-rtti-util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/core/slang-rtti-util.cpp')
-rw-r--r--source/core/slang-rtti-util.cpp589
1 files changed, 589 insertions, 0 deletions
diff --git a/source/core/slang-rtti-util.cpp b/source/core/slang-rtti-util.cpp
index ed4c32e58..b4b2ddae2 100644
--- a/source/core/slang-rtti-util.cpp
+++ b/source/core/slang-rtti-util.cpp
@@ -317,6 +317,142 @@ struct ListFuncs
}
};
+struct StructFuncs
+{
+
+
+ static void ctorArray(const RttiInfo* rttiInfo, void* inDst, Index count)
+ {
+ 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<Byte>
+ //const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo);
+ typedef List<Byte> Type;
+
+ Type* dst = (Type*)inDst;
+
+ for (Index i = 0; i < count; ++i)
+ {
+ new (dst + i) Type;
+ }
+ }
+ static void copyArray(const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count)
+ {
+ SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List);
+ const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo);
+ const auto elementType = listRttiInfo->m_elementType;
+
+ // We need to get the type funcs
+ auto typeFuncs = RttiUtil::getTypeFuncs(elementType);
+ SLANG_ASSERT(typeFuncs.isValid());
+
+ // We need a type that we can get information from the list from - List<Byte> gives us the functions we need.
+ typedef List<Byte> 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(elementType, newBuffer, count);
+ typeFuncs.copyArray(elementType, newBuffer, oldBuffer, count);
+
+ // Attach the new buffer
+ dstList.attachBuffer((Byte*)newBuffer, count, count);
+
+ // Free the old buffer
+ if (oldBuffer)
+ {
+ typeFuncs.dtorArray(elementType, oldBuffer, dstCapacity);
+
+ ::free(oldBuffer);
+ }
+ }
+ else
+ {
+ typeFuncs.copyArray(elementType, dstList.getBuffer(), srcList.getBuffer(), srcCount);
+ dstList.unsafeShrinkToCount(srcCount);
+ }
+ }
+ }
+
+ static void dtorArray(const RttiInfo* rttiInfo, void* inDst, Index count)
+ {
+ SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List);
+ const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo);
+
+ const auto elementType = listRttiInfo->m_elementType;
+
+ // We need to get the type funcs
+ auto typeFuncs = RttiUtil::getTypeFuncs(elementType);
+ SLANG_ASSERT(typeFuncs.isValid());
+
+ typedef List<Byte> 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(elementType, buffer, capacity);
+ ::free(buffer);
+ }
+ }
+ }
+
+ static RttiTypeFuncs getFuncs()
+ {
+ RttiTypeFuncs funcs;
+ funcs.copyArray = &copyArray;
+ funcs.dtorArray = &dtorArray;
+ funcs.ctorArray = &ctorArray;
+ return funcs;
+ }
+};
+
+static void _ctorStructArray(const RttiInfo* rttiInfo, void* inDst, Index count)
+{
+ RttiUtil::ctorArray(rttiInfo, inDst, rttiInfo->m_size, count);
+}
+
+static void _copyStructArray(const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count)
+{
+ RttiUtil::copyArray(rttiInfo, inDst, inSrc, rttiInfo->m_size, count);
+}
+
+static void _dtorStructArray(const RttiInfo* rttiInfo, void* inDst, Index count)
+{
+ RttiUtil::dtorArray(rttiInfo, inDst, rttiInfo->m_size, count);
+}
+
+static RttiTypeFuncs _getStructTypeFuncs()
+{
+ RttiTypeFuncs funcs;
+ funcs.copyArray = _copyStructArray;
+ funcs.dtorArray = _dtorStructArray;
+ funcs.ctorArray = _ctorStructArray;
+ return funcs;
+}
+
RttiTypeFuncs RttiUtil::getTypeFuncs(const RttiInfo* rttiInfo)
{
if (rttiInfo->isBuiltIn())
@@ -336,6 +472,7 @@ RttiTypeFuncs RttiUtil::getTypeFuncs(const RttiInfo* rttiInfo)
case RttiInfo::Kind::String: return GetRttiTypeFuncs<String>::getFuncs();
case RttiInfo::Kind::UnownedStringSlice: return GetRttiTypeFuncs<UnownedStringSlice>::getFuncs();
case RttiInfo::Kind::List: return ListFuncs::getFuncs();
+ case RttiInfo::Kind::Struct: return _getStructTypeFuncs();
default: break;
}
@@ -389,4 +526,456 @@ RttiTypeFuncs RttiUtil::getTypeFuncs(const RttiInfo* rttiInfo)
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<const FixedArrayRttiInfo*>(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<const StructRttiInfo*>(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;
+ }
+ 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<const FixedArrayRttiInfo*>(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<const StructRttiInfo*>(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;
+ }
+ 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<const FixedArrayRttiInfo*>(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<const StructRttiInfo*>(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;
+ }
+ default:
+ {
+ return !type->isBuiltIn();
+ }
+ }
+}
+
+/* static */void RttiUtil::ctorArray(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<const FixedArrayRttiInfo*>(rttiInfo);
+
+ if (fixedArrayRttiInfo->m_size == stride)
+ {
+ // It's contiguous do in one go
+ ctorArray(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(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 = getTypeFuncs(rttiInfo);
+
+ const OtherRttiInfo* otherRttiInfo = static_cast<const OtherRttiInfo*>(rttiInfo);
+ if (otherRttiInfo->m_size == stride)
+ {
+ funcs.ctorArray(rttiInfo, dst, count);
+ }
+ else
+ {
+ // Do it in array runs
+ for (Index i = 0; i < count; ++i, dst += stride)
+ {
+ funcs.ctorArray(rttiInfo, dst, 1);
+ }
+ }
+ return;
+ }
+ case RttiInfo::Kind::Struct:
+ {
+ const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(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(field.m_type, dst + field.m_offset, stride, count);
+ }
+ structRttiInfo = structRttiInfo->m_super;
+ }
+ while(structRttiInfo);
+
+ return;
+ }
+ }
+
+ SLANG_ASSERT(!"Unexpected");
+}
+
+/* static */void RttiUtil::copyArray(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<const FixedArrayRttiInfo*>(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(elementType, dst, src, elementSize, elementCount * count);
+ }
+ else
+ {
+ // Do it in array runs
+ for (Index i = 0; i < count; ++i, dst += stride, src += stride)
+ {
+ copyArray(elementType, dst, src, elementSize, elementCount);
+ }
+ }
+ return;
+ }
+ case RttiInfo::Kind::List:
+ case RttiInfo::Kind::Dictionary:
+ case RttiInfo::Kind::Other:
+ {
+ auto funcs = getTypeFuncs(rttiInfo);
+
+ const OtherRttiInfo* otherRttiInfo = static_cast<const OtherRttiInfo*>(rttiInfo);
+ if (otherRttiInfo->m_size == stride)
+ {
+ funcs.copyArray(rttiInfo, dst, src, count);
+ }
+ else
+ {
+ for (Index i = 0; i < count; ++i, dst += stride, src += stride)
+ {
+ funcs.copyArray(rttiInfo, dst, src, 1);
+ }
+ }
+ return;
+ }
+ case RttiInfo::Kind::Struct:
+ {
+ const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(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(field.m_type, dst + field.m_offset, src + field.m_offset, stride, count);
+ }
+ structRttiInfo = structRttiInfo->m_super;
+ }
+ while (structRttiInfo);
+
+ return;
+ }
+ }
+
+ SLANG_ASSERT(!"Unexpected");
+}
+
+/* static */void RttiUtil::dtorArray(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<const FixedArrayRttiInfo*>(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(elementType, dst, elementSize, elementCount * count);
+ }
+ else
+ {
+ // Do it in array runs
+ for (Index i = 0; i < count; ++i, dst += stride)
+ {
+ dtorArray(elementType, dst, elementSize, elementCount);
+ }
+ }
+ return;
+ }
+ case RttiInfo::Kind::List:
+ case RttiInfo::Kind::Dictionary:
+ case RttiInfo::Kind::Other:
+ {
+ auto funcs = getTypeFuncs(rttiInfo);
+
+ const OtherRttiInfo* otherRttiInfo = static_cast<const OtherRttiInfo*>(rttiInfo);
+ if (otherRttiInfo->m_size == stride)
+ {
+ funcs.dtorArray(rttiInfo, dst, count);
+ }
+ else
+ {
+ for (Index i = 0; i < count; ++i, dst += stride)
+ {
+ funcs.dtorArray(rttiInfo, dst, 1);
+ }
+ }
+ return;
+ }
+ case RttiInfo::Kind::Struct:
+ {
+ const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(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(field.m_type, dst + field.m_offset, stride, count);
+ }
+ structRttiInfo = structRttiInfo->m_super;
+ }
+ while (structRttiInfo);
+
+ return;
+ }
+ }
+
+ SLANG_ASSERT(!"Unexpected");
+}
+
} // namespace Slang