diff --git a/binding_generator.py b/binding_generator.py index 2949bcad..de428bc4 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -1676,6 +1676,8 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node): used_classes = list(used_classes) used_classes.sort() fully_used_classes = list(fully_used_classes) + if class_api["name"] == "RefCounted": + fully_used_classes.remove("Ref") # Special case; Ref should include RefCounted but not vice versa. fully_used_classes.sort() with header_filename.open("w+", encoding="utf-8") as header_file: diff --git a/include/godot_cpp/classes/ref.hpp b/include/godot_cpp/classes/ref.hpp index a0e5d0fb..d6c77a8b 100644 --- a/include/godot_cpp/classes/ref.hpp +++ b/include/godot_cpp/classes/ref.hpp @@ -42,30 +42,34 @@ namespace godot { // Helper class for RefCounted objects, same as Godot one. -class RefCounted; - template class Ref { T *reference = nullptr; - void ref(const Ref &p_from) { - if (p_from.reference == reference) { + _FORCE_INLINE_ void ref(const Ref &p_from) { + ref_pointer(p_from.reference); + } + + template + _FORCE_INLINE_ void ref_pointer(T *p_refcounted) { + if (p_refcounted == reference) { return; } - unref(); - - reference = p_from.reference; + // This will go out of scope and get unref'd. + Ref cleanup_ref; + cleanup_ref.reference = reference; + reference = p_refcounted; if (reference) { - reference->reference(); - } - } - - void ref_pointer(T *p_ref) { - ERR_FAIL_NULL(p_ref); - - if (p_ref->init_ref()) { - reference = p_ref; + if constexpr (Init) { + if (!reference->init_ref()) { + reference = nullptr; + } + } else { + if (!reference->reference()) { + reference = nullptr; + } + } } } @@ -111,40 +115,32 @@ public: ref(p_from); } - template - void operator=(const Ref &p_from) { - RefCounted *refb = const_cast(static_cast(p_from.ptr())); - if (!refb) { - unref(); + void operator=(Ref &&p_from) { + if (reference == p_from.reference) { return; } + unref(); + reference = p_from.reference; + p_from.reference = nullptr; + } - Ref r; - r.reference = Object::cast_to(refb); - ref(r); - r.reference = nullptr; + template + void operator=(const Ref &p_from) { + ref_pointer(Object::cast_to(p_from.ptr())); + } + + void operator=(T *p_from) { + ref_pointer(p_from); } void operator=(const Variant &p_variant) { - // Needs testing, Variant has a cast to Object * here. - - // Object *object = p_variant.get_validated_object(); - Object *object = p_variant; + Object *object = p_variant.get_validated_object(); if (object == reference) { return; } - unref(); - - if (!object) { - return; - } - - T *r = Object::cast_to(object); - if (r && r->reference()) { - reference = r; - } + ref_pointer(Object::cast_to(object)); } template @@ -152,69 +148,55 @@ public: if (reference == p_ptr) { return; } - unref(); - T *r = Object::cast_to(p_ptr); - if (r) { - ref_pointer(r); - } + ref_pointer(Object::cast_to(p_ptr)); } Ref(const Ref &p_from) { - ref(p_from); + this->operator=(p_from); + } + + Ref(Ref &&p_from) { + reference = p_from.reference; + p_from.reference = nullptr; } template Ref(const Ref &p_from) { - RefCounted *refb = const_cast(static_cast(p_from.ptr())); - if (!refb) { - unref(); - return; - } - - Ref r; - r.reference = Object::cast_to(refb); - ref(r); - r.reference = nullptr; + this->operator=(p_from); } - Ref(T *p_reference) { - if (p_reference) { - ref_pointer(p_reference); - } + Ref(T *p_from) { + this->operator=(p_from); } - Ref(const Variant &p_variant) { - // Needs testing, Variant has a cast to Object * here. - - // Object *object = p_variant.get_validated_object(); - Object *object = p_variant; - - if (!object) { - return; - } - - T *r = Object::cast_to(object); - if (r && r->reference()) { - reference = r; - } + Ref(const Variant &p_from) { + this->operator=(p_from); } inline bool is_valid() const { return reference != nullptr; } inline bool is_null() const { return reference == nullptr; } void unref() { - if (reference && reference->unreference()) { - memdelete(reference); + if (reference) { + // NOTE: `reinterpret_cast` is "safe" here because we know `T` has simple linear + // inheritance to `RefCounted`. This guarantees that `T * == `RefCounted *`, which + // allows us to declare `Ref` with forward declared `T` types. + if (reinterpret_cast(reference)->unreference()) { + memdelete(reinterpret_cast(reference)); + } + reference = nullptr; } - reference = nullptr; } - void instantiate() { - ref(memnew(T())); + template + void instantiate(VarArgs... p_params) { + ref(memnew(T(p_params...))); } - Ref() {} + uint32_t hash() const { return HashMapHasherDefault::hash(reference); } + + Ref() = default; ~Ref() { unref(); @@ -224,7 +206,7 @@ public: // without adding to the refcount. inline static Ref _gde_internal_constructor(Object *obj) { Ref r; - r.reference = (T *)obj; + r.reference = reinterpret_cast(obj); return r; } };