Havok: Add hkClass and other reflection types

This commit is contained in:
Léo Lam 2022-01-05 23:55:54 +01:00
parent 2359ce6fb4
commit 000ca1c6d9
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
7 changed files with 523 additions and 24 deletions

View File

@ -21,6 +21,11 @@ add_library(hkStubs OBJECT
Havok/Common/Base/Object/hkReferencedObject.cpp
Havok/Common/Base/Object/hkReferencedObject.h
Havok/Common/Base/Reflection/hkClass.h
Havok/Common/Base/Reflection/hkClassEnum.h
Havok/Common/Base/Reflection/hkClassMember.h
Havok/Common/Base/Reflection/hkTypeInfo.h
Havok/Common/Base/Thread/Atomic/hkAtomicPrimitives.h
Havok/Common/Base/Thread/Thread/hkThreadLocalData.h

View File

@ -0,0 +1,114 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
class hkClassEnum;
class hkClassMember;
class hkCustomAttributes;
class hkStreamWriter;
class hkTypedUnion;
template <typename Key, typename Value>
class hkPointerMap;
class hkClass {
public:
HK_DECLARE_CLASS_ALLOCATOR(hkClass)
HK_DECLARE_REFLECTION()
enum SignatureFlags {
SIGNATURE_LOCAL = 1,
};
enum FlagValues {
FLAGS_NONE = 0,
FLAGS_NOT_SERIALIZABLE = 1,
};
using Flags = hkFlags<FlagValues, hkUint32>;
// Note: this is not constexpr and this is the reason Havok code is littered with
// static constructor functions that call this hkClass constructor at runtime
// even though everything could have been initialised at compile time.
hkClass(const char* className, const hkClass* parentClass, int objectSizeInBytes,
const hkClass** implementedInterfaces, int numImplementedInterfaces,
const hkClassEnum* declaredEnums, int numDeclaredEnums,
const hkClassMember* declaredMembers, int numDeclaredMembers,
const void* defaults = nullptr, const hkCustomAttributes* attributes = nullptr,
hkUint32 flags = 0, hkUint32 version = 0);
const char* getName() const;
bool equals(const hkClass* other) const;
const hkClass* getParent() const;
hkClass* getParent();
int getInheritanceDepth() const;
hkBool isSuperClass(const hkClass& k) const;
const hkClass* getInterface(int i) const;
int getNumInterfaces() const;
const hkClass* getDeclaredInterface(int i) const;
int getNumDeclaredInterfaces() const;
const hkClassEnum& getEnum(int i) const;
const hkClassEnum* getEnumByName(const char* name) const;
int getNumEnums() const;
const hkClassEnum& getDeclaredEnum(int i) const;
const hkClassEnum* getDeclaredEnumByName(const char* name) const;
int getNumDeclaredEnums() const;
const hkClassMember& getMember(int i) const;
hkClassMember& getMember(int i);
const hkClassMember* getMemberByName(const char* name) const;
int getMemberIndexByName(const char* name) const;
int getMemberIndexByNameCaseInsensitive(const char* name) const;
int getNumMembers() const;
const hkClassMember& getDeclaredMember(int i) const;
const hkClassMember* getDeclaredMemberByName(const char* name) const;
int getDeclaredMemberIndexByName(const char* name) const;
int getNumDeclaredMembers() const;
int getObjectSize() const;
void setObjectSize(int size);
hkBool hasVtable() const;
hkBool32 hasDefault(int memberIndex) const;
hkBool32 hasDeclaredDefault(int declaredIndex) const;
hkResult getDefault(int memberIndex, hkStreamWriter* w) const;
const void* getDefault(int memberIndex) const;
hkResult getDeclaredDefault(int declaredIndex, hkStreamWriter* w) const;
hkResult getDefault(int memberIndex, hkTypedUnion& value) const;
const void* getDeclaredDefault(int memberIndex) const;
hkResult getDeclaredDefault(int declaredIndex, hkTypedUnion& value) const;
hkUint32 getSignature(int signatureFlags = 0) const;
int getDescribedVersion() const;
void writeSignature(hkStreamWriter* w) const;
const hkVariant* getAttribute(const char* id) const;
const Flags& getFlags() const;
Flags& getFlags();
using UpdateFlagFromClassMap = hkPointerMap<const hkClass*, hkInt32>;
static void updateMetadataInplace(hkClass** c, int sourceVersion);
static void updateMetadataInplace(hkClass* c, UpdateFlagFromClassMap& updatedAlready,
int sourceVersion);
private:
hkResult retrieveMember(int memberIndex, const void*& defaultOut,
const hkClassMember*& memberOut) const;
protected:
const char* m_name;
const hkClass* m_parent;
int m_objectSize;
int m_numImplementedInterfaces;
const class hkClassEnum* m_declaredEnums;
int m_numDeclaredEnums;
const class hkClassMember* m_declaredMembers;
int m_numDeclaredMembers;
const void* m_defaults;
const hkCustomAttributes* m_attributes;
Flags m_flags;
int m_describedVersion;
};

View File

@ -0,0 +1,79 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
class hkCustomAttributes;
class hkStreamWriter;
class hkClassEnum {
public:
HK_DECLARE_CLASS_ALLOCATOR(hkClassEnum)
HK_DECLARE_REFLECTION()
class Item {
public:
HK_DECLARE_CLASS_ALLOCATOR(Item)
HK_DECLARE_REFLECTION()
constexpr Item(int v, const char* n) : m_value(v), m_name(n) {}
const char* getName() const { return m_name; }
int getValue() const { return m_value; }
private:
int m_value;
const char* m_name;
};
enum FlagValues { FLAGS_NONE = 0 };
using Flags = hkFlags<FlagValues, hkUint32>;
hkClassEnum(const char* name, const Item* items, int numItems);
constexpr hkClassEnum(const char* name, const Item* items, int numItems,
hkCustomAttributes* attributes, hkUint32 flags)
: m_name(name), m_items(items), m_numItems(numItems), m_attributes(attributes),
m_flags(flags) {}
const char* getName() const;
int getNumItems() const;
const hkClassEnum::Item& getItem(int i) const;
hkResult getNameOfValue(int val, const char** name) const;
hkResult getValueOfName(const char* name, int* val) const;
hkResult decomposeFlags(int flagValue, hkArray<const char*>& bitsOut, int& bitsOver) const;
hkUint32 getSignature() const;
void writeSignature(hkStreamWriter* w) const;
const hkVariant* getAttribute(const char* name) const;
inline const Flags& getFlags() const;
inline Flags& getFlags();
private:
const char* m_name;
const class Item* m_items;
int m_numItems;
hkCustomAttributes* m_attributes;
Flags m_flags;
};
inline hkClassEnum::hkClassEnum(const char* name, const hkClassEnum::Item* items, int numItems)
: m_name(name), m_items(items), m_numItems(numItems), m_attributes(nullptr), m_flags(0) {}
inline const char* hkClassEnum::getName() const {
return m_name;
}
inline int hkClassEnum::getNumItems() const {
return m_numItems;
}
inline const hkClassEnum::Item& hkClassEnum::getItem(int i) const {
return m_items[i];
}
inline const hkClassEnum::Flags& hkClassEnum::getFlags() const {
return m_flags;
}
inline hkClassEnum::Flags& hkClassEnum::getFlags() {
return m_flags;
}

View File

@ -0,0 +1,195 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
class hkClassEnum;
class hkCustomAttributes;
class hkClassMember {
public:
HK_DECLARE_CLASS_ALLOCATOR(hkClassMember)
HK_DECLARE_REFLECTION()
enum Type {
TYPE_VOID = 0,
TYPE_BOOL,
TYPE_CHAR,
TYPE_INT8,
TYPE_UINT8,
TYPE_INT16,
TYPE_UINT16,
TYPE_INT32,
TYPE_UINT32,
TYPE_INT64,
TYPE_UINT64,
TYPE_REAL,
TYPE_VECTOR4,
TYPE_QUATERNION,
TYPE_MATRIX3,
TYPE_ROTATION,
TYPE_QSTRANSFORM,
TYPE_MATRIX4,
TYPE_TRANSFORM,
TYPE_ZERO,
TYPE_POINTER,
TYPE_FUNCTIONPOINTER,
/// hkArray<T>
TYPE_ARRAY,
/// hkInplaceArray<T,N> or hkInplaceArrayAligned16<T,N>
TYPE_INPLACEARRAY,
/// hkEnum<ENUM,STORAGE>
TYPE_ENUM,
TYPE_STRUCT,
TYPE_SIMPLEARRAY,
TYPE_HOMOGENEOUSARRAY,
TYPE_VARIANT,
TYPE_CSTRING,
TYPE_ULONG,
TYPE_FLAGS,
TYPE_HALF,
/// hkStringPtr
TYPE_STRINGPTR,
/// hkRelArray
TYPE_RELARRAY,
TYPE_MAX
};
enum FlagValues {
FLAGS_NONE = 0,
ALIGN_8 = 1 << 7,
ALIGN_16 = 1 << 8,
NOT_OWNED = 1 << 9,
SERIALIZE_IGNORED = 1 << 10,
ALIGN_32 = 1 << 11,
#ifdef HK_REAL_IS_DOUBLE
ALIGN_REAL = ALIGN_32,
#else
ALIGN_REAL = ALIGN_16,
#endif
};
using Flags = hkFlags<FlagValues, hkUint16>;
enum DeprecatedFlagValues {
DEPRECATED_SIZE_8 = 8,
DEPRECATED_ENUM_8 = 8,
DEPRECATED_SIZE_16 = 16,
DEPRECATED_ENUM_16 = 16,
DEPRECATED_SIZE_32 = 32,
DEPRECATED_ENUM_32 = 32,
};
enum {
HK_CLASS_ZERO_DEFAULT = -2,
};
constexpr hkClassMember(const char* name, const hkClass* class_, const hkClassEnum* enum_,
const hkEnum<Type, hkUint8>& type, const hkEnum<Type, hkUint8>& subtype,
hkInt16 cArraySize, hkUint16 flags, hkUint16 offset,
const hkCustomAttributes* attributes)
: m_name(name), m_class(class_), m_enum(enum_), m_type(type), m_subtype(subtype),
m_cArraySize(cArraySize), m_flags(flags), m_offset(offset), m_attributes(attributes) {}
inline const char* getName() const;
inline hkClassMember::Type getType() const;
inline void setType(hkClassMember::Type type);
inline hkClassMember::Type getSubType() const;
inline void setSubType(hkClassMember::Type subtype);
hkClassMember::Type getArrayType() const;
int getSizeInBytes() const;
int getAlignment() const;
hkBool isNotOwner() const;
int getTypeName(char* buf, int bufLen) const;
int getArrayMemberSize() const;
inline hkBool hasClass() const;
const hkClass& getStructClass() const;
const hkClass* getClass() const;
inline hkBool hasEnumClass() const;
const hkClassEnum& getEnumClass() const;
int getCstyleArraySize() const;
const hkClassEnum& getEnumType() const;
int getEnumValue(const void* memberAddress) const;
void setEnumValue(void* memberAddress, int value) const;
inline int getOffset() const;
inline void setOffset(int offset);
inline const Flags& getFlags() const;
inline Flags& getFlags();
const hkVariant* getAttribute(const char* id) const;
static hkClassMember::Type getTypeOf(const char* name);
static hkClassMember::Type getSubtypeOf(const char* name);
struct TypeProperties {
HK_DECLARE_CLASS_ALLOCATOR(hkClassMember::TypeProperties)
hkEnum<hkClassMember::Type, hkUint8> m_type;
const char* m_name;
short m_size;
short m_align;
};
static const TypeProperties& getClassMemberTypeProperties(Type type);
private:
const char* m_name;
const hkClass* m_class;
const hkClassEnum* m_enum;
hkEnum<Type, hkUint8> m_type;
hkEnum<Type, hkUint8> m_subtype;
hkInt16 m_cArraySize;
Flags m_flags;
hkUint16 m_offset;
const hkCustomAttributes* m_attributes;
};
inline const char* hkClassMember::getName() const {
return m_name;
}
inline hkClassMember::Type hkClassMember::getType() const {
return static_cast<Type>(m_type);
}
inline void hkClassMember::setType(hkClassMember::Type type) {
m_type = type;
}
inline hkClassMember::Type hkClassMember::getSubType() const {
return static_cast<Type>(m_subtype);
}
inline void hkClassMember::setSubType(hkClassMember::Type subtype) {
m_subtype = subtype;
}
inline int hkClassMember::getOffset() const {
return m_offset;
}
inline void hkClassMember::setOffset(int offset) {
m_offset = static_cast<hkUint16>(offset);
}
inline const hkClassMember::Flags& hkClassMember::getFlags() const {
return m_flags;
}
inline hkClassMember::Flags& hkClassMember::getFlags() {
return m_flags;
}
inline hkBool hkClassMember::hasClass() const {
return m_class != nullptr;
}
inline hkBool hkClassMember::hasEnumClass() const {
return m_enum != nullptr;
}

View File

@ -0,0 +1,91 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
#include <cstring>
#include <type_traits>
class hkClass;
class hkTypeInfo {
public:
HK_DECLARE_CLASS_ALLOCATOR(hkTypeInfo)
using FinishLoadedObjectFunction = void (*)(void*, int);
using CleanupLoadedObjectFunction = void (*)(void*);
template <typename T>
HK_ALWAYS_INLINE static hkTypeInfo make(const char* name, const char* scopedName) {
FinishLoadedObjectFunction finish = nullptr;
constexpr bool needsFinish = std::is_constructible_v<T, hkFinishLoadedObjectFlag>;
if constexpr (needsFinish)
finish = finishFunctionImpl<T>;
CleanupLoadedObjectFunction cleanup = cleanupFunctionImpl<T>;
const void* vtable = nullptr;
if constexpr (std::is_polymorphic_v<T>) {
static_assert(needsFinish, "polymorphic types must have a finish constructor");
vtable = getVtableFunctionImpl<T>();
}
return hkTypeInfo{name, scopedName, finish, cleanup, vtable, sizeof(T)};
}
hkTypeInfo(const char* name, const char* scopedName, FinishLoadedObjectFunction finish,
CleanupLoadedObjectFunction cleanup, const void* vtable, hk_size_t size)
: m_typeName(name), m_scopedName(scopedName), m_finishLoadedObjectFunction(finish),
m_cleanupLoadedObjectFunction(cleanup), m_vtable(vtable), m_size(size) {}
const char* getTypeName() const { return m_typeName; }
const char* getScopedName() const { return m_scopedName; }
const void* getVtable() const { return m_vtable; }
void cleanupLoadedObject(void* ptr) const;
void finishLoadedObject(void* ptr, int finishFlag) const;
void finishLoadedObjectWithoutTracker(void* ptr, int finishFlag) const;
hkBool hasFinishFunction() const { return m_finishLoadedObjectFunction != nullptr; }
hkBool hasCleanupFunction() const { return m_cleanupLoadedObjectFunction != nullptr; }
hk_size_t getSize() const { return m_size; }
hkBool isVirtual() const { return m_vtable != nullptr; }
private:
template <typename T>
HK_VISIBILITY_HIDDEN static void finishFunctionImpl(void* p, int finishing) {
hkFinishLoadedObjectFlag flag{finishing};
new (p) T{flag};
}
template <typename T>
HK_VISIBILITY_HIDDEN static void cleanupFunctionImpl(void* p) {
static_cast<T*>(p)->~T();
}
template <typename T>
HK_VISIBILITY_HIDDEN static const void* getVtableFunctionImpl() {
// The following trick only works because all Havok polymorphic types are supposed
// to have hkBaseObject as the most-base class -- forcing the vtable to be at offset 0.
//
// Unfortunately we can't check if hkBaseObject is at offset 0, but let's at least
// verify that hkBaseObject is a base class of T.
static_assert(std::is_base_of_v<hkBaseObject, T>,
"polymorphic types must have hkBaseObject as a base");
union {
alignas(16) void* dummy;
std::aligned_storage_t<sizeof(T), alignof(T)> obj;
};
hkFinishLoadedObjectFlag flag;
new (static_cast<void*>(std::addressof(obj))) T{flag};
const void* vtable_ptr;
std::memcpy(&vtable_ptr, &obj, sizeof(vtable_ptr));
return vtable_ptr;
}
const char* m_typeName;
const char* m_scopedName;
FinishLoadedObjectFunction m_finishLoadedObjectFunction;
CleanupLoadedObjectFunction m_cleanupLoadedObjectFunction;
const void* m_vtable;
hk_size_t m_size;
};

View File

@ -3,3 +3,5 @@
#define HK_FORCE_INLINE inline
#define HK_ALWAYS_INLINE HK_FORCE_INLINE
#define HK_NEVER_INLINE __attribute__((noinline))
#define HK_VISIBILITY_HIDDEN __attribute__((visibility("hidden")))

View File

@ -7,6 +7,7 @@
using hkFloat32 = float;
using hkDouble64 = double;
using hkReal = hkFloat32;
#define HK_REAL_IS_FLOAT
using hkChar = char;
using hkInt8 = std::int8_t;
@ -75,17 +76,17 @@ class hkBool {
public:
HK_ALWAYS_INLINE hkBool() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
HK_FORCE_INLINE hkBool(bool b) : m_bool(static_cast<char>(b)) {}
HK_FORCE_INLINE constexpr hkBool(bool b) : m_bool(static_cast<char>(b)) {}
HK_FORCE_INLINE explicit operator bool() const { return m_bool != 0; }
HK_FORCE_INLINE constexpr explicit operator bool() const { return m_bool != 0; }
HK_FORCE_INLINE hkBool& operator=(bool e) {
HK_FORCE_INLINE constexpr hkBool& operator=(bool e) {
m_bool = static_cast<char>(e);
return *this;
}
HK_FORCE_INLINE hkBool operator==(bool e) const { return (m_bool != 0) == e; }
HK_FORCE_INLINE hkBool operator!=(bool e) const { return (m_bool != 0) != e; }
HK_FORCE_INLINE constexpr hkBool operator==(bool e) const { return (m_bool != 0) == e; }
HK_FORCE_INLINE constexpr hkBool operator!=(bool e) const { return (m_bool != 0) != e; }
private:
char m_bool;
@ -100,18 +101,19 @@ template <typename Enum, typename Storage>
struct hkEnum {
HK_ALWAYS_INLINE hkEnum() {}
hkEnum(Enum value) { *this = value; } // NOLINT(google-explicit-constructor)
constexpr hkEnum(Enum value) // NOLINT(google-explicit-constructor)
: m_storage(static_cast<Storage>(value)) {}
// NOLINTNEXTLINE(google-explicit-constructor)
operator Enum() const { return static_cast<Enum>(m_storage); }
constexpr operator Enum() const { return static_cast<Enum>(m_storage); }
hkEnum& operator=(Enum value) {
constexpr hkEnum& operator=(Enum value) {
m_storage = static_cast<Storage>(value);
return *this;
}
bool operator==(Enum e) const { return m_storage == static_cast<Storage>(e); }
bool operator!=(Enum e) const { return m_storage != static_cast<Storage>(e); }
constexpr bool operator==(Enum e) const { return m_storage == static_cast<Storage>(e); }
constexpr bool operator!=(Enum e) const { return m_storage != static_cast<Storage>(e); }
Storage m_storage;
};
@ -120,29 +122,31 @@ template <typename, typename Storage>
class hkFlags {
public:
HK_FORCE_INLINE hkFlags() {}
HK_FORCE_INLINE explicit hkFlags(Storage s) : m_storage(s) {}
HK_FORCE_INLINE constexpr explicit hkFlags(Storage s) : m_storage(s) {}
HK_FORCE_INLINE void clear() { m_storage = 0; }
HK_FORCE_INLINE void clear(Storage mask) { m_storage &= ~mask; }
HK_FORCE_INLINE void setAll(Storage s) { m_storage = s; }
HK_FORCE_INLINE constexpr void clear() { m_storage = 0; }
HK_FORCE_INLINE constexpr void clear(Storage mask) { m_storage &= ~mask; }
HK_FORCE_INLINE constexpr void setAll(Storage s) { m_storage = s; }
HK_FORCE_INLINE void operator|=(Storage s) { m_storage |= s; }
HK_FORCE_INLINE void operator^=(Storage s) { m_storage ^= s; }
HK_FORCE_INLINE void operator&=(Storage s) { m_storage &= s; }
HK_FORCE_INLINE constexpr void operator|=(Storage s) { m_storage |= s; }
HK_FORCE_INLINE constexpr void operator^=(Storage s) { m_storage ^= s; }
HK_FORCE_INLINE constexpr void operator&=(Storage s) { m_storage &= s; }
HK_FORCE_INLINE void setWithMask(Storage s, Storage mask) {
HK_FORCE_INLINE constexpr void setWithMask(Storage s, Storage mask) {
m_storage = (m_storage & ~mask) | (s & mask);
}
HK_FORCE_INLINE Storage get() const { return m_storage; }
HK_FORCE_INLINE bool anyIsSet(Storage mask) const { return (m_storage & mask) != 0; }
HK_FORCE_INLINE bool noneIsSet(Storage mask) const { return (m_storage & mask) == 0; }
HK_FORCE_INLINE bool allAreSet(Storage mask) const { return (m_storage & mask) == mask; }
HK_FORCE_INLINE constexpr Storage get() const { return m_storage; }
HK_FORCE_INLINE constexpr bool anyIsSet(Storage mask) const { return (m_storage & mask) != 0; }
HK_FORCE_INLINE constexpr bool noneIsSet(Storage mask) const { return (m_storage & mask) == 0; }
HK_FORCE_INLINE constexpr bool allAreSet(Storage mask) const {
return (m_storage & mask) == mask;
}
HK_FORCE_INLINE bool operator==(const hkFlags& other) const {
HK_FORCE_INLINE constexpr bool operator==(const hkFlags& other) const {
return other.m_storage == m_storage;
}
HK_FORCE_INLINE bool operator!=(const hkFlags& other) const {
HK_FORCE_INLINE constexpr bool operator!=(const hkFlags& other) const {
return other.m_storage != m_storage;
}
@ -187,3 +191,12 @@ public:
HK_FORCE_INLINE hkLong hkGetByteOffset(const void* base, const void* pntr) {
return hkLong(pntr) - hkLong(base);
}
class hkClass;
struct hkVariant {
void* m_object;
const hkClass* m_class;
};
#define HK_DECLARE_REFLECTION() static const hkClass& staticClass();