#include "slang-rtti-info.h" #include "slang-com-helper.h" #include "slang-rtti-util.h" #include 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(alignof(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), 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 guard(m_mutex); return m_arena.allocate(size); } void deallocateAll() { std::lock_guard guard(m_mutex); m_arena.reset(); } 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); } /* static */ void RttiInfo::deallocateAll() { return RttiInfoManager::getSingleton().deallocateAll(); } /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StructRttiBuilder !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ static void _appendFixedArray(const FixedArrayRttiInfo* inFixedArray, StringBuilder& out) { List fixedArrays; fixedArrays.add(inFixedArray); const RttiInfo* cur = inFixedArray->m_elementType; while (cur->m_kind == RttiInfo::Kind::FixedArray) { const FixedArrayRttiInfo* curArray = static_cast(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(info); append(ptrRttiInfo->m_targetType, out); out << "*"; break; } case RttiInfo::Kind::RefPtr: { const RefPtrRttiInfo* ptrRttiInfo = static_cast(info); out << "RefPtr<"; append(ptrRttiInfo->m_targetType, out); out << ">"; break; } case RttiInfo::Kind::FixedArray: { const FixedArrayRttiInfo* arrayRttiInfo = static_cast(info); _appendFixedArray(arrayRttiInfo, out); break; } case RttiInfo::Kind::List: { const ListRttiInfo* listRttiInfo = static_cast(info); out << "List<"; append(listRttiInfo->m_elementType, out); out << ">"; break; } case RttiInfo::Kind::Dictionary: { const DictionaryRttiInfo* dictionaryRttiInfo = static_cast(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(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; } /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RttiTypeFuncsMap !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ RttiTypeFuncs RttiTypeFuncsMap::getFuncsForType(const RttiInfo* rttiInfo) { if (auto funcsPtr = m_map.tryGetValue(rttiInfo)) { return *funcsPtr; } // Try to get the default impl // NOTE! funcs could be invalid if there is no default impl. const auto funcs = RttiUtil::getDefaultTypeFuncs(rttiInfo); // Add to the map m_map.add(rttiInfo, funcs); return funcs; } void RttiTypeFuncsMap::add(const RttiInfo* rttiInfo, const RttiTypeFuncs& funcs) { if (auto funcsPtr = m_map.tryGetValueOrAdd(rttiInfo, funcs)) { // If there are funcs set, they aren't valid otherwise this would be // replacing, so assert on that scenario. SLANG_ASSERT(!funcsPtr->isValid()); // Replace the funcs *funcsPtr = funcs; } } } // namespace Slang