Browse Source

Rewrite Ref<T> to behave like Godot again

Marc Gilleron 7 years ago
parent
commit
3197c3dce3
2 changed files with 158 additions and 109 deletions
  1. 6 1
      binding_generator.py
  2. 152 108
      include/core/Ref.hpp

+ 6 - 1
binding_generator.py

@@ -72,10 +72,15 @@ def generate_class_header(used_classes, c):
     
     
     source.append("#include <core/CoreTypes.hpp>")
-    source.append("#include <core/Ref.hpp>")
 
     class_name = strip_name(c["name"])
 
+    # Ref<T> is not included in object.h in Godot either,
+    # so don't include it here because it's not needed
+    if class_name != "Object":
+        source.append("#include <core/Ref.hpp>")
+
+
     included = []
 
     for used_class in used_classes:

+ 152 - 108
include/core/Ref.hpp

@@ -3,156 +3,200 @@
 
 #include "Variant.hpp"
 #include "GodotGlobal.hpp"
+#include "../Reference.hpp"
 
 namespace godot {
 
-template<class T>
+// Replicates Godot's Ref<T> behavior
+// Rewritten from f5234e70be7dec4930c2d5a0e829ff480d044b1d.
+template <class T>
 class Ref {
-	T *reference;
+
+	T *reference = NULL;
+
+	void ref(const Ref &p_from) {
+
+		if (p_from.reference == reference)
+			return;
+
+		unref();
+
+		reference = p_from.reference;
+		if (reference)
+			reference->reference();
+	}
+
+	void ref_pointer(T *p_ref) {
+
+		ERR_FAIL_COND(!p_ref);
+
+		if (p_ref->init_ref())
+			reference = p_ref;
+	}
 
 public:
-	inline bool operator==(const Ref<T> &r) const
-	{
-		return reference == r.reference;
-	}
-	
-	inline bool operator!=(const Ref<T> &r) const
-	{
-		return reference != r.reference;
-	}
-	
-	inline T *operator->()
-	{
+	inline bool operator<(const Ref<T> &p_r) const {
+
+		return reference < p_r.reference;
+	}
+	inline bool operator==(const Ref<T> &p_r) const {
+
+		return reference == p_r.reference;
+	}
+	inline bool operator!=(const Ref<T> &p_r) const {
+
+		return reference != p_r.reference;
+	}
+
+	inline T *operator->() {
+
 		return reference;
 	}
-	
-	inline T *operator*()
-	{
+
+	inline T *operator*() {
+
 		return reference;
 	}
-	
-	inline T *ptr()
-	{
+
+	inline const T *operator->() const {
+
 		return reference;
 	}
-	
-	inline const T *operator->() const
-	{
+
+	inline const T *ptr() const {
+
 		return reference;
 	}
-	
-	inline const T *operator*() const
-	{
+	inline T *ptr() {
+
 		return reference;
 	}
-	
-	inline const T *ptr() const
-	{
+
+	inline const T *operator*() const {
+
 		return reference;
 	}
-	
-	
-	
-	void operator=(const Ref &from)
-	{
-		if (reference)
-			unref();
 
-		if (from.reference) {
-			reference = from.reference;
-			reference->reference();
-		} else {
-			reference = nullptr;
-		}
+	operator Variant() const {
+		// Note: the C API handles the cases where the object is a Reference,
+		// so the Variant will be correctly constructed with a RefPtr engine-side
+		return Variant((Object*)reference);
 	}
 
-	template<class T_Other>
-	void operator=(const Ref<T_Other> &from)
-	{
-		if (reference)
-			unref();
+	void operator=(const Ref &p_from) {
 
-		if (from.reference) {
-			reference = (T *) from.reference;
-			reference->reference();
-		} else {
-			reference = nullptr;
-		}
+		ref(p_from);
 	}
-	
-	void operator=(const Variant &variant)
-	{
-		if (reference)
-			unref();
 
-		reference = (T *) (Object *) variant;
-	}
-	
-	operator Variant() const
-	{
-		return Variant((Object *) reference);
+	template <class T_Other>
+	void operator=(const Ref<T_Other> &p_from) {
+
+		// TODO We need a safe cast
+		Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
+		if (!refb) {
+			unref();
+			return;
+		}
+		Ref r;
+		//r.reference = Object::cast_to<T>(refb);
+		r.reference = (T*)refb;
+		ref(r);
+		r.reference = NULL;
 	}
-	
-	template<class T_Other>
-	Ref(const Ref<T_Other> &from)
-	{
-		if (from.reference) {
-			reference = (T *) from.reference;
-			reference->reference();
-		} else {
-			reference = nullptr;
+
+	void operator=(const Variant &p_variant) {
+
+		// TODO We need a safe cast
+		Reference *refb = (Reference *) (Object *) p_variant;
+		if (!refb) {
+			unref();
+			return;
 		}
+		Ref r;
+		// TODO We need a safe cast
+		//r.reference = Object::cast_to<T>(refb);
+		r.reference = (T *)refb;
+		ref(r);
+		r.reference = NULL;
 	}
-	
-	Ref(const Ref &from)
-	{
-		if (from.reference) {
-			reference = from.reference;
-			reference->reference();
-		} else {
-			reference = nullptr;
+
+	Ref(const Ref &p_from) {
+
+		reference = NULL;
+		ref(p_from);
+	}
+
+	template <class T_Other>
+	Ref(const Ref<T_Other> &p_from) {
+
+		reference = NULL;
+		// TODO We need a safe cast
+		Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
+		if (!refb) {
+			unref();
+			return;
 		}
+		Ref r;
+		// TODO We need a safe cast
+		//r.reference = Object::cast_to<T>(refb);
+		r.reference = (T *)refb;
+		ref(r);
+		r.reference = NULL;
 	}
 
+	Ref(T *p_reference) {
 
-	Ref(T *r)
-	{
-		reference = r;
+		if (p_reference)
+			ref_pointer(p_reference);
+		else
+			reference = NULL;
 	}
-	
-	template<class T_Other>
-	Ref(T_Other *r) : Ref((T *) r) {}
 
-	Ref(const Variant &variant)
-	{
-		reference = (T *) (Object *) variant;
+	Ref(const Variant &p_variant) {
+
+		reference = NULL;
+		// TODO We need a safe cast
+		Reference *refb = (Reference *) (Object *) p_variant;
+		if (!refb) {
+			unref();
+			return;
+		}
+		Ref r;
+		// TODO We need a safe cast
+		//r.reference = Object::cast_to<T>(refb);
+		r.reference = (T *)refb;
+		ref(r);
+		r.reference = NULL;
 	}
 
-	inline bool is_valid() const { return reference != nullptr; }
-	inline bool is_null() const { return reference == nullptr; }
-	
-	void unref()
-	{
+	inline bool is_valid() const { return reference != NULL; }
+	inline bool is_null() const { return reference == NULL; }
+
+	void unref() {
+		//TODO this should be moved to mutexes, since this engine does not really
+		// do a lot of referencing on references and stuff
+		// mutexes will avoid more crashes?
+
 		if (reference && reference->unreference()) {
-			godot::api->godot_object_destroy((godot_object *) reference);
+
+			//memdelete(reference);
+			delete reference;
 		}
-		reference = nullptr;
+		reference = NULL;
 	}
-	
-	void instance()
-	{
-		unref();
 
-		reference = new T;
+	void instance() {
+		//ref(memnew(T));
+		ref(new T);
 	}
 
-	Ref()
-	{
-		reference = nullptr;
+	Ref() {
+
+		reference = NULL;
 	}
-	
-	~Ref()
-	{
+
+	~Ref() {
+
 		unref();
 	}
 };