summaryrefslogtreecommitdiffstats
path: root/source/core
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2021-11-18 15:58:12 -0500
committerGitHub <noreply@github.com>2021-11-18 15:58:12 -0500
commit1d5f815b3964edee8a2d701e1a6cc078c89d677f (patch)
treeaa5b4b1473344e635d7ce1d2159fc57eeb40b841 /source/core
parentb482844b689eb109ee1d70c527e098400ac6d409 (diff)
RTTI/JSON (#2021)
* #include an absolute path didn't work - because paths were taken to always be relative. * Use 'Process' to communicate with an command line tool. * Remove slang-win-stream * Tidy up windows ProcessUtil. * First version of BufferedReadStream. * Windows working IPC for steams. * Test proxy count option. * Split Process/ProcessUtil. Process is platform dependant. ProcessUtil are functions that are platform independent. * First implementation of Unix Process interface. * Unix process compiles on cygwin. * Fix typo in unix process. * Separate unix pipe stream error of invalid access, from pipe availability. * Fix in standard line extraction. * Make fd non blocking. * Fix issues with Windows Process streams. * Added UnixPipe. * Some fixes around UnixPipeStream. * Make a unix stream closed explicit. * Hack to debug linux process/stream. * Revert to old linux pipe handling. * Pass executable path for unit tests. Split out CommandLine into own source. * Small improvements in process/command line. * Check process behavior with crash. * Make stderr and stdout unbuffered for crash testing. * Only turn disable buffering in crash test. * Disable crash test on CI. * Fix crash on clang/linux. * Enable crash test. Remove _appendBuffer as can use StreamUtil functionality. * Added inital processing for http headers. * Small improvements to HttpHeader. * First pass HTTPPacketConnection working on windows. * Enable other Process communication tests. * Update comments. * WIP JSON RPC. * Add terminate to Process. Made JSONRPC a Util. * Small tidy up around HTTPPacketConnection. * Improve process termination options. * WIP for test-server. * Add diagnostics error handling to test-server. * Improved JSON support. Parsing/creating JSON-RPC messages. * WIP JSONRPC parsing. * First pass RttiInfo support. * WIP converting between JSON/native types. * Project files. * Split out RttiUtil. Made RttiInfo constuction thread safe. * WIP RTTI<->JSON. * Add diagnostics to JSON<->native conversions. * Make RttiInfo for structs globals. Avoids problem around derived types (like pointers), being able to cause an abort. * Add pointer support to RTTI. Fixed some compilation issues on linux. * Add fixed array support. * Added Rtti unit test. * Add rtti unit test. * Split out quoted/unquoted key handling. Fix bugs in JSON value/container. Added JSON native test. * Make default array allocator use malloc/free. Remove the new[] handler (doesn't work on visuals studio). * Fix for linux warning. * Remove some test code. * Fix issues on x86 win. * Fix warning on aarch64.
Diffstat (limited to 'source/core')
-rw-r--r--source/core/slang-allocator.h21
-rw-r--r--source/core/slang-common.h3
-rw-r--r--source/core/slang-list.h13
-rw-r--r--source/core/slang-rtti-info.cpp184
-rw-r--r--source/core/slang-rtti-info.h341
-rw-r--r--source/core/slang-rtti-util.cpp392
-rw-r--r--source/core/slang-rtti-util.h30
7 files changed, 971 insertions, 13 deletions
diff --git a/source/core/slang-allocator.h b/source/core/slang-allocator.h
index f25fd92c9..bc1b880f8 100644
--- a/source/core/slang-allocator.h
+++ b/source/core/slang-allocator.h
@@ -19,11 +19,9 @@ namespace Slang
#elif defined(__CYGWIN__)
return aligned_alloc(alignment, size);
#else
- void * rs = 0;
+ void* rs = nullptr;
int succ = posix_memalign(&rs, alignment, size);
- if (succ!=0)
- rs = 0;
- return rs;
+ return (succ == 0) ? rs : nullptr;
#endif
}
@@ -66,18 +64,15 @@ namespace Slang
// Helper utilties for calling allocators.
template<typename T, int isPOD>
- class Initializer
- {
-
- };
+ class Initializer;
template<typename T>
class Initializer<T, 0>
{
public:
- static void initialize(T* buffer, int size)
+ static void initialize(T* buffer, Index size)
{
- for (int i = 0; i < size; i++)
+ for (Index i = 0; i < size; i++)
new (buffer + i) T();
}
};
@@ -85,8 +80,10 @@ namespace Slang
class Initializer<T, 1>
{
public:
- static void initialize(T* buffer, int size)
+ static void initialize(T* buffer, Index size)
{
+ SLANG_UNUSED(buffer);
+ SLANG_UNUSED(size);
// It's pod so no initialization required
//for (int i = 0; i < size; i++)
// new (buffer + i) T;
@@ -116,6 +113,7 @@ namespace Slang
}
};
+#if 0
template<typename T>
class AllocateMethod<T, StandardAllocator>
{
@@ -129,6 +127,7 @@ namespace Slang
delete[] ptr;
}
};
+#endif
}
#endif
diff --git a/source/core/slang-common.h b/source/core/slang-common.h
index eb6502b41..6f91da873 100644
--- a/source/core/slang-common.h
+++ b/source/core/slang-common.h
@@ -33,8 +33,9 @@ namespace Slang
// TODO(JS): It looks like Index is actually 64 bit on 64 bit targets(!)
// Previous discussions landed on Index being int32_t.
- // Type used for indexing, in arrays/views etc
+ // Type used for indexing, in arrays/views etc. Signed.
typedef Int Index;
+ typedef UInt UIndex;
static const Index kMaxIndex = kMaxInt;
diff --git a/source/core/slang-list.h b/source/core/slang-list.h
index 4420cc084..25687d129 100644
--- a/source/core/slang-list.h
+++ b/source/core/slang-list.h
@@ -145,6 +145,15 @@ namespace Slang
m_capacity = 0;
return rs;
}
+ void attachBuffer(T* buffer, Index count, Index capacity)
+ {
+ // Can only attach a buffer if there isn't a buffer already associated
+ SLANG_ASSERT(m_buffer == nullptr);
+ SLANG_ASSERT(count <= capacity);
+ m_buffer = buffer;
+ m_count = count;
+ m_capacity = capacity;
+ }
inline ArrayView<T> getArrayView() const
{
@@ -324,7 +333,9 @@ namespace Slang
void reserve(Index size)
{
- if(size > m_capacity)
+ // The cast for this comparison is needed, otherwise some compilers erroneously detect
+ // the possiblity of a zero sized allocation (possible if m_capacity is assumed to be negative).
+ if(UIndex(size) > UIndex(m_capacity))
{
T* newBuffer = _allocate(size);
if (m_capacity)
diff --git a/source/core/slang-rtti-info.cpp b/source/core/slang-rtti-info.cpp
new file mode 100644
index 000000000..f53cf742f
--- /dev/null
+++ b/source/core/slang-rtti-info.cpp
@@ -0,0 +1,184 @@
+#include "slang-rtti-info.h"
+
+#include "../../slang-com-helper.h"
+
+#include <mutex>
+
+namespace Slang {
+
+#define SLANG_RTTI_INFO_INVALID(name) RttiInfo{RttiInfo::Kind::Invalid, 0, 0}
+#define SLANG_RTTI_INFO_BASIC(name, type) \
+ RttiInfo{RttiInfo::Kind::name, RttiInfo::AlignmentType(SLANG_ALIGN_OF(type)), RttiInfo::SizeType(sizeof(type))}
+
+/* static */const RttiInfo RttiInfo::g_basicTypes[Index(Kind::CountOf)] =
+{
+ SLANG_RTTI_INFO_INVALID(Invalid),
+ SLANG_RTTI_INFO_BASIC(I32, int32_t),
+ SLANG_RTTI_INFO_BASIC(U32, uint32_t),
+ SLANG_RTTI_INFO_BASIC(I64, int64_t),
+ SLANG_RTTI_INFO_BASIC(U64, uint64_t),
+ SLANG_RTTI_INFO_BASIC(F32, float),
+ SLANG_RTTI_INFO_BASIC(F64, double),
+ SLANG_RTTI_INFO_BASIC(Bool, bool),
+ SLANG_RTTI_INFO_BASIC(String, String),
+ SLANG_RTTI_INFO_BASIC(UnownedStringSlice, UnownedStringSlice),
+ SLANG_RTTI_INFO_BASIC(Ptr, void*),
+ SLANG_RTTI_INFO_BASIC(RefPtr, RefPtr<StringRepresentation>),
+ SLANG_RTTI_INFO_INVALID(FixedArray),
+ SLANG_RTTI_INFO_INVALID(Struct),
+ SLANG_RTTI_INFO_INVALID(Other),
+ SLANG_RTTI_INFO_INVALID(Enum),
+ SLANG_RTTI_INFO_INVALID(List),
+ SLANG_RTTI_INFO_INVALID(Dictionary),
+};
+
+struct RttiInfoManager
+{
+ void* allocate(size_t size)
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ return m_arena.allocate(size);
+ }
+
+ static RttiInfoManager& getSingleton()
+ {
+ static RttiInfoManager g_manager;
+ return g_manager;
+ }
+
+protected:
+ RttiInfoManager() :
+ m_arena(1024)
+ {
+ }
+
+ std::recursive_mutex m_mutex; ///< We need a mutex to guard access to m_arena
+ MemoryArena m_arena;
+};
+
+/* static */void* RttiInfo::allocate(size_t size)
+{
+ return RttiInfoManager::getSingleton().allocate(size);
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StructRttiBuilder !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+static void _appendFixedArray(const FixedArrayRttiInfo* inFixedArray, StringBuilder& out)
+{
+ List<const FixedArrayRttiInfo*> fixedArrays;
+ fixedArrays.add(inFixedArray);
+
+ const RttiInfo* cur = inFixedArray->m_elementType;
+ while (cur->m_kind == RttiInfo::Kind::FixedArray)
+ {
+ const FixedArrayRttiInfo* curArray = static_cast<const FixedArrayRttiInfo*>(cur);
+ fixedArrays.add(curArray);
+ cur = curArray->m_elementType;
+ }
+
+ // Append the 'target' which is in cur
+ RttiInfo::append(cur, out);
+ // Now all the fixed array values, in order
+ for (auto fixedArray : fixedArrays)
+ {
+ out << "[" << int32_t(fixedArray->m_elementCount) << "]";
+ }
+}
+
+/* static */void RttiInfo::append(const RttiInfo* info, StringBuilder& out)
+{
+ switch (info->m_kind)
+ {
+ case RttiInfo::Kind::I32: out << "int32_t"; break;
+ case RttiInfo::Kind::U32: out << "uint32_t"; break;
+ case RttiInfo::Kind::I64: out << "int64_t"; break;
+ case RttiInfo::Kind::U64: out << "uint64_t"; break;
+ case RttiInfo::Kind::F32: out << "float"; break;
+ case RttiInfo::Kind::F64: out << "double"; break;
+ case RttiInfo::Kind::Bool: out << "bool"; break;
+ case RttiInfo::Kind::String: out << "String"; break;
+ case RttiInfo::Kind::UnownedStringSlice: out << "UnownedStringSlice"; break;
+ case RttiInfo::Kind::Ptr:
+ {
+ const PtrRttiInfo* ptrRttiInfo = static_cast<const PtrRttiInfo*>(info);
+ append(ptrRttiInfo->m_targetType, out);
+ out << "*";
+ break;
+ }
+ case RttiInfo::Kind::RefPtr:
+ {
+ const RefPtrRttiInfo* ptrRttiInfo = static_cast<const RefPtrRttiInfo*>(info);
+ out << "RefPtr<";
+ append(ptrRttiInfo->m_targetType, out);
+ out << ">";
+ break;
+ }
+ case RttiInfo::Kind::FixedArray:
+ {
+ const FixedArrayRttiInfo* arrayRttiInfo = static_cast<const FixedArrayRttiInfo*>(info);
+ _appendFixedArray(arrayRttiInfo, out);
+ break;
+ }
+ case RttiInfo::Kind::List:
+ {
+ const ListRttiInfo* listRttiInfo = static_cast<const ListRttiInfo*>(info);
+ out << "List<";
+ append(listRttiInfo->m_elementType, out);
+ out << ">";
+ break;
+ }
+ case RttiInfo::Kind::Dictionary:
+ {
+ const DictionaryRttiInfo* dictionaryRttiInfo = static_cast<const DictionaryRttiInfo*>(info);
+
+ out << "Dictionary<";
+ append(dictionaryRttiInfo->m_keyType, out);
+ out << ",";
+ append(dictionaryRttiInfo->m_valueType, out);
+ out << ">";
+ break;
+ }
+ default:
+ {
+ if (info->isNamed())
+ {
+ const NamedRttiInfo* namedRttiInfo = static_cast<const NamedRttiInfo*>(info);
+ out << namedRttiInfo->m_name;
+ break;
+ }
+
+ out << "%Unknown%";
+ break;
+ }
+ }
+}
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StructRttiBuilder !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+void StructRttiBuilder::_init(const char* name, const StructRttiInfo* super, const Byte* base)
+{
+ m_rttiInfo.m_name = name;
+ m_rttiInfo.m_super = super;
+ m_base = base;
+
+ m_rttiInfo.m_fieldCount = 0;
+ m_rttiInfo.m_fields = nullptr;
+}
+
+StructRttiInfo StructRttiBuilder::make()
+{
+ const Index fieldCount = m_fields.getCount();
+
+ if (fieldCount)
+ {
+ StructRttiInfo::Field* dstFields = (StructRttiInfo::Field*)RttiInfo::allocate(sizeof(StructRttiInfo::Field) * fieldCount);
+ ::memcpy(dstFields, m_fields.getBuffer(), sizeof(StructRttiInfo::Field) * fieldCount);
+
+ m_rttiInfo.m_fields = dstFields;
+ m_rttiInfo.m_fieldCount = fieldCount;
+ }
+
+ return m_rttiInfo;
+}
+
+} // namespace Slang
diff --git a/source/core/slang-rtti-info.h b/source/core/slang-rtti-info.h
new file mode 100644
index 000000000..c1fe1810f
--- /dev/null
+++ b/source/core/slang-rtti-info.h
@@ -0,0 +1,341 @@
+#ifndef SLANG_CORE_RTTI_INFO_H
+#define SLANG_CORE_RTTI_INFO_H
+
+#include "slang-basic.h"
+#include "slang-memory-arena.h"
+
+#include "slang-list.h"
+#include "slang-dictionary.h"
+
+namespace Slang {
+
+struct RttiInfo;
+
+struct RttiTypeFuncs
+{
+ typedef void (*CtorArray)(const RttiInfo* rttiInfo, void* dst, Index count);
+ typedef void (*DtorArray)(const RttiInfo* rttiInfo, void* dst, Index count);
+ typedef void (*CopyArray)(const RttiInfo* rttiInfo, void* dst, const void* src, Index count);
+
+ bool isValid() const { return ctorArray && dtorArray && copyArray; }
+
+ static RttiTypeFuncs makeEmpty() { return RttiTypeFuncs{ nullptr, nullptr, nullptr }; }
+
+ CtorArray ctorArray;
+ DtorArray dtorArray;
+ CopyArray copyArray;
+};
+
+template <typename T>
+struct GetRttiTypeFuncs
+{
+ static void ctorArray(const RttiInfo* rttiInfo, void* in, Index count)
+ {
+ SLANG_UNUSED(rttiInfo);
+ T* dst = (T*)in;
+ for (Index i = 0; i < count; ++i)
+ {
+ new (dst + i) T;
+ }
+ }
+ static void dtorArray(const RttiInfo* rttiInfo, void* in, Index count)
+ {
+ SLANG_UNUSED(rttiInfo);
+ T* dst = (T*)in;
+ for (Index i = 0; i < count; ++i)
+ {
+ (dst + i)->~T();
+ }
+ }
+ static void copyArray(const RttiInfo* rttiInfo, void* inDst, const void* inSrc, Index count)
+ {
+ SLANG_UNUSED(rttiInfo);
+ T* dst = (T*)inDst;
+ const T* src = (T*)inSrc;
+ for (Index i = 0; i < count; ++i)
+ {
+ dst[i] = src[i];
+ }
+ }
+ static RttiTypeFuncs getFuncs()
+ {
+ RttiTypeFuncs funcs;
+ funcs.copyArray = &copyArray;
+ funcs.dtorArray = &dtorArray;
+ funcs.ctorArray = &ctorArray;
+ return funcs;
+ }
+};
+
+struct RttiInfo
+{
+ typedef uint8_t AlignmentType;
+ typedef uint16_t SizeType;
+
+ enum class Kind : uint8_t
+ {
+ Invalid,
+ I32,
+ U32,
+ I64,
+ U64,
+ F32,
+ F64,
+ Bool,
+ String,
+ UnownedStringSlice,
+ Ptr,
+ RefPtr,
+ FixedArray,
+ Struct,
+ Other,
+ Enum,
+ List,
+ Dictionary,
+
+ CountOf,
+ };
+
+ Kind m_kind;
+ AlignmentType m_alignment;
+ SizeType m_size;
+
+ void init(Kind kind, size_t alignment, size_t size) { m_kind = kind; m_alignment = AlignmentType(alignment); m_size = SizeType(size); }
+
+ template <typename T>
+ void init(Kind kind) { init(kind, SLANG_ALIGN_OF(T), sizeof(T)); }
+
+ /// Allocate memory for RttiInfo types.
+ /// Is thread safe, and doesn't require the memory to be freed explicitly
+ /// Will be freed at shutdown (via global dtor)
+ static void* allocate(size_t size);
+
+ 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 isNamed(RttiInfo::Kind kind) { return Index(kind) >= Index(RttiInfo::Kind::Struct) && Index(kind) <= Index(RttiInfo::Kind::Enum); }
+
+ bool isIntegral() const { return isIntegral(m_kind); }
+ bool isFloat() const { return isFloat(m_kind); }
+ bool isBuiltIn() const { return isBuiltIn(m_kind); }
+ bool isNamed() const { return isNamed(m_kind); }
+
+ static void append(const RttiInfo* info, StringBuilder& out);
+
+ static const RttiInfo g_basicTypes[Index(Kind::CountOf)];
+};
+
+// Can combine into flags on a field. Could store default value with a field,
+// but this works fine for most purposes
+enum class RttiDefaultValue : uint8_t
+{
+ Normal, ///< Zero for integral/float types/false for bool
+ One,
+ MinusOne,
+
+ Mask = 0x7,
+};
+
+struct NamedRttiInfo : public RttiInfo
+{
+ const char* m_name; ///< Name
+};
+
+struct StructRttiInfo : public NamedRttiInfo
+{
+ typedef uint8_t Flags;
+ struct Flag
+ {
+ enum Enum : Flags
+ {
+ // We use low bits for 'RttiDefaultValue' value
+ Optional = 0x8,
+ };
+ };
+
+ struct Field
+ {
+ const char* m_name; ///< Name of this field
+ const RttiInfo* m_type; ///< The type of this field
+ uint32_t m_offset; ///< Offset from object type in bytes
+ Flags m_flags; ///< Field flags
+ };
+
+ const StructRttiInfo* m_super; ///< Super class or nullptr if not defined
+
+ Index m_fieldCount; ///< Amount of fields
+ const Field* m_fields; ///< Fields
+};
+
+struct EnumRttiInfo : public NamedRttiInfo
+{
+ // TODO(JS):
+};
+
+SLANG_FORCE_INLINE StructRttiInfo::Flags combine(StructRttiInfo::Flags flags, RttiDefaultValue defaultValue)
+{
+ return StructRttiInfo::Flags(defaultValue) | flags;
+}
+
+struct ListRttiInfo : public RttiInfo
+{
+ const RttiInfo* m_elementType;
+};
+
+struct DictionaryRttiInfo : public RttiInfo
+{
+ const RttiInfo* m_keyType;
+ const RttiInfo* m_valueType;
+};
+
+struct PtrRttiInfo : public RttiInfo
+{
+ const RttiInfo* m_targetType;
+};
+
+struct RefPtrRttiInfo : public RttiInfo
+{
+ const RttiInfo* m_targetType;
+};
+
+struct FixedArrayRttiInfo : public RttiInfo
+{
+ const RttiInfo* m_elementType;
+ size_t m_elementCount;
+};
+
+struct OtherRttiInfo : public NamedRttiInfo
+{
+ typedef bool (*IsDefaultFunc)(const RttiInfo* rttiInfo, const void* in);
+ IsDefaultFunc m_isDefaultFunc;
+ RttiTypeFuncs m_typeFuncs;
+};
+
+// The default is to just get the info from a global held inside the type.
+template <typename T>
+struct GetRttiInfo
+{
+ SLANG_FORCE_INLINE static const RttiInfo* get() { return &T::g_rttiInfo; }
+};
+
+template <> struct GetRttiInfo<bool> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::Bool)];} };
+template <> struct GetRttiInfo<int32_t> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::I32)]; } };
+template <> struct GetRttiInfo<int64_t> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::I64)]; } };
+template <> struct GetRttiInfo<uint32_t> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::U32)]; } };
+template <> struct GetRttiInfo<uint64_t> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::U64)]; } };
+template <> struct GetRttiInfo<float> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::F32)]; } };
+template <> struct GetRttiInfo<double> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::F64)]; } };
+template <> struct GetRttiInfo<String> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::String)]; } };
+template <> struct GetRttiInfo<UnownedStringSlice> { static const RttiInfo* get() { return &RttiInfo::g_basicTypes[Index(RttiInfo::Kind::UnownedStringSlice)]; } };
+
+template <typename T>
+struct GetRttiInfo<List<T>>
+{
+ static const ListRttiInfo _make()
+ {
+ ListRttiInfo info;
+ info.init<List<Byte>>(RttiInfo::Kind::List);
+ info.m_elementType = GetRttiInfo<T>::get();
+ return info;
+ }
+ static const RttiInfo* get() { static const ListRttiInfo g_info = _make(); return &g_info; }
+};
+
+// Strip const
+template <typename T>
+struct GetRttiInfo<const T>
+{
+ static const RttiInfo* get() { return GetRttiInfo<T>::get(); }
+};
+
+template <typename K, typename V>
+struct GetRttiInfo<Dictionary<K, V>>
+{
+ static const DictionaryRttiInfo _make()
+ {
+ DictionaryRttiInfo info;
+ info.init<Dictionary<Byte, Byte>>(RttiInfo::Kind::Dictionary);
+ info.m_keyType = GetRttiInfo<K>::get();
+ info.m_valueType = GetRttiInfo<V>::get();
+ return info;
+ }
+ static const RttiInfo* get() { static const DictionaryRttiInfo g_info = _make(); return &g_info; }
+};
+
+template <typename TARGET>
+struct GetRttiInfo<TARGET*>
+{
+ static const PtrRttiInfo _make()
+ {
+ PtrRttiInfo info;
+ info.init<void*>(RttiInfo::Kind::Ptr);
+ info.m_targetType = GetRttiInfo<TARGET>::get();
+ return info;
+ }
+ static const RttiInfo* get() { static const PtrRttiInfo g_info = _make(); return &g_info; }
+};
+
+template <typename TARGET>
+struct GetRttiInfo<RefPtr<TARGET>>
+{
+ static const RefPtrRttiInfo _make()
+ {
+ RefPtrRttiInfo info;
+ info.init<RefPtr<StringRepresentation>>(RttiInfo::Kind::RefPtr);
+ info.m_targetType = GetRttiInfo<TARGET>::get();
+ return info;
+ }
+ static const RttiInfo* get() { static const RefPtrRttiInfo g_info = _make(); return &g_info; }
+};
+
+template <typename T, size_t COUNT>
+struct GetRttiInfo<T[COUNT]>
+{
+ static const FixedArrayRttiInfo _make()
+ {
+ FixedArrayRttiInfo info;
+ info.m_kind = RttiInfo::Kind::FixedArray;
+ info.m_alignment = RttiInfo::AlignmentType(SLANG_ALIGN_OF(T));
+ info.m_size = RttiInfo::SizeType(sizeof(T) * COUNT);
+ info.m_elementType = GetRttiInfo<T>::get();
+ info.m_elementCount = COUNT;
+ return info;
+ }
+ static const RttiInfo* get() { static const FixedArrayRttiInfo g_info = _make(); return &g_info; }
+};
+
+struct StructRttiBuilder
+{
+ template <typename T>
+ StructRttiBuilder(T* obj, const char* name, const StructRttiInfo* super)
+ {
+ m_rttiInfo.init<T>(RttiInfo::Kind::Struct);
+ _init(name, super, (const Byte*)obj);
+ }
+
+ template <typename T>
+ void addField(const char* name, const T* fieldPtr, StructRttiInfo::Flags flags = 0)
+ {
+ StructRttiInfo::Field field;
+
+ field.m_name = name;
+ field.m_type = GetRttiInfo<T>::get();
+ field.m_offset = uint32_t(ptrdiff_t((const Byte*)fieldPtr - m_base));
+ field.m_flags = flags;
+ m_fields.add(field);
+ }
+
+ StructRttiInfo make();
+
+ void _init(const char* name, const StructRttiInfo* super, const Byte* base);
+
+ StructRttiInfo m_rttiInfo;
+
+ List<StructRttiInfo::Field> m_fields;
+ const Byte* m_base;
+};
+
+
+} // namespace Slang
+
+#endif // SLANG_CORE_RTTI_INFO_H
diff --git a/source/core/slang-rtti-util.cpp b/source/core/slang-rtti-util.cpp
new file mode 100644
index 000000000..ed4c32e58
--- /dev/null
+++ b/source/core/slang-rtti-util.cpp
@@ -0,0 +1,392 @@
+#include "slang-rtti-util.h"
+
+namespace Slang {
+
+/* static */SlangResult RttiUtil::setInt(int64_t value, const RttiInfo* rttiInfo, void* dst)
+{
+ SLANG_ASSERT(rttiInfo->isIntegral());
+
+ // We could check ranges are appropriate, but for now we just write.
+ // Passing in rttiInfo allows for other more complex types to be econverted
+ switch (rttiInfo->m_kind)
+ {
+ case RttiInfo::Kind::I32: *(int32_t*)dst = int32_t(value); break;
+ case RttiInfo::Kind::U32: *(uint32_t*)dst = uint32_t(value); break;
+ case RttiInfo::Kind::I64: *(int64_t*)dst = int64_t(value); break;
+ case RttiInfo::Kind::U64: *(uint64_t*)dst = uint64_t(value); break;
+ default: return SLANG_FAIL;
+ }
+ return SLANG_OK;
+}
+
+/* static */int64_t RttiUtil::getInt64(const RttiInfo* rttiInfo, const void* src)
+{
+ SLANG_ASSERT(rttiInfo->isIntegral());
+
+ switch (rttiInfo->m_kind)
+ {
+ case RttiInfo::Kind::I32: return *(const int32_t*)src;
+ case RttiInfo::Kind::U32: return *(const uint32_t*)src;
+ case RttiInfo::Kind::I64: return *(const int64_t*)src;
+ case RttiInfo::Kind::U64: return *(const uint64_t*)src;
+ default: break;
+ }
+
+ SLANG_ASSERT(!"Not integral!");
+ return -1;
+}
+
+/* static */double RttiUtil::asDouble(const RttiInfo* rttiInfo, const void* src)
+{
+ if (rttiInfo->isIntegral())
+ {
+ return (double)getInt64(rttiInfo, src);
+ }
+ else if (rttiInfo->isFloat())
+ {
+ switch (rttiInfo->m_kind)
+ {
+ case RttiInfo::Kind::F32: return *(const float*)src;
+ case RttiInfo::Kind::F64: return *(const double*)src;
+ default: break;
+ }
+ }
+
+ SLANG_ASSERT(!"Cannot convert to float");
+ return 0.0;
+}
+
+/* static */SlangResult RttiUtil::setFromDouble(double v, const RttiInfo* rttiInfo, void* dst)
+{
+ if (rttiInfo->isIntegral())
+ {
+ return setInt(int64_t(v), rttiInfo, dst);
+ }
+ else if (rttiInfo->isFloat())
+ {
+ switch (rttiInfo->m_kind)
+ {
+ case RttiInfo::Kind::F32: *(float*)dst = float(v); return SLANG_OK;
+ case RttiInfo::Kind::F64: *(double*)dst = v; return SLANG_OK;
+ default: break;
+ }
+ }
+
+ return SLANG_FAIL;
+}
+
+/* static */bool RttiUtil::asBool(const RttiInfo* rttiInfo, const void* src)
+{
+ if (rttiInfo->m_kind == RttiInfo::Kind::Bool)
+ {
+ return *(const bool*)src;
+ }
+
+ if (rttiInfo->isIntegral())
+ {
+ return getInt64(rttiInfo, src) != 0;
+ }
+ else if (rttiInfo->isFloat())
+ {
+ return asDouble(rttiInfo, src) != 0.0;
+ }
+
+ SLANG_ASSERT(!"Cannot convert to bool");
+ return false;
+}
+
+static int64_t _getIntDefaultValue(RttiDefaultValue value)
+{
+ switch (value)
+ {
+ default:
+ case RttiDefaultValue::Normal: return 0;
+ case RttiDefaultValue::One: return 1;
+ case RttiDefaultValue::MinusOne: return -1;
+ }
+}
+
+static bool _isStructDefault(const StructRttiInfo* type, const void* src)
+{
+ if (type->m_super)
+ {
+ if (!_isStructDefault(type->m_super, src))
+ {
+ return false;
+ }
+ }
+
+ const Byte* base = (const Byte*)src;
+
+ const Index count = type->m_fieldCount;
+ for (Index i = 0; i < count; ++i)
+ {
+ const auto& field = type->m_fields[i];
+
+ const RttiDefaultValue defaultValue = RttiDefaultValue(field.m_flags & uint8_t(RttiDefaultValue::Mask));
+
+ if (!RttiUtil::isDefault(defaultValue, field.m_type, base + field.m_offset))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* static */bool RttiUtil::isDefault(RttiDefaultValue defaultValue, const RttiInfo* rttiInfo, const void* src)
+{
+ if (rttiInfo->isIntegral())
+ {
+ const auto value = getInt64(rttiInfo, src);
+ return _getIntDefaultValue(defaultValue) == value;
+ }
+ else if (rttiInfo->isFloat())
+ {
+ const auto value = asDouble(rttiInfo, src);
+ return _getIntDefaultValue(defaultValue) == value;
+ }
+
+ switch (rttiInfo->m_kind)
+ {
+ case RttiInfo::Kind::Invalid: return true;
+ case RttiInfo::Kind::Bool: return *(const bool*)src == (_getIntDefaultValue(defaultValue) != 0);
+ case RttiInfo::Kind::String:
+ {
+ return ((const String*)src)->getLength() == 0;
+ }
+ case RttiInfo::Kind::UnownedStringSlice:
+ {
+ return ((const UnownedStringSlice*)src)->getLength() == 0;
+ }
+ case RttiInfo::Kind::Struct:
+ {
+ return _isStructDefault(static_cast<const StructRttiInfo*>(rttiInfo), src);
+ }
+ case RttiInfo::Kind::Enum:
+ {
+ SLANG_ASSERT(!"Not implemented yet");
+ return false;
+ }
+ case RttiInfo::Kind::List:
+ {
+ const auto& v = *(const List<Byte>*)src;
+ return v.getCount() == 0;
+ }
+ case RttiInfo::Kind::Dictionary:
+ {
+ const auto& v = *(const Dictionary<Byte, Byte>*)src;
+ return v.Count() == 0;
+ }
+ case RttiInfo::Kind::Other:
+ {
+ const OtherRttiInfo* otherRttiInfo = static_cast<const OtherRttiInfo*>(rttiInfo);
+ return otherRttiInfo->m_isDefaultFunc && otherRttiInfo->m_isDefaultFunc(rttiInfo, src);
+ }
+ default:
+ {
+ return false;
+ }
+ }
+}
+
+template <typename T>
+struct GetRttiTypeFuncsForBuiltIn
+{
+ static void ctorArray(const RttiInfo* rttiInfo, void* dst, Index count) { SLANG_UNUSED(rttiInfo); ::memset(dst, 0, sizeof(T) * count); }
+ static void dtorArray(const RttiInfo* rttiInfo, void* dst, Index count) { SLANG_UNUSED(rttiInfo); SLANG_UNUSED(dst); SLANG_UNUSED(count); }
+ static void copyArray(const RttiInfo* rttiInfo, void* dst, const void* src, Index count) { SLANG_UNUSED(rttiInfo); ::memcpy(dst, src, sizeof(T) * count); }
+
+ static RttiTypeFuncs getFuncs()
+ {
+ RttiTypeFuncs funcs;
+ funcs.copyArray = &copyArray;
+ funcs.dtorArray = &dtorArray;
+ funcs.ctorArray = &ctorArray;
+ return funcs;
+ }
+};
+
+struct ListFuncs
+{
+ 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;
+ }
+};
+
+RttiTypeFuncs RttiUtil::getTypeFuncs(const RttiInfo* rttiInfo)
+{
+ if (rttiInfo->isBuiltIn())
+ {
+ switch (rttiInfo->m_size)
+ {
+ case 1: return GetRttiTypeFuncsForBuiltIn<uint8_t>::getFuncs();
+ case 2: return GetRttiTypeFuncsForBuiltIn<uint16_t>::getFuncs();
+ case 4: return GetRttiTypeFuncsForBuiltIn<uint32_t>::getFuncs();
+ case 8: return GetRttiTypeFuncsForBuiltIn<uint64_t>::getFuncs();
+ }
+ return RttiTypeFuncs::makeEmpty();
+ }
+
+ switch (rttiInfo->m_kind)
+ {
+ case RttiInfo::Kind::String: return GetRttiTypeFuncs<String>::getFuncs();
+ case RttiInfo::Kind::UnownedStringSlice: return GetRttiTypeFuncs<UnownedStringSlice>::getFuncs();
+ case RttiInfo::Kind::List: return ListFuncs::getFuncs();
+ default: break;
+ }
+
+ return RttiTypeFuncs::makeEmpty();
+}
+
+/* static */SlangResult RttiUtil::setListCount(const RttiInfo* elementType, void* dst, Index count)
+{
+ // NOTE! The following only works because List<T> has capacity initialized members, and
+ // setting the count if it is <= capacity just sets the count (ie things aren't released(!)).
+
+ List<Byte>& dstList = *(List<Byte>*)dst;
+ const Index oldCount = dstList.getCount();
+ if (oldCount == count)
+ {
+ return SLANG_OK;
+ }
+ if (count < oldCount)
+ {
+ dstList.unsafeShrinkToCount(count);
+ return SLANG_OK;
+ }
+
+ // Get funcs needed
+ const auto typeFuncs = RttiUtil::getTypeFuncs(elementType);
+
+ if (!typeFuncs.isValid())
+ {
+ return SLANG_FAIL;
+ }
+
+ 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, oldCount);
+
+ // Attach the new buffer
+ dstList.attachBuffer((Byte*)newBuffer, count, count);
+
+ // Free the old buffer
+ if (oldBuffer)
+ {
+ typeFuncs.dtorArray(elementType, oldBuffer, dstCapacity);
+ ::free(oldBuffer);
+ }
+
+ return SLANG_OK;
+}
+
+} // namespace Slang
diff --git a/source/core/slang-rtti-util.h b/source/core/slang-rtti-util.h
new file mode 100644
index 000000000..d514d1980
--- /dev/null
+++ b/source/core/slang-rtti-util.h
@@ -0,0 +1,30 @@
+#ifndef SLANG_CORE_RTTI_UTIL_H
+#define SLANG_CORE_RTTI_UTIL_H
+
+#include "slang-rtti-info.h"
+
+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);
+
+ static double asDouble(const RttiInfo* rttiInfo, const void* src);
+
+ static SlangResult setFromDouble(double v, const RttiInfo* rttiInfo, void* dst);
+
+ static bool asBool(const RttiInfo* rttiInfo, const void* src);
+
+ static bool isDefault(RttiDefaultValue defaultValue, const RttiInfo* rttiInfo, const void* src);
+
+ static RttiTypeFuncs getTypeFuncs(const RttiInfo* rttiInfo);
+
+ /// Set a list count
+ static SlangResult setListCount(const RttiInfo* elementType, void* dst, Index count);
+
+};
+
+} // namespace Slang
+
+#endif // SLANG_CORE_RTTI_UTIL_H