yum-mirror/slang

Making it easier to work with shaders

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

Julius IkkalaReplace SLANG_ALIGN_OF with C++11 alignof (#7523)551d0c365

master
13.0 KiB527 linesraw
1#ifndef SLANG_CORE_RTTI_INFO_H
2#define SLANG_CORE_RTTI_INFO_H
3
4#include "slang-basic.h"
5#include "slang-dictionary.h"
6#include "slang-list.h"
7#include "slang-memory-arena.h"
8
9namespace Slang
10{
11
12struct RttiInfo;
13struct RttiTypeFuncsMap;
14
15struct RttiTypeFuncs
16{
17    typedef void (
18        *CtorArray)(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, Index count);
19    typedef void (
20        *DtorArray)(RttiTypeFuncsMap* typeMap, const RttiInfo* rttiInfo, void* dst, Index count);
21    typedef void (*CopyArray)(
22        RttiTypeFuncsMap* typeMap,
23        const RttiInfo* rttiInfo,
24        void* dst,
25        const void* src,
26        Index count);
27
28    bool isValid() const { return ctorArray && dtorArray && copyArray; }
29
30    static RttiTypeFuncs makeEmpty() { return RttiTypeFuncs{nullptr, nullptr, nullptr}; }
31
32    CtorArray ctorArray;
33    DtorArray dtorArray;
34    CopyArray copyArray;
35};
36
37/* Provides a mechanism to map a type to it's RttiFuncs */
38struct RttiTypeFuncsMap
39{
40    /// For a given type returns the funcs.
41    /// If not found returns funcs that return 'isValid' as false.
42    RttiTypeFuncs getFuncsForType(const RttiInfo* rttiInfo);
43
44    /// Add funcs for a type
45    void add(const RttiInfo* rttiInfo, const RttiTypeFuncs& funcs);
46
47protected:
48    Dictionary<const RttiInfo*, RttiTypeFuncs> m_map;
49};
50
51/* Template to get funcs for any arbitrary type */
52template<typename T>
53struct GetRttiTypeFuncs
54{
55    static void ctorArray(
56        RttiTypeFuncsMap* typeMap,
57        const RttiInfo* rttiInfo,
58        void* in,
59        Index count)
60    {
61        SLANG_UNUSED(typeMap);
62        SLANG_UNUSED(rttiInfo);
63        T* dst = (T*)in;
64        for (Index i = 0; i < count; ++i)
65        {
66            new (dst + i) T;
67        }
68    }
69    static void dtorArray(
70        RttiTypeFuncsMap* typeMap,
71        const RttiInfo* rttiInfo,
72        void* in,
73        Index count)
74    {
75        SLANG_UNUSED(typeMap);
76        SLANG_UNUSED(rttiInfo);
77        T* dst = (T*)in;
78        for (Index i = 0; i < count; ++i)
79        {
80            (dst + i)->~T();
81        }
82    }
83    static void copyArray(
84        RttiTypeFuncsMap* typeMap,
85        const RttiInfo* rttiInfo,
86        void* inDst,
87        const void* inSrc,
88        Index count)
89    {
90        SLANG_UNUSED(rttiInfo);
91        SLANG_UNUSED(typeMap);
92
93        T* dst = (T*)inDst;
94        const T* src = (T*)inSrc;
95        for (Index i = 0; i < count; ++i)
96        {
97            dst[i] = src[i];
98        }
99    }
100    static RttiTypeFuncs getFuncs()
101    {
102        RttiTypeFuncs funcs;
103        funcs.copyArray = &copyArray;
104        funcs.dtorArray = &dtorArray;
105        funcs.ctorArray = &ctorArray;
106        return funcs;
107    }
108};
109
110/* An implementation of funcs, for a type that is POD *and* can be zero initialized.
111Built in types generally fall into this catagory, but so do raw pointers and other types,
112such as structs that only contain "ZeroPod" types */
113template<typename T>
114struct GetRttiTypeFuncsForZeroPod
115{
116    static void ctorArray(
117        RttiTypeFuncsMap* typeMap,
118        const RttiInfo* rttiInfo,
119        void* dst,
120        Index count)
121    {
122        SLANG_UNUSED(typeMap);
123        SLANG_UNUSED(rttiInfo);
124        ::memset(dst, 0, sizeof(T) * count);
125    }
126    static void dtorArray(
127        RttiTypeFuncsMap* typeMap,
128        const RttiInfo* rttiInfo,
129        void* dst,
130        Index count)
131    {
132        SLANG_UNUSED(typeMap);
133        SLANG_UNUSED(rttiInfo);
134        SLANG_UNUSED(dst);
135        SLANG_UNUSED(count);
136    }
137    static void copyArray(
138        RttiTypeFuncsMap* typeMap,
139        const RttiInfo* rttiInfo,
140        void* dst,
141        const void* src,
142        Index count)
143    {
144        SLANG_UNUSED(typeMap);
145        SLANG_UNUSED(rttiInfo);
146        ::memcpy(dst, src, sizeof(T) * count);
147    }
148
149    static RttiTypeFuncs getFuncs()
150    {
151        RttiTypeFuncs funcs;
152        funcs.copyArray = &copyArray;
153        funcs.dtorArray = &dtorArray;
154        funcs.ctorArray = &ctorArray;
155        return funcs;
156    }
157};
158
159struct RttiInfo
160{
161    typedef uint8_t AlignmentType;
162    typedef uint16_t SizeType;
163
164    enum class Kind : uint8_t
165    {
166        Invalid,
167        I32,
168        U32,
169        I64,
170        U64,
171        F32,
172        F64,
173        Bool,
174        String,
175        UnownedStringSlice,
176        Ptr,
177        RefPtr,
178        FixedArray,
179        Struct,
180        Other,
181        Enum,
182        List,
183        Dictionary,
184        Optional,
185        CountOf,
186    };
187
188    Kind m_kind;
189    AlignmentType m_alignment;
190    SizeType m_size;
191
192    void init(Kind kind, size_t alignment, size_t size)
193    {
194        m_kind = kind;
195        m_alignment = AlignmentType(alignment);
196        m_size = SizeType(size);
197    }
198
199    template<typename T>
200    void init(Kind kind)
201    {
202        init(kind, alignof(T), sizeof(T));
203    }
204
205    /// Allocate memory for RttiInfo types.
206    /// Is thread safe, and doesn't require the memory to be freed explicitly
207    /// Will be freed at shutdown (via global dtor)
208    static void* allocate(size_t size);
209    /// Will free up any allocations. Can only be called at shutdown, and there are guarenteed no
210    /// uses of RttiInfo - otherwise contents may be undefined. NOTE! Memory *will* be freed with
211    /// final dtors, but if memory check functions are used they can report this memory.
212    static void deallocateAll();
213
214    static bool isIntegral(RttiInfo::Kind kind)
215    {
216        return Index(kind) >= Index(RttiInfo::Kind::I32) &&
217               Index(kind) <= Index(RttiInfo::Kind::U64);
218    }
219    static bool isFloat(RttiInfo::Kind kind)
220    {
221        return kind == RttiInfo::Kind::F32 || kind == RttiInfo::Kind::F64;
222    }
223    static bool isBuiltIn(RttiInfo::Kind kind)
224    {
225        return Index(kind) >= Index(RttiInfo::Kind::I32) &&
226               Index(kind) <= Index(RttiInfo::Kind::Bool);
227    }
228    static bool isNamed(RttiInfo::Kind kind)
229    {
230        return Index(kind) >= Index(RttiInfo::Kind::Struct) &&
231               Index(kind) <= Index(RttiInfo::Kind::Enum);
232    }
233
234    bool isIntegral() const { return isIntegral(m_kind); }
235    bool isFloat() const { return isFloat(m_kind); }
236    bool isBuiltIn() const { return isBuiltIn(m_kind); }
237    bool isNamed() const { return isNamed(m_kind); }
238
239    static void append(const RttiInfo* info, StringBuilder& out);
240
241    static const RttiInfo g_basicTypes[Index(Kind::CountOf)];
242};
243
244// Can combine into flags on a field. Could store default value with a field,
245// but this works fine for most purposes
246enum class RttiDefaultValue : uint8_t
247{
248    Normal, ///< Zero for integral/float types/false for bool
249    One,
250    MinusOne,
251
252    Mask = 0x7,
253};
254
255struct NamedRttiInfo : public RttiInfo
256{
257    const char* m_name; ///< Name
258};
259
260struct StructRttiInfo : public NamedRttiInfo
261{
262    typedef uint8_t Flags;
263    struct Flag
264    {
265        enum Enum : Flags
266        {
267            // We use low bits for 'RttiDefaultValue' value
268            Optional = 0x8,
269        };
270    };
271
272    struct Field
273    {
274        const char* m_name;     ///< Name of this field
275        const RttiInfo* m_type; ///< The type of this field
276        uint32_t m_offset;      ///< Offset from object type in bytes
277        Flags m_flags;          ///< Field flags
278    };
279
280    const StructRttiInfo* m_super; ///< Super class or nullptr if not defined
281
282    Index m_fieldCount;    ///< Amount of fields
283    const Field* m_fields; ///< Fields
284    bool m_ignoreUnknownFieldsInJson = false;
285};
286
287struct EnumRttiInfo : public NamedRttiInfo
288{
289    // TODO(JS):
290};
291
292SLANG_FORCE_INLINE StructRttiInfo::Flags combine(
293    StructRttiInfo::Flags flags,
294    RttiDefaultValue defaultValue)
295{
296    return StructRttiInfo::Flags(defaultValue) | flags;
297}
298
299struct OptionalRttiInfo : public RttiInfo
300{
301    const RttiInfo* m_elementType;
302    uint32_t m_valueOffset;
303};
304
305struct ListRttiInfo : public RttiInfo
306{
307    const RttiInfo* m_elementType;
308};
309
310struct DictionaryRttiInfo : public RttiInfo
311{
312    const RttiInfo* m_keyType;
313    const RttiInfo* m_valueType;
314};
315
316struct PtrRttiInfo : public RttiInfo
317{
318    const RttiInfo* m_targetType;
319};
320
321struct RefPtrRttiInfo : public RttiInfo
322{
323    const RttiInfo* m_targetType;
324};
325
326struct FixedArrayRttiInfo : public RttiInfo
327{
328    const RttiInfo* m_elementType;
329    size_t m_elementCount;
330};
331
332struct OtherRttiInfo : public NamedRttiInfo
333{
334    typedef bool (*IsDefaultFunc)(const RttiInfo* rttiInfo, const void* in);
335    IsDefaultFunc m_isDefaultFunc;
336    RttiTypeFuncs m_typeFuncs;
337};
338
339// The default is to just get the info from a global held inside the type.
340template<typename T>
341struct GetRttiInfo
342{
343    SLANG_FORCE_INLINE static const RttiInfo* get() { return &T::g_rttiInfo; }
344};
345
346template<>
347struct GetRttiInfo<bool>
348{
349    static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::Bool)]; }
350};
351template<>
352struct GetRttiInfo<int32_t>
353{
354    static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::I32)]; }
355};
356template<>
357struct GetRttiInfo<int64_t>
358{
359    static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::I64)]; }
360};
361template<>
362struct GetRttiInfo<uint32_t>
363{
364    static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::U32)]; }
365};
366template<>
367struct GetRttiInfo<uint64_t>
368{
369    static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::U64)]; }
370};
371template<>
372struct GetRttiInfo<float>
373{
374    static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::F32)]; }
375};
376template<>
377struct GetRttiInfo<double>
378{
379    static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::F64)]; }
380};
381template<>
382struct GetRttiInfo<String>
383{
384    static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::String)]; }
385};
386template<>
387struct GetRttiInfo<UnownedStringSlice>
388{
389    static const RttiInfo* get()
390    {
391        return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::UnownedStringSlice)];
392    }
393};
394
395template<typename T>
396struct GetRttiInfo<List<T>>
397{
398    static const ListRttiInfo _make()
399    {
400        ListRttiInfo info;
401        info.init<List<Byte>>(RttiInfo::Kind::List);
402        info.m_elementType = GetRttiInfo<T>::get();
403        return info;
404    }
405    static const RttiInfo* get()
406    {
407        static const ListRttiInfo g_info = _make();
408        return &g_info;
409    }
410};
411
412// Strip const
413template<typename T>
414struct GetRttiInfo<const T>
415{
416    static const RttiInfo* get() { return GetRttiInfo<T>::get(); }
417};
418
419template<typename K, typename V>
420struct GetRttiInfo<Dictionary<K, V>>
421{
422    static const DictionaryRttiInfo _make()
423    {
424        DictionaryRttiInfo info;
425        info.init<Dictionary<Byte, Byte>>(RttiInfo::Kind::Dictionary);
426        info.m_keyType = GetRttiInfo<K>::get();
427        info.m_valueType = GetRttiInfo<V>::get();
428        return info;
429    }
430    static const RttiInfo* get()
431    {
432        static const DictionaryRttiInfo g_info = _make();
433        return &g_info;
434    }
435};
436
437template<typename TARGET>
438struct GetRttiInfo<TARGET*>
439{
440    static const PtrRttiInfo _make()
441    {
442        PtrRttiInfo info;
443        info.init<void*>(RttiInfo::Kind::Ptr);
444        info.m_targetType = GetRttiInfo<TARGET>::get();
445        return info;
446    }
447    static const RttiInfo* get()
448    {
449        static const PtrRttiInfo g_info = _make();
450        return &g_info;
451    }
452};
453
454template<typename TARGET>
455struct GetRttiInfo<RefPtr<TARGET>>
456{
457    static const RefPtrRttiInfo _make()
458    {
459        RefPtrRttiInfo info;
460        info.init<RefPtr<StringRepresentation>>(RttiInfo::Kind::RefPtr);
461        info.m_targetType = GetRttiInfo<TARGET>::get();
462        return info;
463    }
464    static const RttiInfo* get()
465    {
466        static const RefPtrRttiInfo g_info = _make();
467        return &g_info;
468    }
469};
470
471template<typename T, size_t COUNT>
472struct GetRttiInfo<T[COUNT]>
473{
474    static const FixedArrayRttiInfo _make()
475    {
476        FixedArrayRttiInfo info;
477        info.m_kind = RttiInfo::Kind::FixedArray;
478        info.m_alignment = RttiInfo::AlignmentType(alignof(T));
479        info.m_size = RttiInfo::SizeType(sizeof(T) * COUNT);
480        info.m_elementType = GetRttiInfo<T>::get();
481        info.m_elementCount = COUNT;
482        return info;
483    }
484    static const RttiInfo* get()
485    {
486        static const FixedArrayRttiInfo g_info = _make();
487        return &g_info;
488    }
489};
490
491struct StructRttiBuilder
492{
493    template<typename T>
494    StructRttiBuilder(T* obj, const char* name, const StructRttiInfo* super)
495    {
496        m_rttiInfo.init<T>(RttiInfo::Kind::Struct);
497        _init(name, super, (const Byte*)obj);
498    }
499
500    template<typename T>
501    void addField(const char* name, const T* fieldPtr, StructRttiInfo::Flags flags = 0)
502    {
503        StructRttiInfo::Field field;
504
505        field.m_name = name;
506        field.m_type = GetRttiInfo<T>::get();
507        field.m_offset = uint32_t(ptrdiff_t((const Byte*)fieldPtr - m_base));
508        field.m_flags = flags;
509        m_fields.add(field);
510    }
511
512    void ignoreUnknownFields() { m_rttiInfo.m_ignoreUnknownFieldsInJson = true; }
513
514    StructRttiInfo make();
515
516    void _init(const char* name, const StructRttiInfo* super, const Byte* base);
517
518    StructRttiInfo m_rttiInfo;
519
520    List<StructRttiInfo::Field> m_fields;
521    const Byte* m_base;
522};
523
524
525} // namespace Slang
526
527#endif // SLANG_CORE_RTTI_INFO_H