yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Yong HeLanguageServer: Enhance auto completion for override. (#7465)4d517794e

master
32.8 KiB1159 linesraw
1#include "slang-rtti-util.h"
2
3namespace Slang
4{
5
6/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiTypeFuncs Impls
7 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
8
9struct ListFuncs
10{
11    static void ctorArray(
12        RttiTypeFuncsMap* typeMap,
13        const RttiInfo* rttiInfo,
14        void* inDst,
15        Index count)
16    {
17        SLANG_UNUSED(typeMap);
18        SLANG_UNUSED(rttiInfo);
19        SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List);
20
21        // We don't care about the element type, as we can just initialize them all as List<Byte>
22        // const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo);
23        typedef List<Byte> Type;
24
25        Type* dst = (Type*)inDst;
26
27        for (Index i = 0; i < count; ++i)
28        {
29            new (dst + i) Type;
30        }
31    }
32
33    static void copyArray(
34        RttiTypeFuncsMap* typeMap,
35        const RttiInfo* rttiInfo,
36        void* inDst,
37        const void* inSrc,
38        Index count)
39    {
40        SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List);
41        const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo);
42        const auto elementType = listRttiInfo->m_elementType;
43
44        // We need to get the type funcs
45        auto typeFuncs = typeMap->getFuncsForType(elementType);
46        SLANG_ASSERT(typeFuncs.isValid());
47
48        // We need a type that we can get information from the list from - List<Byte> gives us the
49        // functions we need.
50        typedef List<Byte> Type;
51
52        Type* dst = (Type*)inDst;
53        const Type* src = (const Type*)inSrc;
54
55        for (Index i = 0; i < count; ++i)
56        {
57            auto& dstList = dst[i];
58            auto& srcList = src[i];
59
60            const Index srcCount = srcList.getCount();
61
62            if (srcCount > dstList.getCount())
63            {
64                // Allocate new memory
65                const Index dstCapacity = dstList.getCapacity();
66                void* oldBuffer = dstList.detachBuffer();
67
68                void* newBuffer = ::malloc(count * elementType->m_size);
69                // Initialize it all first
70                typeFuncs.ctorArray(typeMap, elementType, newBuffer, count);
71                typeFuncs.copyArray(typeMap, elementType, newBuffer, oldBuffer, count);
72
73                // Attach the new buffer
74                dstList.attachBuffer((Byte*)newBuffer, count, count);
75
76                // Free the old buffer
77                if (oldBuffer)
78                {
79                    typeFuncs.dtorArray(typeMap, elementType, oldBuffer, dstCapacity);
80
81                    ::free(oldBuffer);
82                }
83            }
84            else
85            {
86                typeFuncs.copyArray(
87                    typeMap,
88                    elementType,
89                    dstList.getBuffer(),
90                    srcList.getBuffer(),
91                    srcCount);
92                dstList.unsafeShrinkToCount(srcCount);
93            }
94        }
95    }
96
97    static void dtorArray(
98        RttiTypeFuncsMap* typeMap,
99        const RttiInfo* rttiInfo,
100        void* inDst,
101        Index count)
102    {
103        SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List);
104        const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo);
105
106        const auto elementType = listRttiInfo->m_elementType;
107
108        // We need to get the type funcs
109        auto typeFuncs = typeMap->getFuncsForType(elementType);
110        SLANG_ASSERT(typeFuncs.isValid());
111
112        typedef List<Byte> Type;
113        Type* dst = (Type*)inDst;
114
115        for (Index i = 0; i < count; ++i)
116        {
117            auto& dstList = dst[i];
118
119            const Index capacity = dstList.getCapacity();
120            Byte* buffer = dstList.detachBuffer();
121
122            if (buffer)
123            {
124                typeFuncs.dtorArray(typeMap, elementType, buffer, capacity);
125                ::free(buffer);
126            }
127        }
128    }
129
130    static RttiTypeFuncs getFuncs()
131    {
132        RttiTypeFuncs funcs;
133        funcs.copyArray = &copyArray;
134        funcs.dtorArray = &dtorArray;
135        funcs.ctorArray = &ctorArray;
136        return funcs;
137    }
138};
139
140struct StructFuncs
141{
142    static void ctorArray(
143        RttiTypeFuncsMap* typeMap,
144        const RttiInfo* rttiInfo,
145        void* inDst,
146        Index count)
147    {
148        SLANG_UNUSED(typeMap);
149        SLANG_UNUSED(rttiInfo);
150        SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List);
151
152        // We don't care about the element type, as we can just initialize them all as List<Byte>
153        // const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo);
154        typedef List<Byte> Type;
155
156        Type* dst = (Type*)inDst;
157
158        for (Index i = 0; i < count; ++i)
159        {
160            new (dst + i) Type;
161        }
162    }
163    static void copyArray(
164        RttiTypeFuncsMap* typeMap,
165        const RttiInfo* rttiInfo,
166        void* inDst,
167        const void* inSrc,
168        Index count)
169    {
170        SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List);
171        const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo);
172        const auto elementType = listRttiInfo->m_elementType;
173
174        // We need to get the type funcs
175        auto typeFuncs = typeMap->getFuncsForType(elementType);
176        SLANG_ASSERT(typeFuncs.isValid());
177
178        // We need a type that we can get information from the list from - List<Byte> gives us the
179        // functions we need.
180        typedef List<Byte> Type;
181
182        Type* dst = (Type*)inDst;
183        const Type* src = (const Type*)inSrc;
184
185        for (Index i = 0; i < count; ++i)
186        {
187            auto& dstList = dst[i];
188            auto& srcList = src[i];
189
190            const Index srcCount = srcList.getCount();
191
192            if (srcCount > dstList.getCount())
193            {
194                // Allocate new memory
195                const Index dstCapacity = dstList.getCapacity();
196                void* oldBuffer = dstList.detachBuffer();
197
198                void* newBuffer = ::malloc(count * elementType->m_size);
199                // Initialize it all first
200                typeFuncs.ctorArray(typeMap, elementType, newBuffer, count);
201                typeFuncs.copyArray(typeMap, elementType, newBuffer, oldBuffer, count);
202
203                // Attach the new buffer
204                dstList.attachBuffer((Byte*)newBuffer, count, count);
205
206                // Free the old buffer
207                if (oldBuffer)
208                {
209                    typeFuncs.dtorArray(typeMap, elementType, oldBuffer, dstCapacity);
210
211                    ::free(oldBuffer);
212                }
213            }
214            else
215            {
216                typeFuncs.copyArray(
217                    typeMap,
218                    elementType,
219                    dstList.getBuffer(),
220                    srcList.getBuffer(),
221                    srcCount);
222                dstList.unsafeShrinkToCount(srcCount);
223            }
224        }
225    }
226
227    static void dtorArray(
228        RttiTypeFuncsMap* typeMap,
229        const RttiInfo* rttiInfo,
230        void* inDst,
231        Index count)
232    {
233        SLANG_ASSERT(rttiInfo->m_kind == RttiInfo::Kind::List);
234        const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(rttiInfo);
235
236        const auto elementType = listRttiInfo->m_elementType;
237
238        // We need to get the type funcs
239        auto typeFuncs = typeMap->getFuncsForType(elementType);
240        SLANG_ASSERT(typeFuncs.isValid());
241
242        typedef List<Byte> Type;
243        Type* dst = (Type*)inDst;
244
245        for (Index i = 0; i < count; ++i)
246        {
247            auto& dstList = dst[i];
248
249            const Index capacity = dstList.getCapacity();
250            Byte* buffer = dstList.detachBuffer();
251
252            if (buffer)
253            {
254                typeFuncs.dtorArray(typeMap, elementType, buffer, capacity);
255                ::free(buffer);
256            }
257        }
258    }
259
260    static RttiTypeFuncs getFuncs()
261    {
262        RttiTypeFuncs funcs;
263        funcs.copyArray = &copyArray;
264        funcs.dtorArray = &dtorArray;
265        funcs.ctorArray = &ctorArray;
266        return funcs;
267    }
268};
269
270struct StructArrayFuncs
271{
272    static void ctorArray(
273        RttiTypeFuncsMap* typeMap,
274        const RttiInfo* rttiInfo,
275        void* inDst,
276        Index count)
277    {
278        return RttiUtil::ctorArray(typeMap, rttiInfo, inDst, rttiInfo->m_size, count);
279    }
280
281    static void copyArray(
282        RttiTypeFuncsMap* typeMap,
283        const RttiInfo* rttiInfo,
284        void* inDst,
285        const void* inSrc,
286        Index count)
287    {
288        return RttiUtil::copyArray(typeMap, rttiInfo, inDst, inSrc, rttiInfo->m_size, count);
289    }
290
291    static void dtorArray(
292        RttiTypeFuncsMap* typeMap,
293        const RttiInfo* rttiInfo,
294        void* inDst,
295        Index count)
296    {
297        return RttiUtil::dtorArray(typeMap, rttiInfo, inDst, rttiInfo->m_size, count);
298    }
299
300    static RttiTypeFuncs getFuncs()
301    {
302        RttiTypeFuncs funcs;
303        funcs.copyArray = copyArray;
304        funcs.dtorArray = dtorArray;
305        funcs.ctorArray = ctorArray;
306        return funcs;
307    }
308};
309
310/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
311
312RttiTypeFuncs RttiUtil::getDefaultTypeFuncs(const RttiInfo* rttiInfo)
313{
314    if (rttiInfo->isBuiltIn())
315    {
316        switch (rttiInfo->m_size)
317        {
318        case 1:
319            return GetRttiTypeFuncsForZeroPod<uint8_t>::getFuncs();
320        case 2:
321            return GetRttiTypeFuncsForZeroPod<uint16_t>::getFuncs();
322        case 4:
323            return GetRttiTypeFuncsForZeroPod<uint32_t>::getFuncs();
324        case 8:
325            return GetRttiTypeFuncsForZeroPod<uint64_t>::getFuncs();
326        }
327        return RttiTypeFuncs::makeEmpty();
328    }
329
330    switch (rttiInfo->m_kind)
331    {
332    case RttiInfo::Kind::String:
333        return GetRttiTypeFuncs<String>::getFuncs();
334    case RttiInfo::Kind::UnownedStringSlice:
335        return GetRttiTypeFuncs<UnownedStringSlice>::getFuncs();
336    case RttiInfo::Kind::List:
337        return ListFuncs::getFuncs();
338    case RttiInfo::Kind::Struct:
339    case RttiInfo::Kind::Optional:
340        return StructArrayFuncs::getFuncs();
341    default:
342        break;
343    }
344
345    return RttiTypeFuncs::makeEmpty();
346}
347
348/* static */ SlangResult RttiUtil::setInt(int64_t value, const RttiInfo* rttiInfo, void* dst)
349{
350    SLANG_ASSERT(rttiInfo->isIntegral());
351
352    // We could check ranges are appropriate, but for now we just write.
353    // Passing in rttiInfo allows for other more complex types to be econverted
354    switch (rttiInfo->m_kind)
355    {
356    case RttiInfo::Kind::I32:
357        *(int32_t*)dst = int32_t(value);
358        break;
359    case RttiInfo::Kind::U32:
360        *(uint32_t*)dst = uint32_t(value);
361        break;
362    case RttiInfo::Kind::I64:
363        *(int64_t*)dst = int64_t(value);
364        break;
365    case RttiInfo::Kind::U64:
366        *(uint64_t*)dst = uint64_t(value);
367        break;
368    default:
369        return SLANG_FAIL;
370    }
371    return SLANG_OK;
372}
373
374/* static */ int64_t RttiUtil::getInt64(const RttiInfo* rttiInfo, const void* src)
375{
376    SLANG_ASSERT(rttiInfo->isIntegral());
377
378    switch (rttiInfo->m_kind)
379    {
380    case RttiInfo::Kind::I32:
381        return *(const int32_t*)src;
382    case RttiInfo::Kind::U32:
383        return *(const uint32_t*)src;
384    case RttiInfo::Kind::I64:
385        return *(const int64_t*)src;
386    case RttiInfo::Kind::U64:
387        return *(const uint64_t*)src;
388    default:
389        break;
390    }
391
392    SLANG_ASSERT(!"Not integral!");
393    return -1;
394}
395
396/* static */ double RttiUtil::asDouble(const RttiInfo* rttiInfo, const void* src)
397{
398    if (rttiInfo->isIntegral())
399    {
400        return (double)getInt64(rttiInfo, src);
401    }
402    else if (rttiInfo->isFloat())
403    {
404        switch (rttiInfo->m_kind)
405        {
406        case RttiInfo::Kind::F32:
407            return *(const float*)src;
408        case RttiInfo::Kind::F64:
409            return *(const double*)src;
410        default:
411            break;
412        }
413    }
414
415    SLANG_ASSERT(!"Cannot convert to float");
416    return 0.0;
417}
418
419/* static */ SlangResult RttiUtil::setFromDouble(double v, const RttiInfo* rttiInfo, void* dst)
420{
421    if (rttiInfo->isIntegral())
422    {
423        return setInt(int64_t(v), rttiInfo, dst);
424    }
425    else if (rttiInfo->isFloat())
426    {
427        switch (rttiInfo->m_kind)
428        {
429        case RttiInfo::Kind::F32:
430            *(float*)dst = float(v);
431            return SLANG_OK;
432        case RttiInfo::Kind::F64:
433            *(double*)dst = v;
434            return SLANG_OK;
435        default:
436            break;
437        }
438    }
439
440    return SLANG_FAIL;
441}
442
443/* static */ bool RttiUtil::asBool(const RttiInfo* rttiInfo, const void* src)
444{
445    if (rttiInfo->m_kind == RttiInfo::Kind::Bool)
446    {
447        return *(const bool*)src;
448    }
449
450    if (rttiInfo->isIntegral())
451    {
452        return getInt64(rttiInfo, src) != 0;
453    }
454    else if (rttiInfo->isFloat())
455    {
456        return asDouble(rttiInfo, src) != 0.0;
457    }
458
459    SLANG_ASSERT(!"Cannot convert to bool");
460    return false;
461}
462
463static int64_t _getIntDefaultValue(RttiDefaultValue value)
464{
465    switch (value)
466    {
467    default:
468    case RttiDefaultValue::Normal:
469        return 0;
470    case RttiDefaultValue::One:
471        return 1;
472    case RttiDefaultValue::MinusOne:
473        return -1;
474    }
475}
476
477static bool _isStructDefault(const StructRttiInfo* type, const void* src)
478{
479    if (type->m_super)
480    {
481        if (!_isStructDefault(type->m_super, src))
482        {
483            return false;
484        }
485    }
486
487    const Byte* base = (const Byte*)src;
488
489    const Index count = type->m_fieldCount;
490    for (Index i = 0; i < count; ++i)
491    {
492        const auto& field = type->m_fields[i];
493
494        const RttiDefaultValue defaultValue =
495            RttiDefaultValue(field.m_flags & uint8_t(RttiDefaultValue::Mask));
496
497        if (!RttiUtil::isDefault(defaultValue, field.m_type, base + field.m_offset))
498        {
499            return false;
500        }
501    }
502
503    return true;
504}
505
506/* static */ bool RttiUtil::isDefault(
507    RttiDefaultValue defaultValue,
508    const RttiInfo* rttiInfo,
509    const void* src)
510{
511    if (rttiInfo->isIntegral())
512    {
513        const auto value = getInt64(rttiInfo, src);
514        return _getIntDefaultValue(defaultValue) == value;
515    }
516    else if (rttiInfo->isFloat())
517    {
518        const auto value = asDouble(rttiInfo, src);
519        return _getIntDefaultValue(defaultValue) == value;
520    }
521
522    switch (rttiInfo->m_kind)
523    {
524    case RttiInfo::Kind::Invalid:
525        return true;
526    case RttiInfo::Kind::Bool:
527        return *(const bool*)src == (_getIntDefaultValue(defaultValue) != 0);
528    case RttiInfo::Kind::String:
529        {
530            return ((const String*)src)->getLength() == 0;
531        }
532    case RttiInfo::Kind::UnownedStringSlice:
533        {
534            return ((const UnownedStringSlice*)src)->getLength() == 0;
535        }
536    case RttiInfo::Kind::Struct:
537        {
538            return _isStructDefault(static_cast<const StructRttiInfo*>(rttiInfo), src);
539        }
540    case RttiInfo::Kind::Enum:
541        {
542            SLANG_ASSERT(!"Not implemented yet");
543            return false;
544        }
545    case RttiInfo::Kind::List:
546        {
547            const auto& v = *(const List<Byte>*)src;
548            return v.getCount() == 0;
549        }
550    case RttiInfo::Kind::Dictionary:
551        {
552            const auto& v = *(const Dictionary<Byte, Byte>*)src;
553            return v.getCount() == 0;
554        }
555    case RttiInfo::Kind::Other:
556        {
557            const OtherRttiInfo* otherRttiInfo = static_cast<const OtherRttiInfo*>(rttiInfo);
558            return otherRttiInfo->m_isDefaultFunc && otherRttiInfo->m_isDefaultFunc(rttiInfo, src);
559        }
560    case RttiInfo::Kind::Optional:
561        {
562            return *(const bool*)src == (_getIntDefaultValue(defaultValue) != 0);
563        }
564    default:
565        {
566            return false;
567        }
568    }
569}
570
571/* static */ SlangResult RttiUtil::setListCount(
572    RttiTypeFuncsMap* typeMap,
573    const RttiInfo* elementType,
574    void* dst,
575    Index count)
576{
577    // NOTE! The following only works because List<T> has capacity initialized members, and
578    // setting the count if it is <= capacity just sets the count (ie things aren't released(!)).
579
580    List<Byte>& dstList = *(List<Byte>*)dst;
581    const Index oldCount = dstList.getCount();
582    if (oldCount == count)
583    {
584        return SLANG_OK;
585    }
586    if (count < oldCount)
587    {
588        dstList.unsafeShrinkToCount(count);
589        return SLANG_OK;
590    }
591
592    const auto typeFuncs = typeMap->getFuncsForType(elementType);
593    SLANG_ASSERT(typeFuncs.isValid());
594
595    const Index dstCapacity = dstList.getCapacity();
596    void* oldBuffer = dstList.detachBuffer();
597
598    void* newBuffer = ::malloc(count * elementType->m_size);
599    // Initialize it all first
600    typeFuncs.ctorArray(typeMap, elementType, newBuffer, count);
601
602    typeFuncs.copyArray(typeMap, elementType, newBuffer, oldBuffer, oldCount);
603
604    // Attach the new buffer
605    dstList.attachBuffer((Byte*)newBuffer, count, count);
606
607    // Free the old buffer
608    if (oldBuffer)
609    {
610        typeFuncs.dtorArray(typeMap, elementType, oldBuffer, dstCapacity);
611        ::free(oldBuffer);
612    }
613
614    return SLANG_OK;
615}
616
617/* static */ bool RttiUtil::canMemCpy(const RttiInfo* type)
618{
619    switch (type->m_kind)
620    {
621    case RttiInfo::Kind::RefPtr:
622    case RttiInfo::Kind::String:
623    case RttiInfo::Kind::Invalid:
624        {
625            return false;
626        }
627    case RttiInfo::Kind::UnownedStringSlice:
628    case RttiInfo::Kind::Ptr:
629    case RttiInfo::Kind::Enum:
630        {
631            return true;
632        }
633    case RttiInfo::Kind::FixedArray:
634        {
635            const FixedArrayRttiInfo* fixedArrayRttiInfo =
636                static_cast<const FixedArrayRttiInfo*>(type);
637            return canMemCpy(fixedArrayRttiInfo->m_elementType);
638        }
639    case RttiInfo::Kind::Other:
640    case RttiInfo::Kind::List:
641    case RttiInfo::Kind::Dictionary:
642        {
643            return false;
644        }
645    case RttiInfo::Kind::Struct:
646        {
647            const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(type);
648
649            do
650            {
651                // If all the fields can be zero inited, struct can be
652                const auto fieldCount = structRttiInfo->m_fieldCount;
653                const auto fields = structRttiInfo->m_fields;
654
655                for (Index i = 0; i < fieldCount; ++i)
656                {
657                    const auto& field = fields[i];
658                    if (!canMemCpy(field.m_type))
659                    {
660                        return false;
661                    }
662                }
663                structRttiInfo = structRttiInfo->m_super;
664            } while (structRttiInfo);
665
666            return true;
667        }
668    case RttiInfo::Kind::Optional:
669        {
670            const OptionalRttiInfo* optionalRttiInfo = static_cast<const OptionalRttiInfo*>(type);
671            return canMemCpy(optionalRttiInfo->m_elementType);
672        }
673    default:
674        {
675            return type->isBuiltIn();
676        }
677    }
678}
679
680/* static */ bool RttiUtil::canZeroInit(const RttiInfo* type)
681{
682    switch (type->m_kind)
683    {
684    case RttiInfo::Kind::Invalid:
685        {
686            return true;
687        }
688    case RttiInfo::Kind::String:
689        {
690            // As it stands we can zero init String, but if impl changes that might not
691            // be true
692            return true;
693        }
694    case RttiInfo::Kind::UnownedStringSlice:
695    case RttiInfo::Kind::Ptr:
696    case RttiInfo::Kind::RefPtr:
697    case RttiInfo::Kind::Enum:
698        {
699            return true;
700        }
701    case RttiInfo::Kind::FixedArray:
702        {
703            const FixedArrayRttiInfo* fixedArrayRttiInfo =
704                static_cast<const FixedArrayRttiInfo*>(type);
705            return canZeroInit(fixedArrayRttiInfo->m_elementType);
706        }
707    case RttiInfo::Kind::Other:
708    case RttiInfo::Kind::List:
709    case RttiInfo::Kind::Dictionary:
710        {
711            return false;
712        }
713    case RttiInfo::Kind::Struct:
714        {
715            const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(type);
716
717            do
718            {
719                // If all the fields can be zero inited, struct can be
720                const auto fieldCount = structRttiInfo->m_fieldCount;
721                const auto fields = structRttiInfo->m_fields;
722
723                for (Index i = 0; i < fieldCount; ++i)
724                {
725                    const auto& field = fields[i];
726                    if (!canZeroInit(field.m_type))
727                    {
728                        return false;
729                    }
730                }
731                structRttiInfo = structRttiInfo->m_super;
732            } while (structRttiInfo);
733
734            return true;
735        }
736    case RttiInfo::Kind::Optional:
737        {
738            const OptionalRttiInfo* optionalRttiInfo = static_cast<const OptionalRttiInfo*>(type);
739            return canZeroInit(optionalRttiInfo->m_elementType);
740        }
741    default:
742        {
743            return type->isBuiltIn();
744        }
745    }
746}
747
748/* static */ bool RttiUtil::hasDtor(const RttiInfo* type)
749{
750    switch (type->m_kind)
751    {
752    case RttiInfo::Kind::Invalid:
753        {
754            return false;
755        }
756    case RttiInfo::Kind::String:
757    case RttiInfo::Kind::RefPtr:
758        {
759            return true;
760        }
761    case RttiInfo::Kind::UnownedStringSlice:
762    case RttiInfo::Kind::Ptr:
763    case RttiInfo::Kind::Enum:
764        {
765            return false;
766        }
767    case RttiInfo::Kind::FixedArray:
768        {
769            const FixedArrayRttiInfo* fixedArrayRttiInfo =
770                static_cast<const FixedArrayRttiInfo*>(type);
771            return hasDtor(fixedArrayRttiInfo->m_elementType);
772        }
773    case RttiInfo::Kind::Other:
774    case RttiInfo::Kind::List:
775    case RttiInfo::Kind::Dictionary:
776        {
777            return true;
778        }
779    case RttiInfo::Kind::Struct:
780        {
781            const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(type);
782
783            do
784            {
785                // If all the fields can be zero inited, struct can be
786                const auto fieldCount = structRttiInfo->m_fieldCount;
787                const auto fields = structRttiInfo->m_fields;
788
789                for (Index i = 0; i < fieldCount; ++i)
790                {
791                    const auto& field = fields[i];
792                    if (hasDtor(field.m_type))
793                    {
794                        return true;
795                    }
796                }
797                structRttiInfo = structRttiInfo->m_super;
798            } while (structRttiInfo);
799            return false;
800        }
801    case RttiInfo::Kind::Optional:
802        {
803            const OptionalRttiInfo* optionalRttiInfo = static_cast<const OptionalRttiInfo*>(type);
804            return hasDtor(optionalRttiInfo->m_elementType);
805        }
806    default:
807        {
808            return !type->isBuiltIn();
809        }
810    }
811}
812
813/* static */ void RttiUtil::ctorArray(
814    RttiTypeFuncsMap* typeMap,
815    const RttiInfo* rttiInfo,
816    void* inDst,
817    ptrdiff_t stride,
818    Index count)
819{
820    if (count <= 0)
821    {
822        return;
823    }
824
825    Byte* dst = (Byte*)inDst;
826    if (canZeroInit(rttiInfo))
827    {
828        if (stride == rttiInfo->m_size)
829        {
830            ::memset(dst, 0, count * stride);
831        }
832        else
833        {
834            const size_t size = rttiInfo->m_size;
835            for (Index i = 0; i < count; ++i, dst += stride)
836            {
837                ::memset(dst, 0, size);
838            }
839        }
840        return;
841    }
842
843    switch (rttiInfo->m_kind)
844    {
845    case RttiInfo::Kind::FixedArray:
846        {
847            const FixedArrayRttiInfo* fixedArrayRttiInfo =
848                static_cast<const FixedArrayRttiInfo*>(rttiInfo);
849
850            if (fixedArrayRttiInfo->m_size == stride)
851            {
852                // It's contiguous do in one go
853                ctorArray(
854                    typeMap,
855                    fixedArrayRttiInfo->m_elementType,
856                    dst,
857                    fixedArrayRttiInfo->m_elementType->m_size,
858                    fixedArrayRttiInfo->m_elementCount * count);
859            }
860            else
861            {
862                // Do it in array runs
863                for (Index i = 0; i < count; ++i, dst += stride)
864                {
865                    ctorArray(
866                        typeMap,
867                        fixedArrayRttiInfo->m_elementType,
868                        dst,
869                        fixedArrayRttiInfo->m_elementType->m_size,
870                        fixedArrayRttiInfo->m_elementCount);
871                }
872            }
873            return;
874        }
875    case RttiInfo::Kind::List:
876    case RttiInfo::Kind::Dictionary:
877    case RttiInfo::Kind::Other:
878        {
879            auto funcs = typeMap->getFuncsForType(rttiInfo);
880            SLANG_ASSERT(funcs.isValid());
881
882            const OtherRttiInfo* otherRttiInfo = static_cast<const OtherRttiInfo*>(rttiInfo);
883            if (otherRttiInfo->m_size == stride)
884            {
885                funcs.ctorArray(typeMap, rttiInfo, dst, count);
886            }
887            else
888            {
889                // Do it in array runs
890                for (Index i = 0; i < count; ++i, dst += stride)
891                {
892                    funcs.ctorArray(typeMap, rttiInfo, dst, 1);
893                }
894            }
895            return;
896        }
897    case RttiInfo::Kind::Struct:
898        {
899            const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(rttiInfo);
900
901            do
902            {
903                // If all the fields can be zero inited, struct can be
904                const auto fieldCount = structRttiInfo->m_fieldCount;
905                const auto fields = structRttiInfo->m_fields;
906
907                for (Index i = 0; i < fieldCount; ++i)
908                {
909                    const auto& field = fields[i];
910                    ctorArray(typeMap, field.m_type, dst + field.m_offset, stride, count);
911                }
912                structRttiInfo = structRttiInfo->m_super;
913            } while (structRttiInfo);
914
915            return;
916        }
917    case RttiInfo::Kind::Optional:
918        {
919            const OptionalRttiInfo* optionalRttiInfo =
920                static_cast<const OptionalRttiInfo*>(rttiInfo);
921            ctorArray(typeMap, GetRttiInfo<bool>::get(), dst, stride, count);
922            ctorArray(
923                typeMap,
924                optionalRttiInfo->m_elementType,
925                dst + optionalRttiInfo->m_valueOffset,
926                stride,
927                count);
928            return;
929        }
930    }
931
932    SLANG_ASSERT(!"Unexpected");
933}
934
935/* static */ void RttiUtil::copyArray(
936    RttiTypeFuncsMap* typeMap,
937    const RttiInfo* rttiInfo,
938    void* inDst,
939    const void* inSrc,
940    ptrdiff_t stride,
941    Index count)
942{
943    if (count <= 0)
944    {
945        return;
946    }
947
948    const size_t size = rttiInfo->m_size;
949
950    Byte* dst = (Byte*)inDst;
951    const Byte* src = (const Byte*)inSrc;
952    if (canMemCpy(rttiInfo))
953    {
954        if (stride == ptrdiff_t(size))
955        {
956            ::memcpy(dst, src, count * stride);
957        }
958        else
959        {
960
961            for (Index i = 0; i < count; ++i, dst += stride, src += stride)
962            {
963                ::memcpy(dst, src, size);
964            }
965        }
966        return;
967    }
968
969    switch (rttiInfo->m_kind)
970    {
971    case RttiInfo::Kind::FixedArray:
972        {
973            const FixedArrayRttiInfo* fixedArrayRttiInfo =
974                static_cast<const FixedArrayRttiInfo*>(rttiInfo);
975            const auto elementType = fixedArrayRttiInfo->m_elementType;
976            const auto elementSize = elementType->m_size;
977            const auto elementCount = fixedArrayRttiInfo->m_elementCount;
978
979            if (ptrdiff_t(size) == stride)
980            {
981                // It's contiguous do in one go
982                copyArray(typeMap, elementType, dst, src, elementSize, elementCount * count);
983            }
984            else
985            {
986                // Do it in array runs
987                for (Index i = 0; i < count; ++i, dst += stride, src += stride)
988                {
989                    copyArray(typeMap, elementType, dst, src, elementSize, elementCount);
990                }
991            }
992            return;
993        }
994    case RttiInfo::Kind::List:
995    case RttiInfo::Kind::Dictionary:
996    case RttiInfo::Kind::Other:
997        {
998            auto funcs = typeMap->getFuncsForType(rttiInfo);
999            SLANG_ASSERT(funcs.isValid());
1000
1001            const OtherRttiInfo* otherRttiInfo = static_cast<const OtherRttiInfo*>(rttiInfo);
1002            if (otherRttiInfo->m_size == stride)
1003            {
1004                funcs.copyArray(typeMap, rttiInfo, dst, src, count);
1005            }
1006            else
1007            {
1008                for (Index i = 0; i < count; ++i, dst += stride, src += stride)
1009                {
1010                    funcs.copyArray(typeMap, rttiInfo, dst, src, 1);
1011                }
1012            }
1013            return;
1014        }
1015    case RttiInfo::Kind::Struct:
1016        {
1017            const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(rttiInfo);
1018
1019            do
1020            {
1021                // If all the fields can be zero inited, struct can be
1022                const auto fieldCount = structRttiInfo->m_fieldCount;
1023                const auto fields = structRttiInfo->m_fields;
1024
1025                for (Index i = 0; i < fieldCount; ++i)
1026                {
1027                    const auto& field = fields[i];
1028                    copyArray(
1029                        typeMap,
1030                        field.m_type,
1031                        dst + field.m_offset,
1032                        src + field.m_offset,
1033                        stride,
1034                        count);
1035                }
1036                structRttiInfo = structRttiInfo->m_super;
1037            } while (structRttiInfo);
1038
1039            return;
1040        }
1041    case RttiInfo::Kind::Optional:
1042        {
1043            const OptionalRttiInfo* optionalRttiInfo =
1044                static_cast<const OptionalRttiInfo*>(rttiInfo);
1045            copyArray(typeMap, GetRttiInfo<bool>::get(), dst, src, stride, count);
1046            copyArray(
1047                typeMap,
1048                optionalRttiInfo->m_elementType,
1049                dst + optionalRttiInfo->m_valueOffset,
1050                src + optionalRttiInfo->m_valueOffset,
1051                stride,
1052                count);
1053            return;
1054        }
1055    }
1056
1057    SLANG_ASSERT(!"Unexpected");
1058}
1059
1060/* static */ void RttiUtil::dtorArray(
1061    RttiTypeFuncsMap* typeMap,
1062    const RttiInfo* rttiInfo,
1063    void* inDst,
1064    ptrdiff_t stride,
1065    Index count)
1066{
1067    if (count <= 0 || !hasDtor(rttiInfo))
1068    {
1069        return;
1070    }
1071
1072    const size_t size = rttiInfo->m_size;
1073    Byte* dst = (Byte*)inDst;
1074
1075    switch (rttiInfo->m_kind)
1076    {
1077    case RttiInfo::Kind::FixedArray:
1078        {
1079            const FixedArrayRttiInfo* fixedArrayRttiInfo =
1080                static_cast<const FixedArrayRttiInfo*>(rttiInfo);
1081            const auto elementType = fixedArrayRttiInfo->m_elementType;
1082            const auto elementSize = elementType->m_size;
1083            const auto elementCount = fixedArrayRttiInfo->m_elementCount;
1084
1085            if (ptrdiff_t(size) == stride)
1086            {
1087                // It's contiguous do in one go
1088                dtorArray(typeMap, elementType, dst, elementSize, elementCount * count);
1089            }
1090            else
1091            {
1092                // Do it in array runs
1093                for (Index i = 0; i < count; ++i, dst += stride)
1094                {
1095                    dtorArray(typeMap, elementType, dst, elementSize, elementCount);
1096                }
1097            }
1098            return;
1099        }
1100    case RttiInfo::Kind::List:
1101    case RttiInfo::Kind::Dictionary:
1102    case RttiInfo::Kind::Other:
1103        {
1104            auto funcs = typeMap->getFuncsForType(rttiInfo);
1105            SLANG_ASSERT(funcs.isValid());
1106
1107            const OtherRttiInfo* otherRttiInfo = static_cast<const OtherRttiInfo*>(rttiInfo);
1108            if (otherRttiInfo->m_size == stride)
1109            {
1110                funcs.dtorArray(typeMap, rttiInfo, dst, count);
1111            }
1112            else
1113            {
1114                for (Index i = 0; i < count; ++i, dst += stride)
1115                {
1116                    funcs.dtorArray(typeMap, rttiInfo, dst, 1);
1117                }
1118            }
1119            return;
1120        }
1121    case RttiInfo::Kind::Struct:
1122        {
1123            const StructRttiInfo* structRttiInfo = static_cast<const StructRttiInfo*>(rttiInfo);
1124
1125            do
1126            {
1127                // If all the fields can be zero inited, struct can be
1128                const auto fieldCount = structRttiInfo->m_fieldCount;
1129                const auto fields = structRttiInfo->m_fields;
1130
1131                for (Index i = 0; i < fieldCount; ++i)
1132                {
1133                    const auto& field = fields[i];
1134                    dtorArray(typeMap, field.m_type, dst + field.m_offset, stride, count);
1135                }
1136                structRttiInfo = structRttiInfo->m_super;
1137            } while (structRttiInfo);
1138
1139            return;
1140        }
1141    case RttiInfo::Kind::Optional:
1142        {
1143            const OptionalRttiInfo* optionalRttiInfo =
1144                static_cast<const OptionalRttiInfo*>(rttiInfo);
1145            dtorArray(typeMap, GetRttiInfo<bool>::get(), dst, stride, count);
1146            dtorArray(
1147                typeMap,
1148                optionalRttiInfo->m_elementType,
1149                dst + optionalRttiInfo->m_valueOffset,
1150                stride,
1151                count);
1152            return;
1153        }
1154    }
1155
1156    SLANG_ASSERT(!"Unexpected");
1157}
1158
1159} // namespace Slang