diff options
| -rw-r--r-- | source/compiler-core/slang-json-diagnostic-defs.h | 1 | ||||
| -rw-r--r-- | source/compiler-core/slang-json-native.cpp | 46 | ||||
| -rw-r--r-- | source/compiler-core/slang-json-parser.cpp | 4 | ||||
| -rw-r--r-- | source/compiler-core/slang-json-value.cpp | 29 | ||||
| -rw-r--r-- | source/compiler-core/slang-json-value.h | 8 | ||||
| -rw-r--r-- | source/core/slang-array-view.h | 22 | ||||
| -rw-r--r-- | source/core/slang-rtti-info.h | 2 | ||||
| -rw-r--r-- | source/core/slang-rtti-util.cpp | 589 | ||||
| -rw-r--r-- | source/core/slang-rtti-util.h | 11 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 6 | ||||
| -rw-r--r-- | tools/slang-unit-test/unit-test-json-native.cpp | 53 |
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 = ©Array; + 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 |
