diff options
Diffstat (limited to 'core/method_bind.h')
-rw-r--r-- | core/method_bind.h | 532 |
1 files changed, 365 insertions, 167 deletions
diff --git a/core/method_bind.h b/core/method_bind.h index 942e2e0036..d43186257b 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -31,18 +31,7 @@ #ifndef METHOD_BIND_H #define METHOD_BIND_H -#ifdef DEBUG_ENABLED -#define DEBUG_METHODS_ENABLED -#endif - -#include "core/list.h" -#include "core/method_ptrcall.h" -#include "core/object.h" -#include "core/type_info.h" -#include "core/typedefs.h" -#include "core/variant.h" - -#include <stdio.h> +#include "core/binder_common.h" enum MethodFlags { @@ -57,151 +46,15 @@ enum MethodFlags { METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL, }; -template <class T> -struct VariantCaster { - static _FORCE_INLINE_ T cast(const Variant &p_variant) { - return p_variant; - } -}; - -template <class T> -struct VariantCaster<T &> { - static _FORCE_INLINE_ T cast(const Variant &p_variant) { - return p_variant; - } -}; - -template <class T> -struct VariantCaster<const T &> { - static _FORCE_INLINE_ T cast(const Variant &p_variant) { - return p_variant; - } -}; - -#define _VC(m_idx) \ - (VariantCaster<P##m_idx>::cast((m_idx - 1) >= p_arg_count ? get_default_argument(m_idx - 1) : *p_args[m_idx - 1])) - -#ifdef PTRCALL_ENABLED - -#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 int(); \ - } \ - }; \ - template <> \ - struct PtrToArg<m_enum> { \ - _FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \ - return m_enum(*reinterpret_cast<const int *>(p_ptr)); \ - } \ - _FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \ - *(int *)p_ptr = p_val; \ - } \ - }; - -#else - -#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 int(); \ - } \ - }; - -#endif - -// Object enum casts must go here -VARIANT_ENUM_CAST(Object::ConnectFlags); - -template <typename T> -struct VariantObjectClassChecker { - static _FORCE_INLINE_ bool check(const Variant &p_variant) { - return true; - } -}; - -template <> -struct VariantObjectClassChecker<Node *> { - static _FORCE_INLINE_ bool check(const Variant &p_variant) { - Object *obj = p_variant; - Node *node = p_variant; - return node || !obj; - } -}; - -template <> -struct VariantObjectClassChecker<Control *> { - static _FORCE_INLINE_ bool check(const Variant &p_variant) { - Object *obj = p_variant; - Control *control = p_variant; - return control || !obj; - } -}; - -#define CHECK_ARG(m_arg) \ - if ((m_arg - 1) < p_arg_count) { \ - Variant::Type argtype = get_argument_type(m_arg - 1); \ - if (!Variant::can_convert_strict(p_args[m_arg - 1]->get_type(), argtype) || \ - !VariantObjectClassChecker<P##m_arg>::check(*p_args[m_arg - 1])) { \ - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \ - r_error.argument = m_arg - 1; \ - r_error.expected = argtype; \ - return Variant(); \ - } \ - } - -#define CHECK_NOARG(m_arg) \ - { \ - if (p_arg##m_arg.get_type() != Variant::NIL) { \ - if (r_argerror) { \ - *r_argerror = (m_arg - 1); \ - } \ - return CALL_ERROR_EXTRA_ARGUMENT; \ - } \ - } +VARIANT_ENUM_CAST(MethodFlags) // some helpers -VARIANT_ENUM_CAST(Vector3::Axis); - -VARIANT_ENUM_CAST(Error); -VARIANT_ENUM_CAST(Margin); -VARIANT_ENUM_CAST(Corner); -VARIANT_ENUM_CAST(Orientation); -VARIANT_ENUM_CAST(HAlign); -VARIANT_ENUM_CAST(VAlign); -VARIANT_ENUM_CAST(PropertyHint); -VARIANT_ENUM_CAST(PropertyUsageFlags); -VARIANT_ENUM_CAST(MethodFlags); -VARIANT_ENUM_CAST(Variant::Type); -VARIANT_ENUM_CAST(Variant::Operator); - -template <> -struct VariantCaster<char32_t> { - static _FORCE_INLINE_ char32_t cast(const Variant &p_variant) { - return (char32_t)p_variant.operator int(); - } -}; -#ifdef PTRCALL_ENABLED -template <> -struct PtrToArg<char32_t> { - _FORCE_INLINE_ static char32_t convert(const void *p_ptr) { - return char32_t(*reinterpret_cast<const int *>(p_ptr)); - } - _FORCE_INLINE_ static void encode(char32_t p_val, const void *p_ptr) { - *(int *)p_ptr = p_val; - } -}; -#endif - class MethodBind { int method_id; uint32_t hint_flags = METHOD_FLAGS_DEFAULT; StringName name; + StringName instance_class; Vector<Variant> default_arguments; int default_argument_count = 0; int argument_count = 0; @@ -225,11 +78,11 @@ protected: void set_argument_count(int p_count) { argument_count = p_count; } public: - Vector<Variant> get_default_arguments() const { return default_arguments; } + _FORCE_INLINE_ const Vector<Variant> &get_default_arguments() const { return default_arguments; } _FORCE_INLINE_ int get_default_argument_count() const { return default_argument_count; } _FORCE_INLINE_ Variant has_default_argument(int p_arg) const { - int idx = argument_count - p_arg - 1; + int idx = p_arg - (argument_count - default_arguments.size()); if (idx < 0 || idx >= default_arguments.size()) { return false; @@ -239,7 +92,7 @@ public: } _FORCE_INLINE_ Variant get_default_argument(int p_arg) const { - int idx = argument_count - p_arg - 1; + int idx = p_arg - (argument_count - default_arguments.size()); if (idx < 0 || idx >= default_arguments.size()) { return Variant(); @@ -249,7 +102,6 @@ public: } #ifdef DEBUG_METHODS_ENABLED - _FORCE_INLINE_ Variant::Type get_argument_type(int p_argument) const { ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, Variant::NIL); return argument_types[p_argument + 1]; @@ -258,15 +110,16 @@ public: PropertyInfo get_argument_info(int p_argument) const; PropertyInfo get_return_info() const; - void set_argument_names(const Vector<StringName> &p_names); //set by class, db, can't be inferred otherwise + void set_argument_names(const Vector<StringName> &p_names); // Set by ClassDB, can't be inferred otherwise. Vector<StringName> get_argument_names() const; virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const = 0; - #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); } - virtual String get_instance_class() const = 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; } _FORCE_INLINE_ int get_argument_count() const { return argument_count; }; @@ -302,7 +155,6 @@ protected: public: #ifdef DEBUG_METHODS_ENABLED - virtual PropertyInfo _gen_argument_type_info(int p_arg) const { if (p_arg < 0) { return arguments.return_val; @@ -320,14 +172,12 @@ public: virtual GodotTypeInfo::Metadata get_argument_meta(int) const { return GodotTypeInfo::METADATA_NONE; } - #else - virtual Variant::Type _gen_argument_type(int p_arg) const { return Variant::NIL; } - #endif + virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { T *instance = static_cast<T *>(p_object); return (instance->*call_method)(p_args, p_arg_count, r_error); @@ -364,7 +214,6 @@ public: void set_method(NativeCall p_method) { call_method = p_method; } virtual bool is_const() const { return false; } - virtual String get_instance_class() const { return T::get_class_static(); } virtual bool is_vararg() const { return true; } @@ -378,16 +227,365 @@ MethodBind *create_vararg_method_bind(Variant (T::*p_method)(const Variant **, i MethodBindVarArg<T> *a = memnew((MethodBindVarArg<T>)); a->set_method(p_method); a->set_method_info(p_info, p_return_nil_is_variant); + a->set_instance_class(T::get_class_static()); return a; } -/** This amazing hack is based on the FastDelegates theory */ - -// tale of an amazing hack.. // +/**** VARIADIC TEMPLATES ****/ -// if you declare a nonexistent class.. +#ifndef TYPED_METHOD_BIND class __UnexistingClass; +#define MB_T __UnexistingClass +#else +#define MB_T T +#endif -#include "method_bind.gen.inc" +// no return, not const +#ifdef TYPED_METHOD_BIND +template <class T, class... P> +#else +template <class... P> +#endif +class MethodBindT : public MethodBind { + void (MB_T::*method)(P...); + +protected: +#ifdef DEBUG_METHODS_ENABLED +// 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; + } +#endif + +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) { +#ifdef TYPED_METHOD_BIND + call_with_variant_args_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments()); +#else + call_with_variant_args_dv((MB_T *)(p_object), method, p_args, p_arg_count, r_error, get_default_arguments()); +#endif + return Variant(); + } + +#ifdef PTRCALL_ENABLED + virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) { +#ifdef TYPED_METHOD_BIND + call_with_ptr_args<T, P...>(static_cast<T *>(p_object), method, p_args); +#else + call_with_ptr_args<MB_T, P...>((MB_T *)(p_object), method, p_args); +#endif + } +#endif + + MethodBindT(void (MB_T::*p_method)(P...)) { + method = p_method; +#ifdef DEBUG_METHODS_ENABLED + _generate_argument_types(sizeof...(P)); +#endif + set_argument_count(sizeof...(P)); + } +}; + +template <class T, class... P> +MethodBind *create_method_bind(void (T::*p_method)(P...)) { +#ifdef TYPED_METHOD_BIND + MethodBind *a = memnew((MethodBindT<T, P...>)(p_method)); +#else + MethodBind *a = memnew((MethodBindT<P...>)(reinterpret_cast<void (MB_T::*)(P...)>(p_method))); +#endif + a->set_instance_class(T::get_class_static()); + return a; +} + +// no return, not const + +#ifdef TYPED_METHOD_BIND +template <class T, class... P> +#else +template <class... P> +#endif +class MethodBindTC : public MethodBind { + void (MB_T::*method)(P...) const; + +protected: +#ifdef DEBUG_METHODS_ENABLED +// 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; + } +#endif + +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) { +#ifdef TYPED_METHOD_BIND + call_with_variant_argsc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments()); +#else + call_with_variant_argsc_dv((MB_T *)(p_object), method, p_args, p_arg_count, r_error, get_default_arguments()); +#endif + return Variant(); + } + +#ifdef PTRCALL_ENABLED + virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) { +#ifdef TYPED_METHOD_BIND + call_with_ptr_argsc<T, P...>(static_cast<T *>(p_object), method, p_args); +#else + call_with_ptr_argsc<MB_T, P...>((MB_T *)(p_object), method, p_args); +#endif + } +#endif + + MethodBindTC(void (MB_T::*p_method)(P...) const) { + method = p_method; + _set_const(true); +#ifdef DEBUG_METHODS_ENABLED + _generate_argument_types(sizeof...(P)); +#endif + set_argument_count(sizeof...(P)); + } +}; + +template <class T, class... P> +MethodBind *create_method_bind(void (T::*p_method)(P...) const) { +#ifdef TYPED_METHOD_BIND + MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method)); +#else + MethodBind *a = memnew((MethodBindTC<P...>)(reinterpret_cast<void (MB_T::*)(P...) const>(p_method))); +#endif + a->set_instance_class(T::get_class_static()); + return a; +} + +// return, not const + +#ifdef TYPED_METHOD_BIND +template <class T, class R, class... P> +#else +template <class R, class... P> +#endif +class MethodBindTR : public MethodBind { + R(MB_T::*method) + (P...); + +protected: +#ifdef DEBUG_METHODS_ENABLED +// 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; + } + } + + 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(); + } + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif +#endif + +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; +#ifdef TYPED_METHOD_BIND + call_with_variant_args_ret_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments()); +#else + call_with_variant_args_ret_dv((MB_T *)p_object, method, p_args, p_arg_count, ret, r_error, get_default_arguments()); +#endif + return ret; + } + +#ifdef PTRCALL_ENABLED + virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) { +#ifdef TYPED_METHOD_BIND + call_with_ptr_args_ret<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret); +#else + call_with_ptr_args_ret<MB_T, R, P...>((MB_T *)(p_object), method, p_args, r_ret); +#endif + } +#endif + + MethodBindTR(R (MB_T::*p_method)(P...)) { + method = p_method; + _set_returns(true); +#ifdef DEBUG_METHODS_ENABLED + _generate_argument_types(sizeof...(P)); +#endif + set_argument_count(sizeof...(P)); + } +}; + +template <class T, class R, class... P> +MethodBind *create_method_bind(R (T::*p_method)(P...)) { +#ifdef TYPED_METHOD_BIND + MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method)); +#else + MethodBind *a = memnew((MethodBindTR<R, P...>)(reinterpret_cast<R (MB_T::*)(P...)>(p_method))); +#endif + + a->set_instance_class(T::get_class_static()); + return a; +} + +// return, const + +#ifdef TYPED_METHOD_BIND +template <class T, class R, class... P> +#else +template <class R, class... P> +#endif +class MethodBindTRC : public MethodBind { + R(MB_T::*method) + (P...) const; + +protected: +#ifdef DEBUG_METHODS_ENABLED +// 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; + } + } + + 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(); + } + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif +#endif + +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; +#ifdef TYPED_METHOD_BIND + call_with_variant_args_retc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments()); +#else + call_with_variant_args_retc_dv((MB_T *)(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments()); +#endif + return ret; + } + +#ifdef PTRCALL_ENABLED + virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) { +#ifdef TYPED_METHOD_BIND + call_with_ptr_args_retc<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret); +#else + call_with_ptr_args_retc<MB_T, R, P...>((MB_T *)(p_object), method, p_args, r_ret); +#endif + } +#endif + + MethodBindTRC(R (MB_T::*p_method)(P...) const) { + method = p_method; + _set_returns(true); + _set_const(true); +#ifdef DEBUG_METHODS_ENABLED + _generate_argument_types(sizeof...(P)); +#endif + set_argument_count(sizeof...(P)); + } +}; + +template <class T, class R, class... P> +MethodBind *create_method_bind(R (T::*p_method)(P...) const) { +#ifdef TYPED_METHOD_BIND + MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method)); +#else + MethodBind *a = memnew((MethodBindTRC<R, P...>)(reinterpret_cast<R (MB_T::*)(P...) const>(p_method))); +#endif + a->set_instance_class(T::get_class_static()); + return a; +} #endif // METHOD_BIND_H |