Skip to content

Commit

Permalink
Core: Natively bind all enums/bitfields to Variant
Browse files Browse the repository at this point in the history
  • Loading branch information
Repiteo committed Sep 22, 2024
1 parent e4e024a commit 9fac614
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 162 deletions.
57 changes: 2 additions & 55 deletions core/variant/binder_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,61 +83,8 @@ struct VariantCaster<const T &> {
}
};

#define VARIANT_ENUM_CAST(m_enum) \
MAKE_ENUM_TYPE_INFO(m_enum) \
template <> \
struct VariantCaster<m_enum> { \
static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \
return (m_enum)p_variant.operator int64_t(); \
} \
}; \
template <> \
struct PtrToArg<m_enum> { \
_FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \
return m_enum(*reinterpret_cast<const int64_t *>(p_ptr)); \
} \
typedef int64_t EncodeT; \
_FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \
*(int64_t *)p_ptr = (int64_t)p_val; \
} \
}; \
template <> \
struct ZeroInitializer<m_enum> { \
static void initialize(m_enum &value) { value = (m_enum)0; } \
}; \
template <> \
struct VariantInternalAccessor<m_enum> { \
static _FORCE_INLINE_ m_enum get(const Variant *v) { return m_enum(*VariantInternal::get_int(v)); } \
static _FORCE_INLINE_ void set(Variant *v, m_enum p_value) { *VariantInternal::get_int(v) = (int64_t)p_value; } \
};

#define VARIANT_BITFIELD_CAST(m_enum) \
MAKE_BITFIELD_TYPE_INFO(m_enum) \
template <> \
struct VariantCaster<BitField<m_enum>> { \
static _FORCE_INLINE_ BitField<m_enum> cast(const Variant &p_variant) { \
return BitField<m_enum>(p_variant.operator int64_t()); \
} \
}; \
template <> \
struct PtrToArg<BitField<m_enum>> { \
_FORCE_INLINE_ static BitField<m_enum> convert(const void *p_ptr) { \
return BitField<m_enum>(*reinterpret_cast<const int64_t *>(p_ptr)); \
} \
typedef int64_t EncodeT; \
_FORCE_INLINE_ static void encode(BitField<m_enum> p_val, const void *p_ptr) { \
*(int64_t *)p_ptr = p_val; \
} \
}; \
template <> \
struct ZeroInitializer<BitField<m_enum>> { \
static void initialize(BitField<m_enum> &value) { value = 0; } \
}; \
template <> \
struct VariantInternalAccessor<BitField<m_enum>> { \
static _FORCE_INLINE_ BitField<m_enum> get(const Variant *v) { return BitField<m_enum>(*VariantInternal::get_int(v)); } \
static _FORCE_INLINE_ void set(Variant *v, BitField<m_enum> p_value) { *VariantInternal::get_int(v) = p_value.operator int64_t(); } \
};
#define VARIANT_ENUM_CAST(m_enum) STORE_READABLE_TYPE(m_enum)
#define VARIANT_BITFIELD_CAST(m_enum) STORE_READABLE_TYPE(m_enum)

// Object enum casts must go here
VARIANT_ENUM_CAST(Object::ConnectFlags);
Expand Down
30 changes: 28 additions & 2 deletions core/variant/method_ptrcall.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
#include "core/typedefs.h"
#include "core/variant/variant.h"

template <typename T>
struct PtrToArg {};
template <typename T, typename = void>
struct PtrToArg;

#define MAKE_PTRARG(m_type) \
template <> \
Expand Down Expand Up @@ -155,6 +155,32 @@ MAKE_PTRARG(PackedColorArray);
MAKE_PTRARG(PackedVector4Array);
MAKE_PTRARG_BY_REFERENCE(Variant);

// This is for Enum/BitField.

template <typename T>
struct PtrToArg<T, std::enable_if_t<std::is_enum_v<T>>> {
using SimpleT = GetSimpleTypeT<T>;
_FORCE_INLINE_ static SimpleT convert(const void *p_ptr) {
return SimpleT(*reinterpret_cast<const int64_t *>(p_ptr));
}
typedef int64_t EncodeT;
_FORCE_INLINE_ static void encode(SimpleT p_val, const void *p_ptr) {
*(int64_t *)p_ptr = (int64_t)p_val;
}
};

