Use AncestralClass to speed up Object::cast_to when possible.

This commit is contained in:
Lukas Tenbrink 2025-09-22 01:30:57 +02:00
parent 149a4b4ca1
commit 96619d46a1
15 changed files with 62 additions and 8 deletions

View file

@ -605,6 +605,8 @@ public:
MESH_INSTANCE_3D = 1 << 14,
};
static constexpr AncestralClass static_ancestral_class = (AncestralClass)0;
struct Connection {
::Signal signal;
Callable callable;
@ -790,6 +792,8 @@ protected:
bool _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false);
void _define_ancestry(AncestralClass p_class) { _ancestry |= (uint32_t)p_class; }
// Prefer using derives_from.
bool _has_ancestry(AncestralClass p_class) const { return _ancestry & (uint32_t)p_class; }
virtual bool _uses_signal_mutex() const;
@ -821,16 +825,12 @@ public:
static T *cast_to(Object *p_object) {
// This is like dynamic_cast, but faster.
// The reason is that we can assume no virtual and multiple inheritance.
static_assert(std::is_base_of_v<Object, T>, "T must be derived from Object");
static_assert(std::is_same_v<std::decay_t<T>, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS");
return p_object && p_object->is_class_ptr(T::get_class_ptr_static()) ? static_cast<T *>(p_object) : nullptr;
return p_object && p_object->derives_from<T>() ? static_cast<T *>(p_object) : nullptr;
}
template <typename T>
static const T *cast_to(const Object *p_object) {
static_assert(std::is_base_of_v<Object, T>, "T must be derived from Object");
static_assert(std::is_same_v<std::decay_t<T>, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS");
return p_object && p_object->is_class_ptr(T::get_class_ptr_static()) ? static_cast<const T *>(p_object) : nullptr;
return p_object && p_object->derives_from<T>() ? static_cast<const T *>(p_object) : nullptr;
}
enum {
@ -864,7 +864,8 @@ public:
}
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
bool has_ancestry(AncestralClass p_class) const { return _ancestry & (uint32_t)p_class; }
template <typename T>
bool derives_from() const;
const StringName &get_class_name() const;
@ -1024,7 +1025,7 @@ public:
void clear_internal_resource_paths();
_ALWAYS_INLINE_ bool is_ref_counted() const { return has_ancestry(AncestralClass::REF_COUNTED); }
_ALWAYS_INLINE_ bool is_ref_counted() const { return _has_ancestry(AncestralClass::REF_COUNTED); }
void cancel_free();
@ -1035,6 +1036,29 @@ public:
bool predelete_handler(Object *p_object);
void postinitialize_handler(Object *p_object);
template <typename T>
bool Object::derives_from() const {
static_assert(std::is_base_of_v<Object, T>, "T must be derived from Object.");
static_assert(std::is_same_v<std::decay_t<T>, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS.");
// If there is an explicitly set ancestral class on the type, we can use that.
if constexpr (T::static_ancestral_class != T::super_type::static_ancestral_class) {
return _has_ancestry(T::static_ancestral_class);
} else {
return is_class_ptr(T::get_class_ptr_static());
}
}
template <>
inline bool Object::derives_from<Object>() const {
return true;
}
template <>
inline bool Object::derives_from<const Object>() const {
return true;
}
class ObjectDB {
// This needs to add up to 63, 1 bit is for reference.
#define OBJECTDB_VALIDATOR_BITS 39