Skip to content

Commit

Permalink
[Method Bind] Add support for default argument values and static meth…
Browse files Browse the repository at this point in the history
…od binding. Sync headers.
  • Loading branch information
bruvzg committed May 6, 2022
1 parent 24e4aeb commit 031a83b
Show file tree
Hide file tree
Showing 11 changed files with 794 additions and 115 deletions.
463 changes: 403 additions & 60 deletions godot-headers/extension_api.json

Large diffs are not rendered by default.

112 changes: 112 additions & 0 deletions include/godot_cpp/core/binder_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,118 @@ GDNativeExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_ar
return md;
}

template <class... P, size_t... Is>
void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDNativeCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDNATIVE_CALL_OK;

#ifdef DEBUG_METHODS_ENABLED
(p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
#else
(p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
}

template <class... P>
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDNativeVariantPtr *p_args, int p_argcount, GDNativeCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = sizeof...(P);
return;
}
#endif

int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;

int32_t dvs = default_values.size();
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = sizeof...(P);
return;
}
#endif

Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
std::array<const Variant *, sizeof...(P)> argsp;
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
if (i < p_argcount) {
args[i] = Variant(p_args[i]);
} else {
args[i] = default_values[i - p_argcount + (dvs - missing)];
}
argsp[i] = &args[i];
}

call_with_variant_args_static(p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}

template <class... P, size_t... Is>
void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDNativeTypePtr *p_args, IndexSequence<Is...>) {
p_method(PtrToArg<P>::convert(p_args[Is])...);
}

template <class... P>
void call_with_ptr_args_static_method(void (*p_method)(P...), const GDNativeTypePtr *p_args) {
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}

template <class R, class... P, size_t... Is>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDNativeCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDNATIVE_CALL_OK;

#ifdef DEBUG_METHODS_ENABLED
r_ret = (p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
#else
r_ret = (p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
}

template <class R, class... P>
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDNativeVariantPtr *p_args, int p_argcount, Variant &r_ret, GDNativeCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = sizeof...(P);
return;
}
#endif

int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;

int32_t dvs = default_values.size();
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = sizeof...(P);
return;
}
#endif

Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
std::array<const Variant *, sizeof...(P)> argsp;
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
if (i < p_argcount) {
args[i] = Variant(p_args[i]);
} else {
args[i] = default_values[i - p_argcount + (dvs - missing)];
}
argsp[i] = &args[i];
}

call_with_variant_args_static_ret(p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}

template <class R, class... P, size_t... Is>
void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const GDNativeTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}

template <class R, class... P>
void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDNativeTypePtr *p_args, void *r_ret) {
call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}

#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
Expand Down
33 changes: 28 additions & 5 deletions include/godot_cpp/core/class_db.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@

namespace godot {

#define DEFVAL(m_defval) (m_defval)

struct MethodDefinition {
const char *name = nullptr;
std::list<std::string> args;
Expand Down Expand Up @@ -101,10 +103,15 @@ class ClassDB {
template <class T>
static void register_class();

template <class N, class M>
static MethodBind *bind_method(N p_method_name, M p_method);
template <class N, class M, typename... VarArgs>
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);

template <class N, class M, typename... VarArgs>
static MethodBind *bind_static_method(const char *p_class, N p_method_name, M p_method, VarArgs... p_args);

template <class M>
static MethodBind *bind_vararg_method(uint32_t p_flags, const char *p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);

static void add_property_group(const char *p_class, const char *p_name, const char *p_prefix);
static void add_property_subgroup(const char *p_class, const char *p_name, const char *p_prefix);
static void add_property(const char *p_class, const PropertyInfo &p_pinfo, const char *p_setter, const char *p_getter, int p_index = -1);
Expand Down Expand Up @@ -172,11 +179,27 @@ void ClassDB::register_class() {
initialize_class(classes[cl.name]);
}

template <class N, class M>
MethodBind *ClassDB::bind_method(N p_method_name, M p_method) {
template <class N, class M, typename... VarArgs>
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
argptrs[i] = &args[i];
}
MethodBind *bind = create_method_bind(p_method);
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
}

return bind_methodfi(0, bind, p_method_name, nullptr, 0);
template <class N, class M, typename... VarArgs>
MethodBind *ClassDB::bind_static_method(const char *p_class, N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
argptrs[i] = &args[i];
}
MethodBind *bind = create_static_method_bind(p_method);
bind->set_instance_class(p_class);
return bind_methodfi(0, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
}

template <class M>
Expand Down
146 changes: 141 additions & 5 deletions include/godot_cpp/core/method_bind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ class MethodBind {
int argument_count = 0;
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;

bool _static = false;
bool _is_const = false;
bool _has_return = false;
bool _vararg = false;

std::vector<std::string> argument_names;
GDNativeVariantType *argument_types = nullptr;
Expand All @@ -66,6 +68,8 @@ class MethodBind {
void generate_argument_types(int p_count);
void set_const(bool p_const);
void set_return(bool p_return);
void set_static(bool p_static);
void set_vararg(bool p_vararg);
void set_argument_count(int p_count);

public:
Expand Down Expand Up @@ -96,8 +100,10 @@ class MethodBind {

_FORCE_INLINE_ int get_argument_count() const { return argument_count; };
_FORCE_INLINE_ bool is_const() const { return _is_const; }
_FORCE_INLINE_ bool is_static() const { return _static; }
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
_FORCE_INLINE_ bool has_return() const { return _has_return; }
_FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags; }
_FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? GDNATIVE_EXTENSION_METHOD_FLAG_CONST : 0) | (is_vararg() ? GDNATIVE_EXTENSION_METHOD_FLAG_VARARG : 0) | (is_static() ? GDNATIVE_EXTENSION_METHOD_FLAG_STATIC : 0); }
_FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; }
void set_argument_names(const std::vector<std::string> &p_names);
std::vector<std::string> get_argument_names() const;
Expand Down Expand Up @@ -155,15 +161,13 @@ class MethodBindVarArgBase : public MethodBind {
ERR_FAIL(); // Can't call.
}