template <typename T>
struct PtrToArg<BitField<T>> {
using SimpleT = GetSimpleTypeT<T>;
_FORCE_INLINE_ static BitField<SimpleT> convert(const void *p_ptr) {
return SimpleT(*reinterpret_cast<const int64_t *>(p_ptr));
}
typedef int64_t EncodeT;
_FORCE_INLINE_ static void encode(BitField<SimpleT> p_val, const void *p_ptr) {
*(int64_t *)p_ptr = (int64_t)p_val;
}
};

// This is for Object.

template <typename T>
Expand Down
120 changes: 46 additions & 74 deletions core/variant/type_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#ifndef TYPE_INFO_H
#define TYPE_INFO_H

#include "core/templates/simple_type.h"
#include "core/typedefs.h"

#include <type_traits>
Expand Down Expand Up @@ -212,6 +213,15 @@ struct GetTypeInfo<T *, std::enable_if_t<std::is_base_of_v<Object, T>>> {

namespace godot {
namespace details {

template <typename T>
struct _ReadableType {
static constexpr const char *value() { return nullptr; }
};

template <typename T>
inline constexpr const char *readable_type_v = _ReadableType<GetSimpleTypeT<T>>::value();

inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) {
Vector<String> parts = p_qualified_name.split("::", false);
if (parts.size() <= 2) {
Expand All @@ -223,28 +233,25 @@ inline String enum_qualified_name_to_class_info_name(const String &p_qualified_n
} // namespace details
} // namespace godot

#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, \
godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \
} \
};
template <typename T>
struct GetTypeInfo<T, std::enable_if_t<std::is_enum_v<T>>> {
static const Variant::Type VARIANT_TYPE = Variant::INT;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM,
godot::details::enum_qualified_name_to_class_info_name(godot::details::readable_type_v<T>));
}
};

#define MAKE_ENUM_TYPE_INFO(m_enum) \
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum) \
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum const) \
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum &) \
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &)
#define STORE_READABLE_TYPE(m_type) \
template <> \
struct godot::details::_ReadableType<m_type> { \
static constexpr const char *value() { return #m_type; } \
};

template <typename T>
inline StringName __constant_get_enum_name(T param, const String &p_constant) {
if constexpr (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT("Missing VARIANT_ENUM_CAST for constant's enum: " + p_constant);
}
static_assert(godot::details::readable_type_v<T>, "Missing STORE_READABLE_TYPE for enum.");
return GetTypeInfo<T>::get_class_info().class_name;
}

Expand All @@ -265,77 +272,42 @@ class BitField {
_FORCE_INLINE_ constexpr BitField(int64_t p_value) { value = p_value; }
_FORCE_INLINE_ constexpr BitField(T p_value) { value = (int64_t)p_value; }
_FORCE_INLINE_ operator int64_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; }
_FORCE_INLINE_ BitField<T> operator^(const BitField<T> &p_b) const { return BitField<T>(value ^ p_b.value); }
};

#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \
} \
}; \
template <> \
struct GetTypeInfo<BitField<m_impl>> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
godot::details::enum_qualified_name_to_class_info_name(String(#m_enum))); \
} \
};

#define MAKE_BITFIELD_TYPE_INFO(m_enum) \
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum) \
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum const) \
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum &) \
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &)
template <typename T>
struct GetTypeInfo<BitField<T>> {
static const Variant::Type VARIANT_TYPE = Variant::INT;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD,
godot::details::enum_qualified_name_to_class_info_name(godot::details::readable_type_v<T>));
}
};

template <typename T>
inline StringName __constant_get_bitfield_name(T param, const String &p_constant) {
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT("Missing VARIANT_ENUM_CAST for constant's bitfield: " + p_constant);
}
static_assert(godot::details::readable_type_v<T>, "Missing STORE_READABLE_TYPE for bitfield.");
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
}
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())

template <typename T>
struct ZeroInitializer {
static void initialize(T &value) {} //no initialization by default
};

