summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/compiler-core/slang-json-diagnostic-defs.h1
-rw-r--r--source/compiler-core/slang-json-native.cpp46
-rw-r--r--source/compiler-core/slang-json-parser.cpp4
-rw-r--r--source/compiler-core/slang-json-value.cpp29
-rw-r--r--source/compiler-core/slang-json-value.h8
-rw-r--r--source/core/slang-array-view.h22
-rw-r--r--source/core/slang-rtti-info.h2
-rw-r--r--source/core/slang-rtti-util.cpp589
-rw-r--r--source/core/slang-rtti-util.h11
-rw-r--r--source/slang/slang.cpp6
-rw-r--r--tools/slang-unit-test/unit-test-json-native.cpp53
11 files changed, 746 insertions, 25 deletions
diff --git a/source/compiler-core/slang-json-diagnostic-defs.h b/source/compiler-core/slang-json-diagnostic-defs.h
index 23bea9b79..4733a3291 100644
--- a/source/compiler-core/slang-json-diagnostic-defs.h
+++ b/source/compiler-core/slang-json-diagnostic-defs.h
@@ -40,5 +40,6 @@ DIAGNOSTIC(20009, Error, unableToConvertField, "unable to convert field '$0' in
DIAGNOSTIC(20010, Error, fieldNotFound, "field '$0' not found in type '$1'")
DIAGNOSTIC(20011, Error, fieldNotDefinedOnType, "field '$0' not defined on type '$1'")
DIAGNOSTIC(20011, Error, fieldRequiredOnType, "field '$0' required on '$1'")
+DIAGNOSTIC(20012, Error, tooManyElementsForArray, "too many elements ($0) for array array. Max allowed is $1")
#undef DIAGNOSTIC
diff --git a/source/compiler-core/slang-json-native.cpp b/source/compiler-core/slang-json-native.cpp
index 5b2fb5db4..9c972eba3 100644
--- a/source/compiler-core/slang-json-native.cpp
+++ b/source/compiler-core/slang-json-native.cpp
@@ -203,6 +203,33 @@ SlangResult JSONToNativeConverter::convert(const JSONValue& in, const RttiInfo*
return SLANG_OK;
}
+ case RttiInfo::Kind::FixedArray:
+ {
+ if (in.getKind() != JSONValue::Kind::Array)
+ {
+ return SLANG_FAIL;
+ }
+ const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(rttiInfo);
+ const auto elementType = fixedArrayRttiInfo->m_elementType;
+ const Index elementCount = Index(fixedArrayRttiInfo->m_elementCount);
+ const auto elementSize = elementType->m_size;
+
+ auto srcArray = m_container->getArray(in);
+
+ if (srcArray.getCount() > elementCount)
+ {
+ m_sink->diagnose(in.loc, JSONDiagnostics::tooManyElementsForArray, srcArray.getCount(), elementCount);
+ return SLANG_FAIL;
+ }
+
+ Byte* dstEles = (Byte*)out;
+ for (Index i = 0; i < elementCount; ++i, dstEles += elementSize)
+ {
+ SLANG_RETURN_ON_FAIL(convert(srcArray[i], elementType, dstEles));
+ }
+
+ return SLANG_OK;
+ }
case RttiInfo::Kind::Dictionary:
{
// We can *only* serialize this into a straight JSON object iff the key is a string-like type
@@ -341,6 +368,25 @@ SlangResult NativeToJSONConverter::convert(const RttiInfo* rttiInfo, const void*
out = m_container->createArray(dstValues.getBuffer(), count);
return SLANG_OK;
}
+ case RttiInfo::Kind::FixedArray:
+ {
+ const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(rttiInfo);
+ const auto elementType = fixedArrayRttiInfo->m_elementType;
+ const auto elementCount = Index(fixedArrayRttiInfo->m_elementCount);
+ const auto elementSize = elementType->m_size;
+
+ List<JSONValue> dstValues;
+ dstValues.setCount(elementCount);
+
+ const Byte* src = (const Byte*)in;
+ for (Index i = 0; i < elementCount; ++i, src += elementSize)
+ {
+ SLANG_RETURN_ON_FAIL(convert(elementType, src, dstValues[i]));
+ }
+
+ out = m_container->createArray(dstValues.getBuffer(), elementCount);
+ return SLANG_OK;
+ }
case RttiInfo::Kind::Dictionary:
{
const DictionaryRttiInfo* listRttiInfo = static_cast<const DictionaryRttiInfo*>(rttiInfo);
diff --git a/source/compiler-core/slang-json-parser.cpp b/source/compiler-core/slang-json-parser.cpp
index fe9a0f580..52e46258a 100644
--- a/source/compiler-core/slang-json-parser.cpp
+++ b/source/compiler-core/slang-json-parser.cpp
@@ -308,6 +308,8 @@ void JSONWriter::endObject(SourceLoc loc)
m_state = m_stack.getLast();
m_stack.removeLast();
+
+ _postValue();
}
void JSONWriter::startArray(SourceLoc loc)
@@ -343,6 +345,8 @@ void JSONWriter::endArray(SourceLoc loc)
m_state = m_stack.getLast();
m_stack.removeLast();
+
+ _postValue();
}
void JSONWriter::addUnquotedKey(const UnownedStringSlice& key, SourceLoc loc)
diff --git a/source/compiler-core/slang-json-value.cpp b/source/compiler-core/slang-json-value.cpp
index 1e18bee39..4fad3764f 100644
--- a/source/compiler-core/slang-json-value.cpp
+++ b/source/compiler-core/slang-json-value.cpp
@@ -957,8 +957,7 @@ JSONBuilder::JSONBuilder(JSONContainer* container, Flags flags):
{
m_state.m_kind = State::Kind::Root;
m_state.m_startIndex = 0;
-
- m_keyValue.reset();
+ m_state.resetKey();
m_rootValue.reset();
}
@@ -968,9 +967,9 @@ void JSONBuilder::reset()
// Reset the state
m_state.m_kind = State::Kind::Root;
m_state.m_startIndex = 0;
+ m_state.resetKey();
// Clear the work values
- m_keyValue.reset();
m_rootValue.reset();
// Clear the lists
@@ -1037,17 +1036,24 @@ void JSONBuilder::_add(const JSONValue& value)
}
case State::Kind::Object:
{
- m_keyValue.value = value;
- const Index index = _findKeyIndex(m_keyValue.key);
+ SLANG_ASSERT(m_state.hasKey());
+
+ JSONKeyValue keyValue;
+ keyValue.key = m_state.m_key;
+ keyValue.keyLoc = m_state.m_keyLoc;
+ keyValue.value = value;
+
+ const Index index = _findKeyIndex(keyValue.key);
if (index >= 0)
{
- m_keyValues[index] = m_keyValue;
+ m_keyValues[index] = keyValue;
}
else
{
- m_keyValues.add(m_keyValue);
+ m_keyValues.add(keyValue);
}
- m_keyValue.reset();
+
+ m_state.resetKey();
break;
}
}
@@ -1059,6 +1065,7 @@ void JSONBuilder::startObject(SourceLoc loc)
m_state.m_kind = State::Kind::Object;
m_state.m_startIndex = m_keyValues.getCount();
m_state.m_loc = loc;
+ m_state.resetKey();
}
void JSONBuilder::endObject(SourceLoc loc)
@@ -1082,6 +1089,7 @@ void JSONBuilder::startArray(SourceLoc loc)
m_state.m_kind = State::Kind::Array;
m_state.m_startIndex = m_values.getCount();
m_state.m_loc = loc;
+ m_state.resetKey();
}
void JSONBuilder::endArray(SourceLoc loc)
@@ -1110,9 +1118,8 @@ void JSONBuilder::addQuotedKey(const UnownedStringSlice& key, SourceLoc loc)
void JSONBuilder::addUnquotedKey(const UnownedStringSlice& key, SourceLoc loc)
{
- SLANG_ASSERT(m_keyValue.key == JSONKey(0));
- m_keyValue.key = m_container->getKey(key);
- m_keyValue.keyLoc = loc;
+ SLANG_ASSERT(!m_state.hasKey());
+ m_state.setKey(m_container->getKey(key), loc);
}
void JSONBuilder::addLexemeValue(JSONTokenType type, const UnownedStringSlice& value, SourceLoc loc)
diff --git a/source/compiler-core/slang-json-value.h b/source/compiler-core/slang-json-value.h
index 2eae4ae08..119479285 100644
--- a/source/compiler-core/slang-json-value.h
+++ b/source/compiler-core/slang-json-value.h
@@ -334,9 +334,15 @@ protected:
Object,
Array,
};
+ void setKey(JSONKey key, SourceLoc loc) { m_key = key; m_keyLoc = loc; }
+ void resetKey() { m_key = JSONKey(0); m_keyLoc = SourceLoc(); }
+ bool hasKey() const { return m_key != JSONKey(0); }
+
Kind m_kind;
Index m_startIndex;
SourceLoc m_loc;
+ JSONKey m_key;
+ SourceLoc m_keyLoc;
};
void _popState();
@@ -353,8 +359,6 @@ protected:
State m_state;
JSONContainer* m_container;
-
- JSONKeyValue m_keyValue;
JSONValue m_rootValue;
StringBuilder m_work;
diff --git a/source/core/slang-array-view.h b/source/core/slang-array-view.h
index c67a53337..6f5277f5f 100644
--- a/source/core/slang-array-view.h
+++ b/source/core/slang-array-view.h
@@ -120,10 +120,10 @@ namespace Slang
};
template<typename T>
- ConstArrayView<T> makeConstArrayView(const T& obj)
+ ConstArrayView<T> makeConstArrayViewSingle(const T& obj)
{
return ConstArrayView<T>(&obj, 1);
- }
+ }
template<typename T>
ConstArrayView<T> makeConstArrayView(const T* buffer, Index count)
@@ -131,6 +131,13 @@ namespace Slang
return ConstArrayView<T>(buffer, count);
}
+ template<typename T, size_t N>
+ ConstArrayView<T> makeConstArrayView(const T (&arr)[N])
+ {
+ return ConstArrayView<T>(arr, Index(N));
+ }
+
+
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArrayView !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
template<typename T>
@@ -165,10 +172,10 @@ namespace Slang
};
template<typename T>
- ArrayView<T> makeArrayView(T& obj)
+ ArrayView<T> makeArrayViewSingle(T& obj)
{
return ArrayView<T>(&obj, 1);
- }
+ }
template<typename T>
ArrayView<T> makeArrayView(T* buffer, Index count)
@@ -176,6 +183,13 @@ namespace Slang
return ArrayView<T>(buffer, count);
}
+ template<typename T, size_t N>
+ ArrayView<T> makeArrayView(T (&arr)[N])
+ {
+ return ArrayView<T>(arr, Index(N));
+ }
+
+
}
#endif
diff --git a/source/core/slang-rtti-info.h b/source/core/slang-rtti-info.h
index c1fe1810f..09a4bf657 100644
--- a/source/core/slang-rtti-info.h
+++ b/source/core/slang-rtti-info.h
@@ -112,7 +112,7 @@ struct RttiInfo
static bool isIntegral(RttiInfo::Kind kind) { return Index(kind) >= Index(RttiInfo::Kind::I32) && Index(kind) <= Index(RttiInfo::Kind::U64); }
static bool isFloat(RttiInfo::Kind kind) { return kind == RttiInfo::Kind::F32 || kind == RttiInfo::Kind::F64; }
- static bool isBuiltIn(RttiInfo::Kind kind) { return kind == RttiInfo::Kind::I32 || kind == RttiInfo::Kind::Bool; }
+ static bool isBuiltIn(RttiInfo::Kind kind) { return Index(kind) >= Index(RttiInfo::Kind::I32) && Index(kind) <= Index(RttiInfo::Kind::Bool); }
static bool isNamed(RttiInfo::Kind kind) { return Index(kind) >= Index(RttiInfo::Kind::Struct) && Index(kind) <= Index(RttiInfo::Kind::Enum); }
bool isIntegral() const { return isIntegral(m_kind); }
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
diff --git a/source/core/slang-rtti-util.h b/source/core/slang-rtti-util.h
index d514d1980..741e1f847 100644
--- a/source/core/slang-rtti-util.h
+++ b/source/core/slang-rtti-util.h
@@ -6,7 +6,6 @@
namespace Slang {
struct RttiUtil
{
-
static SlangResult setInt(int64_t value, const RttiInfo* rttiInfo, void* dst);
static int64_t getInt64(const RttiInfo* rttiInfo, const void* src);
@@ -23,6 +22,16 @@ struct RttiUtil
/// Set a list count
static SlangResult setListCount(const RttiInfo* elementType, void* dst, Index count);
+ /// Returns if the type can be zero initialized
+ static bool canZeroInit(const RttiInfo* type);
+ /// Returns true if the type needs dtor
+ static bool hasDtor(const RttiInfo* type);
+ /// Returns true if we can memcpy to copy
+ static bool canMemCpy(const RttiInfo* type);
+
+ static void ctorArray(const RttiInfo* rttiInfo, void* inDst, ptrdiff_t stride, Index count);
+ static void copyArray(const RttiInfo* rttiInfo, void* inDst, const void* inSrc, ptrdiff_t stride, Index count);
+ static void dtorArray(const RttiInfo* rttiInfo, void* inDst, ptrdiff_t stride, Index count);
};
} // namespace Slang
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index ccc1404f1..4696d50af 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -1077,7 +1077,7 @@ SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::getContainerType(
ConstantBufferType* cbType = getASTBuilder()->create<ConstantBufferType>();
cbType->elementType = type;
cbType->declRef = getASTBuilder()->getBuiltinDeclRef(
- "ConstantBuffer", makeConstArrayView<Val*>(static_cast<Val*>(type)));
+ "ConstantBuffer", makeConstArrayViewSingle<Val*>(static_cast<Val*>(type)));
containerTypeReflection = cbType;
}
break;
@@ -1086,7 +1086,7 @@ SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::getContainerType(
ParameterBlockType* pbType = getASTBuilder()->create<ParameterBlockType>();
pbType->elementType = type;
pbType->declRef = getASTBuilder()->getBuiltinDeclRef(
- "ParameterBlock", makeConstArrayView<Val*>(static_cast<Val*>(type)));
+ "ParameterBlock", makeConstArrayViewSingle<Val*>(static_cast<Val*>(type)));
containerTypeReflection = pbType;
}
break;
@@ -1096,7 +1096,7 @@ SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::getContainerType(
getASTBuilder()->create<HLSLStructuredBufferType>();
sbType->elementType = type;
sbType->declRef = getASTBuilder()->getBuiltinDeclRef(
- "HLSLStructuredBufferType", makeConstArrayView<Val*>(static_cast<Val*>(type)));
+ "HLSLStructuredBufferType", makeConstArrayViewSingle<Val*>(static_cast<Val*>(type)));
containerTypeReflection = sbType;
}
break;
diff --git a/tools/slang-unit-test/unit-test-json-native.cpp b/tools/slang-unit-test/unit-test-json-native.cpp
index 1d2085751..6636cc04a 100644
--- a/tools/slang-unit-test/unit-test-json-native.cpp
+++ b/tools/slang-unit-test/unit-test-json-native.cpp
@@ -11,13 +11,42 @@ using namespace Slang;
namespace { // anonymous
+struct OtherStruct
+{
+ typedef OtherStruct ThisType;
+
+ bool operator==(const ThisType& rhs) const { return f == rhs.f && value == rhs.value; }
+ bool operator!=(const ThisType& rhs) const { return !(*this == rhs); }
+
+ float f = 1.0f;
+ String value;
+
+ static const StructRttiInfo g_rttiInfo;
+};
+
+static const StructRttiInfo _makeOtherStructRtti()
+{
+ OtherStruct obj;
+ StructRttiBuilder builder(&obj, "OtherStruct", nullptr);
+ builder.addField("f", &obj.f);
+ builder.addField("value", &obj.value);
+ return builder.make();
+}
+/* static */const StructRttiInfo OtherStruct::g_rttiInfo = _makeOtherStructRtti();
+
struct SomeStruct
{
typedef SomeStruct ThisType;
bool operator==(const ThisType& rhs) const
{
- return a == rhs.a && b == rhs.b && s == rhs.s && list == rhs.list;
+ return a == rhs.a &&
+ b == rhs.b &&
+ s == rhs.s &&
+ list == rhs.list &&
+ boolValue == rhs.boolValue &&
+ structList == rhs.structList &&
+ makeConstArrayView(fixedArray) == makeConstArrayView(rhs.fixedArray);
}
bool operator!=(const ThisType& rhs) const { return !(*this == rhs); }
@@ -25,12 +54,15 @@ struct SomeStruct
float b = 2.0f;
String s;
List<String> list;
+ bool boolValue = false;
+
+ List<OtherStruct> structList;
+
+ int fixedArray[2] = { 0, 0 };
static const StructRttiInfo g_rttiInfo;
};
-} // anonymous
-
static const StructRttiInfo _makeSomeStructRtti()
{
SomeStruct obj;
@@ -40,11 +72,17 @@ static const StructRttiInfo _makeSomeStructRtti()
builder.addField("b", &obj.b);
builder.addField("s", &obj.s);
builder.addField("list", &obj.list);
+ builder.addField("boolValue", &obj.boolValue);
+ builder.addField("structList", &obj.structList);
+ builder.addField("fixedArray", &obj.fixedArray);
return builder.make();
}
/* static */const StructRttiInfo SomeStruct::g_rttiInfo = _makeSomeStructRtti();
+} // anonymous
+
+
static SlangResult _check()
{
// Convert into a JSON string
@@ -52,6 +90,15 @@ static SlangResult _check()
SomeStruct s;
s.list.add("Hello!");
s.s = "There";
+ s.boolValue = true;
+
+ OtherStruct o;
+ o.f = 27.5f;
+ o.value = "This works!";
+
+ s.structList.add(o);
+ s.fixedArray[1] = 8;
+ s.fixedArray[0] = -1;
// Try serializing it out