Add static method support to ClassDB
* Based on the work done for Variant in the past. * Added `ClassDB::bind_static_method` * Cleaned up ClassDB::bind_method to use variadic templates. This adds support for having static methods in Object derived classes. Note that this does not make it work yet in GDScript or Mono and, while it works for GDExtension, GodotCPP needs to be updated.
This commit is contained in:
parent
81c2d7a82a
commit
2f651277da
|
@ -1334,7 +1334,7 @@ void File::store_buffer(const Vector<uint8_t> &p_buffer) {
|
|||
f->store_buffer(&r[0], len);
|
||||
}
|
||||
|
||||
bool File::file_exists(const String &p_name) const {
|
||||
bool File::file_exists(const String &p_name) {
|
||||
return FileAccess::exists(p_name);
|
||||
}
|
||||
|
||||
|
@ -1424,7 +1424,7 @@ void File::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &File::store_pascal_string);
|
||||
ClassDB::bind_method(D_METHOD("get_pascal_string"), &File::get_pascal_string);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("file_exists", "path"), &File::file_exists);
|
||||
ClassDB::bind_static_method("File", D_METHOD("file_exists", "path"), &File::file_exists);
|
||||
ClassDB::bind_method(D_METHOD("get_modified_time", "file"), &File::get_modified_time);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
|
||||
|
|
|
@ -436,7 +436,7 @@ public:
|
|||
|
||||
void store_var(const Variant &p_var, bool p_full_objects = false);
|
||||
|
||||
bool file_exists(const String &p_name) const; // Return true if a file exists.
|
||||
static bool file_exists(const String &p_name); // Return true if a file exists.
|
||||
|
||||
uint64_t get_modified_time(const String &p_file) const;
|
||||
|
||||
|
|
|
@ -666,6 +666,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
|
|||
Dictionary d2;
|
||||
d2["name"] = String(method_name);
|
||||
d2["is_const"] = (F.flags & METHOD_FLAG_CONST) ? true : false;
|
||||
d2["is_static"] = (F.flags & METHOD_FLAG_STATIC) ? true : false;
|
||||
d2["is_vararg"] = false;
|
||||
d2["is_virtual"] = true;
|
||||
// virtual functions have no hash since no MethodBind is involved
|
||||
|
@ -708,6 +709,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
|
|||
|
||||
d2["is_const"] = method->is_const();
|
||||
d2["is_vararg"] = method->is_vararg();
|
||||
d2["is_static"] = method->is_static();
|
||||
d2["is_virtual"] = false;
|
||||
d2["hash"] = method->get_hash();
|
||||
|
||||
|
|
|
@ -227,75 +227,27 @@ public:
|
|||
|
||||
static uint64_t get_api_hash(APIType p_api);
|
||||
|
||||
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) {
|
||||
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, nullptr, 0); //use static function, much smaller binary usage
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
|
||||
}
|
||||
|
||||
template <class N, class M>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1) {
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
const Variant *ptr[1] = { &p_def1 };
|
||||
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 1);
|
||||
}
|
||||
|
||||
template <class N, class M>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2) {
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
const Variant *ptr[2] = { &p_def1, &p_def2 };
|
||||
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 2);
|
||||
}
|
||||
|
||||
template <class N, class M>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3) {
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
const Variant *ptr[3] = { &p_def1, &p_def2, &p_def3 };
|
||||
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 3);
|
||||
}
|
||||
|
||||
template <class N, class M>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4) {
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
const Variant *ptr[4] = { &p_def1, &p_def2, &p_def3, &p_def4 };
|
||||
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 4);
|
||||
}
|
||||
|
||||
template <class N, class M>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5) {
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
const Variant *ptr[5] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5 };
|
||||
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 5);
|
||||
}
|
||||
|
||||
template <class N, class M>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5, const Variant &p_def6) {
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
const Variant *ptr[6] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5, &p_def6 };
|
||||
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 6);
|
||||
}
|
||||
|
||||
template <class N, class M>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5, const Variant &p_def6, const Variant &p_def7) {
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
const Variant *ptr[7] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5, &p_def6, &p_def7 };
|
||||
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 7);
|
||||
}
|
||||
|
||||
template <class N, class M>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, const Variant &p_def1, const Variant &p_def2, const Variant &p_def3, const Variant &p_def4, const Variant &p_def5, const Variant &p_def6, const Variant &p_def7, const Variant &p_def8) {
|
||||
MethodBind *bind = create_method_bind(p_method);
|
||||
const Variant *ptr[8] = { &p_def1, &p_def2, &p_def3, &p_def4, &p_def5, &p_def6, &p_def7, &p_def8 };
|
||||
|
||||
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, ptr, 8);
|
||||
template <class N, class M, typename... VarArgs>
|
||||
static MethodBind *bind_static_method(const StringName &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(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
|
||||
}
|
||||
|
||||
template <class M>
|
||||
|
|
|
@ -83,6 +83,10 @@ void MethodBind::_set_const(bool p_const) {
|
|||
_const = p_const;
|
||||
}
|
||||
|
||||
void MethodBind::_set_static(bool p_static) {
|
||||
_static = p_static;
|
||||
}
|
||||
|
||||
void MethodBind::_set_returns(bool p_returns) {
|
||||
_returns = p_returns;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ class MethodBind {
|
|||
int default_argument_count = 0;
|
||||
int argument_count = 0;
|
||||
|
||||
bool _static = false;
|
||||
bool _const = false;
|
||||
bool _returns = false;
|
||||
|
||||
|
@ -69,6 +70,7 @@ protected:
|
|||
Vector<StringName> arg_names;
|
||||
#endif
|
||||
void _set_const(bool p_const);
|
||||
void _set_static(bool p_static);
|
||||
void _set_returns(bool p_returns);
|
||||
virtual Variant::Type _gen_argument_type(int p_arg) const = 0;
|
||||
virtual PropertyInfo _gen_argument_type_info(int p_arg) const = 0;
|
||||
|
@ -116,7 +118,7 @@ public:
|
|||
#endif
|
||||
|
||||
void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
|
||||
uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
|
||||
uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0) | (is_static() ? METHOD_FLAG_STATIC : 0); }
|
||||
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
|
||||
_FORCE_INLINE_ void set_instance_class(const StringName &p_class) { instance_class = p_class; }
|
||||
|
||||
|
@ -129,6 +131,7 @@ public:
|
|||
void set_name(const StringName &p_name);
|
||||
_FORCE_INLINE_ int get_method_id() const { return method_id; }
|
||||
_FORCE_INLINE_ bool is_const() const { return _const; }
|
||||
_FORCE_INLINE_ bool is_static() const { return _static; }
|
||||
_FORCE_INLINE_ bool has_return() const { return _returns; }
|
||||
virtual bool is_vararg() const { return false; }
|
||||
|
||||
|
@ -308,7 +311,7 @@ MethodBind *create_method_bind(void (T::*p_method)(P...)) {
|
|||
return a;
|
||||
}
|
||||
|
||||
// no return, not const
|
||||
// no return, const
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <class T, class... P>
|
||||
|
@ -558,4 +561,139 @@ 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 Variant::Type _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 Variant::NIL;
|
||||
}
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
|
||||
PropertyInfo pi;
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
return pi;
|
||||
}
|
||||
|
||||
public:
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
|
||||
return call_get_argument_metadata<P...>(p_arg);
|
||||
}
|
||||
|
||||
#endif
|
||||
virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
|
||||
(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(Object *p_object, const void **p_args, void *r_ret) {
|
||||
(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 Variant::Type _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;
|
||||
}
|
||||
}
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
|
||||
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
|
||||
PropertyInfo pi;
|
||||
call_get_argument_type_info<P...>(p_arg, pi);
|
||||
return pi;
|
||||
} else {
|
||||
return GetTypeInfo<R>::get_class_info();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
|
||||
if (p_arg >= 0) {
|
||||
return call_get_argument_metadata<P...>(p_arg);
|
||||
} else {
|
||||
return GetTypeInfo<R>::METADATA;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
|
||||
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(Object *p_object, const void **p_args, void *r_ret) {
|
||||
(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_returns(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;
|
||||
}
|
||||
|
||||
#endif // METHOD_BIND_H
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
[/codeblocks]
|
||||
</description>
|
||||
</method>
|
||||
<method name="file_exists" qualifiers="const">
|
||||
<method name="file_exists" qualifiers="static">
|
||||
<return type="bool" />
|
||||
<argument index="0" name="path" type="String" />
|
||||
<description>
|
||||
|
|
Loading…
Reference in New Issue