template <>
struct ZeroInitializer<bool> {
static void initialize(bool &value) { value = false; }
static void initialize(T &value) {
if constexpr (std::is_pointer_v<T>) {
value = nullptr;
} else if constexpr (std::is_arithmetic_v<T> || std::is_enum_v<T>) {
value = T(0);
} else {
// No initialization by default.
}
}
};

template <typename T>
struct ZeroInitializer<T *> {
static void initialize(T *&value) { value = nullptr; }
struct ZeroInitializer<BitField<T>> {
static void initialize(BitField<T> &value) { value = T(0); }
};

#define ZERO_INITIALIZER_NUMBER(m_type) \
template <> \
struct ZeroInitializer<m_type> { \
static void initialize(m_type &value) { value = 0; } \
};

ZERO_INITIALIZER_NUMBER(uint8_t)
ZERO_INITIALIZER_NUMBER(int8_t)
ZERO_INITIALIZER_NUMBER(uint16_t)
ZERO_INITIALIZER_NUMBER(int16_t)
ZERO_INITIALIZER_NUMBER(uint32_t)
ZERO_INITIALIZER_NUMBER(int32_t)
ZERO_INITIALIZER_NUMBER(uint64_t)
ZERO_INITIALIZER_NUMBER(int64_t)
ZERO_INITIALIZER_NUMBER(char16_t)
ZERO_INITIALIZER_NUMBER(char32_t)
ZERO_INITIALIZER_NUMBER(float)
ZERO_INITIALIZER_NUMBER(double)

#endif // TYPE_INFO_H
8 changes: 0 additions & 8 deletions core/variant/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2393,14 +2393,6 @@ Variant::operator Vector<StringName>() const {
return to;
}

Variant::operator Side() const {
return (Side) operator int();
}

Variant::operator Orientation() const {
return (Orientation) operator int();
}

Variant::operator IPAddress() const {
if (type == PACKED_FLOAT32_ARRAY || type == PACKED_INT32_ARRAY || type == PACKED_FLOAT64_ARRAY || type == PACKED_INT64_ARRAY || type == PACKED_BYTE_ARRAY) {
Vector<int> addr = operator Vector<int>();
Expand Down
34 changes: 14 additions & 20 deletions core/variant/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class Object;
struct PropertyInfo;
struct MethodInfo;

template <typename T>
class BitField;

typedef Vector<uint8_t> PackedByteArray;
typedef Vector<int32_t> PackedInt32Array;
typedef Vector<int64_t> PackedInt64Array;
Expand Down Expand Up @@ -422,12 +425,13 @@ class Variant {
operator Vector<Variant>() const;
operator Vector<StringName>() const;

// some core type enums to convert to
operator Side() const;
operator Orientation() const;

operator IPAddress() const;

template <typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
operator T() const { return static_cast<T>(operator int64_t()); }
template <typename T>
operator BitField<T>() const { return static_cast<T>(operator int64_t()); }

Object *get_validated_object() const;
Object *get_validated_object_with_check(bool &r_previously_freed) const;

Expand Down Expand Up @@ -490,22 +494,12 @@ class Variant {

Variant(const IPAddress &p_address);

#define VARIANT_ENUM_CLASS_CONSTRUCTOR(m_enum) \
Variant(m_enum p_value) : \
type(INT) { \
_data._int = (int64_t)p_value; \
}

// Only enum classes that need to be bound need this to be defined.
VARIANT_ENUM_CLASS_CONSTRUCTOR(EulerOrder)
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyAxis)
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyButton)
VARIANT_ENUM_CLASS_CONSTRUCTOR(Key)
VARIANT_ENUM_CLASS_CONSTRUCTOR(KeyLocation)
VARIANT_ENUM_CLASS_CONSTRUCTOR(MIDIMessage)
VARIANT_ENUM_CLASS_CONSTRUCTOR(MouseButton)

#undef VARIANT_ENUM_CLASS_CONSTRUCTOR
template <typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
Variant(T p_enum) :
Variant(static_cast<int64_t>(p_enum)) {}
template <typename T>
Variant(BitField<T> p_bit_field) :
Variant(static_cast<int64_t>(p_bit_field)) {}

// If this changes the table in variant_op must be updated
enum Operator {
Expand Down
Loading

0 comments on commit 9fac614

Please sign in to comment.