virtual bool is_const() const { return false; }

virtual bool is_vararg() const { return true; }

MethodBindVarArgBase(
R (T::*p_method)(const Variant **, GDNativeInt, GDNativeCallError &),
const MethodInfo &p_method_info,
bool p_return_nil_is_variant) :
method(p_method), method_info(p_method_info) {
set_vararg(true);
set_const(true);
set_argument_count(method_info.arguments.size());
if (method_info.arguments.size()) {
std::vector<std::string> names;
Expand Down Expand Up @@ -572,6 +576,138 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
return a;
}

// STATIC BINDS

// no return

template <class... P>
class MethodBindTS : public MethodBind {
void (*function)(P...);

protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
virtual GDNativeVariantType gen_argument_type(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
return GDNATIVE_VARIANT_TYPE_NIL;
}
}

virtual GDNativePropertyInfo gen_argument_type_info(int p_arg) const {
GDNativePropertyInfo pi;
call_get_argument_type_info<P...>(p_arg, pi);
return pi;
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif

public:
virtual GDNativeExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const {
return call_get_argument_metadata<P...>(p_arg);
}

virtual Variant call(GDExtensionClassInstancePtr p_object, const GDNativeVariantPtr *p_args, const GDNativeInt p_arg_count, GDNativeCallError &r_error) const {
(void)p_object; // unused
call_with_variant_args_static_dv(function, p_args, p_arg_count, r_error, get_default_arguments());
return Variant();
}

virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret) const {
(void)p_object;
(void)r_ret;
call_with_ptr_args_static_method(function, p_args);
}

MethodBindTS(void (*p_function)(P...)) {
function = p_function;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_static(true);
}
};

template <class... P>
MethodBind *create_static_method_bind(void (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
return a;
}

// return

template <class R, class... P>
class MethodBindTRS : public MethodBind {
R(*function)
(P...);

protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
virtual GDNativeVariantType gen_argument_type(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
return GetTypeInfo<R>::VARIANT_TYPE;
}
}

virtual GDNativePropertyInfo gen_argument_type_info(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
GDNativePropertyInfo pi;
call_get_argument_type_info<P...>(p_arg, pi);
return pi;
} else {
return GetTypeInfo<R>::get_class_info();
}
}

#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif

public:
virtual GDNativeExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const {
if (p_arg >= 0) {
return call_get_argument_metadata<P...>(p_arg);
} else {
return GetTypeInfo<R>::METADATA;
}
}

virtual Variant call(GDExtensionClassInstancePtr p_object, const GDNativeVariantPtr *p_args, const GDNativeInt p_arg_count, GDNativeCallError &r_error) const {
Variant ret;
call_with_variant_args_static_ret_dv(function, p_args, p_arg_count, ret, r_error, get_default_arguments());
return ret;
}

virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret) const {
(void)p_object;
call_with_ptr_args_static_method_ret(function, p_args, r_ret);
}

MethodBindTRS(R (*p_function)(P...)) {
function = p_function;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_static(true);
set_return(true);
}
};

template <class R, class... P>
MethodBind *create_static_method_bind(R (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
return a;
}

} // namespace godot

#endif // ! GODOT_CPP_METHOD_BIND_HPP
6 changes: 3 additions & 3 deletions include/godot_cpp/core/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,20 +117,20 @@ struct MethodInfo {

template <class... Args>
MethodInfo::MethodInfo(const char *p_name, const Args &...args) :
name(p_name), flags(METHOD_FLAG_NORMAL) {
name(p_name), flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}

template <class... Args>
MethodInfo::MethodInfo(Variant::Type ret, const char *p_name, const Args &...args) :
name(p_name), flags(METHOD_FLAG_NORMAL) {
name(p_name), flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) {
return_val.type = ret;
arguments = { args... };
}

template <class... Args>
MethodInfo::MethodInfo(const PropertyInfo &p_ret, const char *p_name, const Args &...args) :
name(p_name), return_val(p_ret), flags(METHOD_FLAG_NORMAL) {
name(p_name), return_val(p_ret), flags(GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}

Expand Down
Loading

0 comments on commit 031a83b

Please sign in to comment.