Skip to content

Commit

Permalink
Use different Object/Ref encoding for virtual methods
Browse files Browse the repository at this point in the history
  • Loading branch information
dsnopek committed Jun 6, 2023
1 parent 2e45bd8 commit adfc303
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 84 deletions.
24 changes: 17 additions & 7 deletions include/godot_cpp/classes/ref.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,17 @@ class Ref {
}
};

template <class T>
struct PtrToArg<Ref<T>> {
template <class T, bool is_virtual>
struct PtrToArg<Ref<T>, is_virtual> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
// Important: p_ptr is T*, not Ref<T>*, since Object* is what engine gives to ptrcall.
ERR_FAIL_NULL_V(p_ptr, Ref<T>());
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(reinterpret_cast<GDExtensionObjectPtr>(const_cast<void *>(p_ptr)))));
if constexpr (is_virtual) {
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
} else {
// Important: p_ptr is T*, not Ref<T>*, since Object* is what engine gives to ptrcall.
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(reinterpret_cast<GDExtensionObjectPtr>(const_cast<void *>(p_ptr)))));
}
}

typedef Ref<T> EncodeT;
Expand All @@ -248,13 +253,18 @@ struct PtrToArg<Ref<T>> {
}
};

template <class T>
struct PtrToArg<const Ref<T> &> {
template <class T, bool is_virtual>
struct PtrToArg<const Ref<T> &, is_virtual> {
typedef Ref<T> EncodeT;

_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
ERR_FAIL_NULL_V(p_ptr, Ref<T>());
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(reinterpret_cast<GDExtensionObjectPtr>(const_cast<void *>(p_ptr)))));
if constexpr (is_virtual) {
GDExtensionRefPtr ref = const_cast<GDExtensionRefPtr>(p_ptr);
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
} else {
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(reinterpret_cast<GDExtensionObjectPtr>(const_cast<void *>(p_ptr)))));
}
}
};

Expand Down
48 changes: 44 additions & 4 deletions include/godot_cpp/core/binder_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ namespace godot {
return (m_enum)p_variant.operator int64_t(); \
} \
}; \
template <> \
struct PtrToArg<m_enum> { \
template <bool is_virtual> \
struct PtrToArg<m_enum, is_virtual> { \
_FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \
return m_enum(*reinterpret_cast<const int64_t *>(p_ptr)); \
} \
Expand All @@ -71,8 +71,8 @@ namespace godot {
return BitField<m_enum>(p_variant.operator int64_t()); \
} \
}; \
template <> \
struct PtrToArg<BitField<m_enum>> { \
template <bool is_virtual> \
struct PtrToArg<BitField<m_enum>, is_virtual> { \
_FORCE_INLINE_ static BitField<m_enum> convert(const void *p_ptr) { \
return BitField<m_enum>(*reinterpret_cast<const int64_t *>(p_ptr)); \
} \
Expand Down Expand Up @@ -229,6 +229,46 @@ void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...) const, const GDExt
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}

template <class T, class... P, size_t... Is>
void call_virtual_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P, true>::convert(p_args[Is])...);
}

template <class T, class... P, size_t... Is>
void call_virtual_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P, true>::convert(p_args[Is])...);
}

template <class T, class R, class... P, size_t... Is>
void call_virtual_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R, true>::encode((p_instance->*p_method)(PtrToArg<P, true>::convert(p_args[Is])...), r_ret);
}

template <class T, class R, class... P, size_t... Is>
void call_virtual_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R, true>::encode((p_instance->*p_method)(PtrToArg<P, true>::convert(p_args[Is])...), r_ret);
}

template <class T, class... P>
void call_virtual_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_virtual_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}

template <class T, class... P>
void call_virtual_with_ptr_args(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_virtual_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}

template <class T, class R, class... P>
void call_virtual_with_ptr_args(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_virtual_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}

template <class T, class R, class... P>
void call_virtual_with_ptr_args(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_virtual_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}

template <class T, class... P, size_t... Is>
void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
Expand Down
2 changes: 1 addition & 1 deletion include/godot_cpp/core/class_db.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class ClassDB {
#define BIND_VIRTUAL_METHOD(m_class, m_method) \
{ \
auto ___call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \
call_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \
call_virtual_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \
}; \
godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, ___call##m_method); \
}
Expand Down
54 changes: 31 additions & 23 deletions include/godot_cpp/core/method_ptrcall.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@

