Skip to content

Commit

Permalink
Added some comments and simplified some names.
Browse files Browse the repository at this point in the history
  • Loading branch information
nlupugla committed Nov 12, 2024
1 parent d25fe05 commit ab4d72f
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 65 deletions.
17 changes: 8 additions & 9 deletions core/object/method_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,15 @@ enum MethodFlags {

struct MethodInfo {
STRUCT_DECLARE(MethodInfo);
STRUCT_MEMBER_PRIMITIVE(String, name, String());
STRUCT_MEMBER_PRIMITIVE_FROM_TO_ALIAS(List<PropertyInfo>, arguments, "args", List<PropertyInfo>());
STRUCT_MEMBER_PRIMITIVE_ALIAS(Vector<Variant>, default_arguments, "default_args", Vector<Variant>());
STRUCT_MEMBER_PRIMITIVE(uint32_t, flags, METHOD_FLAGS_DEFAULT);
STRUCT_MEMBER_PRIMITIVE(int, id, 0);
STRUCT_MEMBER(String, name, String());
STRUCT_MEMBER_FROM_TO_ALIAS(List<PropertyInfo>, arguments, "args", List<PropertyInfo>());
STRUCT_MEMBER_ALIAS(Vector<Variant>, default_arguments, "default_args", Vector<Variant>());
STRUCT_MEMBER(uint32_t, flags, METHOD_FLAGS_DEFAULT);
STRUCT_MEMBER(int, id, 0);
STRUCT_MEMBER_STRUCT_FROM_TO_ALIAS(PropertyInfo, return_val, "return", PropertyInfo());

STRUCT_MEMBER_PRIMITIVE(int, return_val_metadata, 0);
STRUCT_MEMBER_PRIMITIVE(Vector<int>, arguments_metadata, Vector<int>());
STRUCT_LAYOUT_OWNER(Object, MethodInfo, struct name, struct arguments, struct default_arguments, struct flags, struct id, struct return_val, struct return_val_metadata, struct arguments_metadata);
STRUCT_MEMBER(int, return_val_metadata, 0);
STRUCT_MEMBER(Vector<int>, arguments_metadata, Vector<int>());
STRUCT_LAYOUT(Object, MethodInfo, struct name, struct arguments, struct default_arguments, struct flags, struct id, struct return_val, struct return_val_metadata, struct arguments_metadata);

int get_argument_meta(int p_arg) const {
ERR_FAIL_COND_V(p_arg < -1 || p_arg > arguments.size(), 0);
Expand Down
8 changes: 4 additions & 4 deletions core/object/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,10 +344,10 @@ class Object {

struct Connection {
STRUCT_DECLARE(Connection);
STRUCT_MEMBER_PRIMITIVE(::Signal, signal, ::Signal());
STRUCT_MEMBER_PRIMITIVE(Callable, callable, Callable());
STRUCT_MEMBER_PRIMITIVE(uint32_t, flags, 0);
STRUCT_LAYOUT_OWNER(Object, Connection, struct signal, struct callable, struct flags);
STRUCT_MEMBER(::Signal, signal, ::Signal());
STRUCT_MEMBER(Callable, callable, Callable());
STRUCT_MEMBER(uint32_t, flags, 0);
STRUCT_LAYOUT(Object, Connection, struct signal, struct callable, struct flags);

bool operator<(const Connection &p_conn) const;

Expand Down
14 changes: 7 additions & 7 deletions core/object/property_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,13 @@ enum PropertyUsageFlags {

struct PropertyInfo {
STRUCT_DECLARE(PropertyInfo);
STRUCT_MEMBER_PRIMITIVE(String, name, String());
STRUCT_MEMBER_PRIMITIVE(StringName, class_name, StringName());
STRUCT_MEMBER_PRIMITIVE_FROM(Variant::Type, type, Variant::NIL);
STRUCT_MEMBER_PRIMITIVE_FROM(PropertyHint, hint, PROPERTY_HINT_NONE);
STRUCT_MEMBER_PRIMITIVE(String, hint_string, String());
STRUCT_MEMBER_PRIMITIVE(uint32_t, usage, PROPERTY_USAGE_DEFAULT);
STRUCT_LAYOUT_OWNER(Object, PropertyInfo, struct name, struct class_name, struct type, struct hint, struct hint_string, struct usage);
STRUCT_MEMBER(String, name, String());
STRUCT_MEMBER(StringName, class_name, StringName());
STRUCT_MEMBER_FROM(Variant::Type, type, Variant::NIL);
STRUCT_MEMBER_FROM(PropertyHint, hint, PROPERTY_HINT_NONE);
STRUCT_MEMBER(String, hint_string, String());
STRUCT_MEMBER(uint32_t, usage, PROPERTY_USAGE_DEFAULT);
STRUCT_LAYOUT(Object, PropertyInfo, struct name, struct class_name, struct type, struct hint, struct hint_string, struct usage);

_FORCE_INLINE_ PropertyInfo added_usage(uint32_t p_fl) const {
PropertyInfo pi = *this;
Expand Down
102 changes: 67 additions & 35 deletions core/variant/struct_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,16 @@ class TypedArray;
template <typename T>
class Struct;

/* The following set of macros let you seamlessly add reflection data to
* a C++ struct or class so that it can be exposed as a Godot Struct.
* The StructInfo struct below uses these macros and serves as a good
* example of how these macros should be used.*/

// Goes at the top of every exposed C++ struct.
#define STRUCT_DECLARE(m_struct_name) using StructType = m_struct_name

// Creates the typedef for a non-pointer struct member, along with some helper functions.
// "Alias" means that the exposed name can differ from the internal name.
#define STRUCT_MEMBER_TYPEDEF_ALIAS(m_type, m_member_name, m_member_name_alias, m_default) \
using Type = m_type; \
_FORCE_INLINE_ static const StringName get_name() { return SNAME(m_member_name_alias); } \
Expand All @@ -49,22 +57,31 @@ class Struct;
_FORCE_INLINE_ static Type get(const StructType &p_struct) { return p_struct.m_member_name; } \
_FORCE_INLINE_ static Type get_default_value() { return m_default; } \
_FORCE_INLINE_ static void set_variant(StructType &p_struct, const Variant &p_variant) { p_struct.m_member_name = from_variant(p_variant); } \
_FORCE_INLINE_ static void set(StructType &p_struct, const m_type &p_value) { p_struct.m_member_name = p_value; }
_FORCE_INLINE_ static void set(StructType &p_struct, const Type &p_value) { p_struct.m_member_name = p_value; }

// Shorter macro you can use when the exposed name is the same as the internal name.
#define STRUCT_MEMBER_TYPEDEF(m_type, m_member_name, m_default) \
STRUCT_MEMBER_TYPEDEF_ALIAS(m_type, m_member_name, #m_member_name, m_default)

#define STRUCT_MEMBER_TYPEDEF_POINTER(m_type, m_member_name, m_default) \
// Same as above, but for pointer members.
#define STRUCT_MEMBER_TYPEDEF_POINTER_ALIAS(m_type, m_member_name, m_member_name_alias, m_default) \
using Type = m_type *; \
_FORCE_INLINE_ static const StringName get_name() { return SNAME(#m_member_name); } \
_FORCE_INLINE_ static const StringName get_name() { return SNAME(m_member_name_alias); } \
_FORCE_INLINE_ static Variant get_variant(const StructType &p_struct) { return to_variant(p_struct.m_member_name); } \
_FORCE_INLINE_ static const Variant get_default_value_variant() { return to_variant(m_default); } \
_FORCE_INLINE_ static Type get(const StructType &p_struct) { return p_struct.m_member_name; } \
_FORCE_INLINE_ static const m_type *get_default_value() { return m_default; } \
_FORCE_INLINE_ static const Type get_default_value() { return m_default; } \
_FORCE_INLINE_ static void set_variant(StructType &p_struct, const Variant &p_variant) { p_struct.m_member_name = from_variant(p_variant); } \
_FORCE_INLINE_ static void set(StructType &p_struct, Type p_value) { p_struct.m_member_name = p_value; }

#define STRUCT_MEMBER_PRIMITIVE_ALIAS(m_type, m_member_name, m_member_name_alias, m_default) \
// Creates the typedef for a pointer struct member, along with some helper functions.
#define STRUCT_MEMBER_TYPEDEF_POINTER(m_type, m_member_name, m_default) \
STRUCT_MEMBER_TYPEDEF_POINTER_ALIAS(m_type, m_member_name, #m_member_name, m_default)

// Creates all the reflection data for a struct member and stores it as static properties of a struct with
// the same name as the member. This particular macro only works for primitive Variant types. For more
// complicated types, such as class values, class pointers, or structs, use the corresponding macro below.
#define STRUCT_MEMBER_ALIAS(m_type, m_member_name, m_member_name_alias, m_default) \
m_type m_member_name = m_default; \
struct m_member_name { \
_FORCE_INLINE_ static m_type from_variant(const Variant &p_variant) { return p_variant; } \
Expand All @@ -75,7 +92,12 @@ class Struct;
static const StructInfo *get_struct_member_info() { return nullptr; } \
}

#define STRUCT_MEMBER_PRIMITIVE_FROM(m_type, m_member_name, m_default) \
#define STRUCT_MEMBER(m_type, m_member_name, m_default) \
STRUCT_MEMBER_ALIAS(m_type, m_member_name, #m_member_name, m_default)

// Macros that include _FROM allow you to customize the way the struct is converted from a Variant. You must
// implement the from_variant(const Variant &p_variant) function in the corresponding .cpp file.
#define STRUCT_MEMBER_FROM(m_type, m_member_name, m_default) \
m_type m_member_name = m_default; \
struct m_member_name { \
static m_type from_variant(const Variant &p_variant); \
Expand All @@ -86,10 +108,9 @@ class Struct;
static const StructInfo *get_struct_member_info() { return nullptr; } \
}

#define STRUCT_MEMBER_PRIMITIVE(m_type, m_member_name, m_default) \
STRUCT_MEMBER_PRIMITIVE_ALIAS(m_type, m_member_name, #m_member_name, m_default)

#define STRUCT_MEMBER_PRIMITIVE_FROM_TO_ALIAS(m_type, m_member_name, m_member_name_alias, m_default) \
// Macros that include _TO allow you to customize the way the struct is converted to a Variant. You must
// implement the Variant to_variant function in the corresponding .cpp file.
#define STRUCT_MEMBER_FROM_TO_ALIAS(m_type, m_member_name, m_member_name_alias, m_default) \
m_type m_member_name = m_default; \
struct m_member_name { \
static m_type from_variant(const Variant &p_variant); \
Expand All @@ -100,8 +121,8 @@ class Struct;
static const StructInfo *get_struct_member_info() { return nullptr; } \
}

#define STRUCT_MEMBER_PRIMITIVE_FROM_TO(m_type, m_member_name, m_default) \
STRUCT_MEMBER_PRIMITIVE_FROM_TO_ALIAS(m_type, m_member_name, #m_member_name, m_default)
#define STRUCT_MEMBER_FROM_TO(m_type, m_member_name, m_default) \
STRUCT_MEMBER_FROM_TO_ALIAS(m_type, m_member_name, #m_member_name, m_default)

#define STRUCT_MEMBER_CLASS_POINTER(m_type, m_member_name, m_default) \
m_type *m_member_name = m_default; \
Expand Down Expand Up @@ -152,25 +173,30 @@ class Struct;
#define STRUCT_MEMBER_STRUCT_FROM_TO(m_type, m_member_name, m_default) \
STRUCT_MEMBER_STRUCT_FROM_TO_ALIAS(m_type, m_member_name, #m_member_name, m_default)

#define STRUCT_LAYOUT_WITH_NAME(m_struct_name, m_struct, ...) \
static const StringName get_struct_name() { \
return SNAME(m_struct_name); \
} \
static const StructInfo &get_struct_info() { \
return Layout::get_struct_info(); \
} \
using Layout = StructLayout<m_struct, __VA_ARGS__>; \
m_struct(const Dictionary &p_dict) { \
Layout::fill_struct(p_dict, *this); \
} \
m_struct(const Array &p_array) { \
Layout::fill_struct(p_array, *this); \
// Use after all the struct members have been declared to specialize the StructLayout Template
// and define some helper functions.
#define STRUCT_LAYOUT_ALIAS(m_struct_name, m_struct, ...) \
static const StringName get_struct_name() { \
return SNAME(m_struct_name); \
} \
static const StructInfo &get_struct_info() { \
return Layout::get_struct_info(); \
} \
using Layout = StructLayout<m_struct, __VA_ARGS__>; \
m_struct(const Dictionary &p_dict) { \
Layout::fill_struct(p_dict, *this); \
} \
m_struct(const Array &p_array) { \
Layout::fill_struct(p_array, *this); \
}

#define STRUCT_LAYOUT_OWNER(m_owner, m_struct, ...) STRUCT_LAYOUT_WITH_NAME(#m_owner "." #m_struct, m_struct, __VA_ARGS__)

#define STRUCT_LAYOUT(m_struct, ...) STRUCT_LAYOUT_WITH_NAME(#m_struct, m_struct, __VA_ARGS__)
// Most of the time, the exposed name of a struct follows the pattern "OwningClass.StructName".
#define STRUCT_LAYOUT(m_owner, m_struct, ...) STRUCT_LAYOUT_ALIAS(#m_owner "." #m_struct, m_struct, __VA_ARGS__)

/* The StructLayout template manages all the reflection data for a native struct. It automatically generates
* functions for converting the C++ struct to and from a Godot Struct, Array, or Dictionary.
* The StructType argument is expected to be a struct declared with STRUCT_DECLARE and the StructMember
* arguments are expected to be the reflection structs created by any of the various STRUCT_MEMBER macros. */
template <typename StructType, typename... StructMembers>
struct StructLayout {
static constexpr int32_t struct_member_count = sizeof...(StructMembers);
Expand Down Expand Up @@ -225,6 +251,9 @@ struct StructLayout {
return sizeof...(StructMembers) - TypeFinder<T, StructMembers...>::remaining_count - 1;
}

// Provides random access member lookup for native Godot Structs.
// It uses recursive types to force the compiler to perform a linear member search
// so that member access is O(1) at runtime.
private:
template <typename TypeToFind, typename... TypesToSearch>
struct TypeFinder;
Expand All @@ -245,15 +274,18 @@ struct StructLayout {
};
};

/* Represents the type data of both native and user Godot Structs.
* StructInfo is itself exposed as a Godot Struct, so it serves as
* a good example for how to expose other structs. */
struct StructInfo {
STRUCT_DECLARE(StructInfo);
STRUCT_MEMBER_PRIMITIVE(StringName, name, StringName());
STRUCT_MEMBER_PRIMITIVE(int32_t, count, 0);
STRUCT_MEMBER_PRIMITIVE(Vector<StringName>, names, Vector<StringName>());
STRUCT_MEMBER_PRIMITIVE_FROM_TO(Vector<Variant::Type>, types, Vector<Variant::Type>());
STRUCT_MEMBER_PRIMITIVE(Vector<StringName>, class_names, Vector<StringName>());
STRUCT_MEMBER_PRIMITIVE(Vector<Variant>, default_values, Vector<Variant>());
STRUCT_LAYOUT(StructInfo, struct name, struct count, struct names, struct types, struct class_names, struct default_values);
STRUCT_MEMBER(StringName, name, StringName());
STRUCT_MEMBER(int32_t, count, 0);
STRUCT_MEMBER(Vector<StringName>, names, Vector<StringName>());
STRUCT_MEMBER_FROM_TO(Vector<Variant::Type>, types, Vector<Variant::Type>());
STRUCT_MEMBER(Vector<StringName>, class_names, Vector<StringName>());
STRUCT_MEMBER(Vector<Variant>, default_values, Vector<Variant>());
STRUCT_LAYOUT_ALIAS("StructInfo", StructInfo, struct name, struct count, struct names, struct types, struct class_names, struct default_values);

Vector<const StructInfo *> struct_member_infos;

Expand Down
20 changes: 10 additions & 10 deletions tests/core/variant/test_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,9 @@ TEST_CASE("[Struct] StructInfo") {
TEST_CASE("[Struct] Validation") {
struct NamedInt {
STRUCT_DECLARE(NamedInt);
STRUCT_MEMBER_PRIMITIVE(String, name, String());
STRUCT_MEMBER_PRIMITIVE(int, value, 0);
STRUCT_LAYOUT(NamedInt, struct name, struct value);
STRUCT_MEMBER(String, name, String());
STRUCT_MEMBER(int, value, 0);
STRUCT_LAYOUT(TestStruct, NamedInt, struct name, struct value);
};

Struct<NamedInt> named_int;
Expand Down Expand Up @@ -329,22 +329,22 @@ TEST_CASE("[Struct] Validation") {
TEST_CASE("[Struct] Nesting") {
struct BasicStruct {
STRUCT_DECLARE(BasicStruct);
STRUCT_MEMBER_PRIMITIVE(int, int_val, 4);
STRUCT_MEMBER_PRIMITIVE(float, float_val, 5.5f);
STRUCT_LAYOUT(BasicStruct, struct int_val, struct float_val);
STRUCT_MEMBER(int, int_val, 4);
STRUCT_MEMBER(float, float_val, 5.5f);
STRUCT_LAYOUT(TestStruct, BasicStruct, struct int_val, struct float_val);
BasicStruct() {};
};
struct BasicStructLookalike {
STRUCT_DECLARE(BasicStructLookalike);
STRUCT_MEMBER_PRIMITIVE(int, int_val, 4);
STRUCT_MEMBER_PRIMITIVE(float, float_val, 5.5f);
STRUCT_LAYOUT(BasicStructLookalike, struct int_val, struct float_val);
STRUCT_MEMBER(int, int_val, 4);
STRUCT_MEMBER(float, float_val, 5.5f);
STRUCT_LAYOUT(TestStruct, BasicStructLookalike, struct int_val, struct float_val);
};
struct NestedStruct {
STRUCT_DECLARE(NestedStruct);
STRUCT_MEMBER_CLASS_POINTER(Node, node, nullptr);
STRUCT_MEMBER_STRUCT(BasicStruct, value, BasicStruct());
STRUCT_LAYOUT(NestedStruct, struct node, struct value);
STRUCT_LAYOUT(TestStruct, NestedStruct, struct node, struct value);
};

REQUIRE_EQ(NestedStruct::Layout::struct_member_count, 2);
Expand Down

0 comments on commit ab4d72f

Please sign in to comment.