Skip to content

Commit

Permalink
Core: Natively convert enum/BitField with Variant
Browse files Browse the repository at this point in the history
  • Loading branch information
Repiteo committed Jan 5, 2025
1 parent bdf625b commit 99a936f
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 357 deletions.
69 changes: 2 additions & 67 deletions core/variant/binder_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,73 +82,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) SET_QUALIFIED_NAME(m_enum)
#define VARIANT_BITFIELD_CAST(m_enum) SET_QUALIFIED_NAME(m_enum)

// Object enum casts must go here
VARIANT_ENUM_CAST(Object::ConnectFlags);
Expand Down
29 changes: 27 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 @@ -104,6 +104,28 @@ struct PtrToArg {};
} \
}

#define MAKE_PTRARGCONV_CONDITIONAL(m_type, m_conv, m_conditional) \
template <typename T> \
struct PtrToArg<m_type, std::enable_if_t<m_conditional>> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
} \
typedef m_conv EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
} \
}; \
template <typename T> \
struct PtrToArg<const m_type &, std::enable_if_t<m_conditional>> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
} \
typedef m_conv EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \
} \
}

MAKE_PTRARGCONV(bool, uint8_t);
// Integer types.
MAKE_PTRARGCONV(uint8_t, int64_t);
Expand Down Expand Up @@ -155,6 +177,9 @@ MAKE_PTRARG(PackedColorArray);
MAKE_PTRARG(PackedVector4Array);
MAKE_PTRARG_BY_REFERENCE(Variant);

MAKE_PTRARGCONV_CONDITIONAL(T, int64_t, std::is_enum_v<T>);
MAKE_PTRARGCONV_CONDITIONAL(BitField<T>, int64_t, std::is_enum_v<T>);

// This is for Object.

template <typename T>
Expand Down
111 changes: 33 additions & 78 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" // IWYU pragma: keep // Used in macros.
#include "core/typedefs.h"

#include <type_traits>
Expand Down Expand Up @@ -220,31 +221,31 @@ inline String enum_qualified_name_to_class_info_name(const String &p_qualified_n
// Contains namespace. We only want the class and enum names.
return parts[parts.size() - 2] + "." + parts[parts.size() - 1];
}

template <typename T>
struct GetQualifiedName;

} // 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))); \
} \
#define SET_QUALIFIED_NAME(m_enum) \
template <> \
struct godot::details::GetQualifiedName<m_enum> { \
static inline String value = enum_qualified_name_to_class_info_name(String(#m_enum)); \
};

#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 &)
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::GetQualifiedName<GetSimpleTypeT<T>>::value);
}
};

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);
}
return GetTypeInfo<T>::get_class_info().class_name;
}

Expand All @@ -265,79 +266,33 @@ 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>, 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_BITFIELD,
godot::details::GetQualifiedName<GetSimpleTypeT<T>>::value);
}
};

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);
}
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
}
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())

// No initialization by default, except for scalar types.
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; }
};

template <typename T>
struct ZeroInitializer<T *> {
static void initialize(T *&value) { value = nullptr; }
static void initialize(T &value) {
if constexpr (std::is_scalar_v<T>) {
value = {};
}
}
};

#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 @@ -2436,14 +2436,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
33 changes: 13 additions & 20 deletions core/variant/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class RefCounted;

template <typename T>
class Ref;
template <typename T>
class BitField;

struct PropertyInfo;
struct MethodInfo;
Expand Down Expand Up @@ -441,12 +443,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>
_FORCE_INLINE_ operator T() const { return static_cast<T>(operator int64_t()); }
template <typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
_FORCE_INLINE_ 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 @@ -509,22 +512,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>
_FORCE_INLINE_ Variant(T p_enum) :
Variant(static_cast<int64_t>(p_enum)) {}
template <typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
_FORCE_INLINE_ Variant(BitField<T> p_bitfield) :
Variant(static_cast<int64_t>(p_bitfield)) {}

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

0 comments on commit 99a936f

Please sign in to comment.