namespace godot {

template <class T>
template <class T, bool is_virtual = false>
struct PtrToArg {};

#define MAKE_PTRARG(m_type) \
template <> \
struct PtrToArg<m_type> { \
template <bool is_virtual> \
struct PtrToArg<m_type, is_virtual> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
Expand All @@ -53,8 +53,8 @@ struct PtrToArg {};
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
} \
}; \
template <> \
struct PtrToArg<const m_type &> { \
template <bool is_virtual> \
struct PtrToArg<const m_type &, is_virtual> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
Expand All @@ -65,8 +65,8 @@ struct PtrToArg {};
}

#define MAKE_PTRARGCONV(m_type, m_conv) \
template <> \
struct PtrToArg<m_type> { \
template <bool is_virtual> \
struct PtrToArg<m_type, is_virtual> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
} \
Expand All @@ -78,8 +78,8 @@ struct PtrToArg {};
return static_cast<m_conv>(p_val); \
} \
}; \
template <> \
struct PtrToArg<const m_type &> { \
template <bool is_virtual> \
struct PtrToArg<const m_type &, is_virtual> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
} \
Expand All @@ -93,8 +93,8 @@ struct PtrToArg {};
}

#define MAKE_PTRARG_BY_REFERENCE(m_type) \
template <> \
struct PtrToArg<m_type> { \
template <bool is_virtual> \
struct PtrToArg<m_type, is_virtual> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
Expand All @@ -103,8 +103,8 @@ struct PtrToArg {};
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
} \
}; \
template <> \
struct PtrToArg<const m_type &> { \
template <bool is_virtual> \
struct PtrToArg<const m_type &, is_virtual> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
Expand Down Expand Up @@ -166,21 +166,29 @@ MAKE_PTRARG_BY_REFERENCE(Variant);

// This is for Object.

template <class T>
struct PtrToArg<T *> {
template <class T, bool is_virtual>
struct PtrToArg<T *, is_virtual> {
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
return reinterpret_cast<T *>(godot::internal::get_object_instance_binding(reinterpret_cast<GDExtensionObjectPtr>(const_cast<void *>(p_ptr))));
if constexpr (is_virtual) {
return reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
} else {
return reinterpret_cast<T *>(godot::internal::get_object_instance_binding(reinterpret_cast<GDExtensionObjectPtr>(const_cast<void *>(p_ptr))));
}
}
typedef Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
}
};

template <class T>
struct PtrToArg<const T *> {
template <class T, bool is_virtual>
struct PtrToArg<const T *, is_virtual> {
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
return reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(reinterpret_cast<GDExtensionObjectPtr>(const_cast<void *>(p_ptr))));
if constexpr (is_virtual) {
return reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
} else {
return reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(reinterpret_cast<GDExtensionObjectPtr>(const_cast<void *>(p_ptr))));
}
}
typedef const Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
Expand All @@ -190,8 +198,8 @@ struct PtrToArg<const T *> {

// Pointers.
#define GDVIRTUAL_NATIVE_PTR(m_type) \
template <> \
struct PtrToArg<m_type *> { \
template <bool is_virtual> \
struct PtrToArg<m_type *, is_virtual> { \
_FORCE_INLINE_ static m_type *convert(const void *p_ptr) { \
return (m_type *)(*(void **)p_ptr); \
} \
Expand All @@ -201,8 +209,8 @@ struct PtrToArg<const T *> {
} \
}; \
\
template <> \
struct PtrToArg<const m_type *> { \
template <bool is_virtual> \
struct PtrToArg<const m_type *, is_virtual> { \
_FORCE_INLINE_ static const m_type *convert(const void *p_ptr) { \
return (const m_type *)(*(const void **)p_ptr); \
} \
Expand Down
8 changes: 4 additions & 4 deletions include/godot_cpp/core/type_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ inline StringName __constant_get_bitfield_name(T param, StringName p_constant) {
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
}

template <class T>
struct PtrToArg<TypedArray<T>> {
template <class T, bool is_virtual>
struct PtrToArg<TypedArray<T>, is_virtual> {
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
}
Expand All @@ -306,8 +306,8 @@ struct PtrToArg<TypedArray<T>> {
}
};

template <class T>
struct PtrToArg<const TypedArray<T> &> {
template <class T, bool is_virtual>
struct PtrToArg<const TypedArray<T> &, is_virtual> {
typedef Array EncodeT;
_FORCE_INLINE_ static TypedArray<T>
convert(const void *p_ptr) {
Expand Down
Loading

0 comments on commit adfc303

Please sign in to comment.