Browse Source

Add copy/move constructors and assignment op to builtin types

George Marques 4 years ago
parent
commit
f19bb9f57c
1 changed files with 59 additions and 5 deletions
  1. 59 5
      binding_generator.py

+ 59 - 5
binding_generator.py

@@ -284,6 +284,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
     result.append("")
     result.append("")
     result.append("public:")
     result.append("public:")
 
 
+    copy_constructor_index = -1
+
     if "constructors" in builtin_api:
     if "constructors" in builtin_api:
         for constructor in builtin_api["constructors"]:
         for constructor in builtin_api["constructors"]:
             method_signature = f"\t{class_name}("
             method_signature = f"\t{class_name}("
@@ -291,10 +293,15 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
                 method_signature += make_function_parameters(
                 method_signature += make_function_parameters(
                     constructor["arguments"], include_default=True, for_builtin=True
                     constructor["arguments"], include_default=True, for_builtin=True
                 )
                 )
+                if len(constructor["arguments"]) == 1 and constructor["arguments"][0]["type"] == class_name:
+                    copy_constructor_index = constructor["index"]
             method_signature += ");"
             method_signature += ");"
 
 
             result.append(method_signature)
             result.append(method_signature)
 
 
+    # Move constructor.
+    result.append(f'\t{class_name}({class_name} &&other);')
+
     # Special cases.
     # Special cases.
     if class_name == "String" or class_name == "StringName" or class_name == "NodePath":
     if class_name == "String" or class_name == "StringName" or class_name == "NodePath":
         result.append(f"\t{class_name}(const char *from);")
         result.append(f"\t{class_name}(const char *from);")
@@ -383,6 +390,13 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
                         f'\t{correct_type(operator["return_type"])} operator{operator["name"].replace("unary", "")}() const;'
                         f'\t{correct_type(operator["return_type"])} operator{operator["name"].replace("unary", "")}() const;'
                     )
                     )
 
 
+    # Copy assignment.
+    if copy_constructor_index >= 0:
+        result.append(f"\t{class_name} &operator=(const {class_name} &other);")
+
+    # Move assignment.
+    result.append(f"\t{class_name} &operator=({class_name} &&other);")
+
     # Special cases.
     # Special cases.
     if class_name == "String":
     if class_name == "String":
         result.append("String &operator=(const char *p_str);")
         result.append("String &operator=(const char *p_str);")
@@ -449,6 +463,8 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
 
 
     result.append("#include <godot_cpp/core/builtin_ptrcall.hpp>")
     result.append("#include <godot_cpp/core/builtin_ptrcall.hpp>")
     result.append("")
     result.append("")
+    result.append("#include <utility>")
+    result.append("")
     result.append("namespace godot {")
     result.append("namespace godot {")
     result.append("")
     result.append("")
 
 
@@ -517,6 +533,8 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
     result.append("}")
     result.append("}")
     result.append("")
     result.append("")
 
 
+    copy_constructor_index = -1
+
     if "constructors" in builtin_api:
     if "constructors" in builtin_api:
         for constructor in builtin_api["constructors"]:
         for constructor in builtin_api["constructors"]:
             method_signature = f"{class_name}::{class_name}("
             method_signature = f"{class_name}::{class_name}("
@@ -532,6 +550,8 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
                 f'\tinternal::_call_builtin_constructor(_method_bindings.constructor_{constructor["index"]}, &opaque'
                 f'\tinternal::_call_builtin_constructor(_method_bindings.constructor_{constructor["index"]}, &opaque'
             )
             )
             if "arguments" in constructor:
             if "arguments" in constructor:
+                if len(constructor["arguments"]) == 1 and constructor["arguments"][0]["type"] == class_name:
+                    copy_constructor_index = constructor["index"]
                 method_call += ", "
                 method_call += ", "
                 arguments = []
                 arguments = []
                 for argument in constructor["arguments"]:
                 for argument in constructor["arguments"]:
@@ -549,6 +569,12 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
             result.append("}")
             result.append("}")
             result.append("")
             result.append("")
 
 
+    # Move constructor.
+    result.append(f'{class_name}::{class_name}({class_name} &&other) {{')
+    result.append("\tstd::swap(opaque, other.opaque);")
+    result.append("}")
+    result.append("")
+
     if builtin_api["has_destructor"]:
     if builtin_api["has_destructor"]:
         result.append(f"{class_name}::~{class_name}() {{")
         result.append(f"{class_name}::~{class_name}() {{")
         result.append("\t_method_bindings.destructor(&opaque);")
         result.append("\t_method_bindings.destructor(&opaque);")
@@ -638,8 +664,33 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
                         f'\treturn internal::_call_builtin_operator_ptr<{correct_type(operator["return_type"])}>(_method_bindings.operator_{get_operator_id_name(operator["name"])}, (const GDNativeTypePtr)&opaque, (const GDNativeTypePtr)nullptr);'
                         f'\treturn internal::_call_builtin_operator_ptr<{correct_type(operator["return_type"])}>(_method_bindings.operator_{get_operator_id_name(operator["name"])}, (const GDNativeTypePtr)&opaque, (const GDNativeTypePtr)nullptr);'
                     )
                     )
                     result.append("}")
                     result.append("}")
-            result.append("")
+                result.append("")
+
+    # Copy assignment.
+    if copy_constructor_index >= 0:
+        result.append(f"{class_name} &{class_name}::operator=(const {class_name} &other) {{")
+        if builtin_api["has_destructor"]:
+            result.append("\t_method_bindings.destructor(&opaque);")
+        (encode, arg_name) = get_encoded_arg(
+            "other",
+            class_name,
+            None,
+        )
+        result += encode
+        result.append(
+            f"\tinternal::_call_builtin_constructor(_method_bindings.constructor_{copy_constructor_index}, &opaque, {arg_name});"
+        )
+        result.append("\treturn *this;")
+        result.append("}")
+        result.append("")
+
+    # Move assignment.
+    result.append(f"{class_name} &{class_name}::operator=({class_name} &&other) {{")
+    result.append("\tstd::swap(opaque, other.opaque);")
+    result.append("\treturn *this;")
+    result.append("}")
 
 
+    result.append("")
     result.append("} //namespace godot")
     result.append("} //namespace godot")
 
 
     return "\n".join(result)
     return "\n".join(result)
@@ -699,7 +750,6 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
                     type_name = method["return_value"]["type"]
                     type_name = method["return_value"]["type"]
                     if type_name.endswith("*"):
                     if type_name.endswith("*"):
                         type_name = type_name[:-1]
                         type_name = type_name[:-1]
-                        print("New type name ", type_name)
                     if is_included(type_name, class_name):
                     if is_included(type_name, class_name):
                         if is_enum(type_name):
                         if is_enum(type_name):
                             fully_used_classes.add(get_enum_class(type_name))
                             fully_used_classes.add(get_enum_class(type_name))
@@ -936,11 +986,15 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
 
 
     if is_singleton:
     if is_singleton:
         result.append(f"{class_name} *{class_name}::get_singleton() {{")
         result.append(f"{class_name} *{class_name}::get_singleton() {{")
-        result.append(f'\tstatic GDNativeObjectPtr singleton_obj = internal::interface->global_get_singleton("{class_name}");')
+        result.append(
+            f'\tstatic GDNativeObjectPtr singleton_obj = internal::interface->global_get_singleton("{class_name}");'
+        )
         result.append("#ifdef DEBUG_ENABLED")
         result.append("#ifdef DEBUG_ENABLED")
-        result.append('\tERR_FAIL_COND_V(singleton_obj == nullptr, nullptr);')
+        result.append("\tERR_FAIL_COND_V(singleton_obj == nullptr, nullptr);")
         result.append("#endif // DEBUG_ENABLED")
         result.append("#endif // DEBUG_ENABLED")
-        result.append(f'\tstatic {class_name} *singleton = reinterpret_cast<{class_name} *>(internal::interface->object_get_instance_binding(singleton_obj, internal::token, &{class_name}::___binding_callbacks));')
+        result.append(
+            f"\tstatic {class_name} *singleton = reinterpret_cast<{class_name} *>(internal::interface->object_get_instance_binding(singleton_obj, internal::token, &{class_name}::___binding_callbacks));"
+        )
         result.append("\treturn singleton;")
         result.append("\treturn singleton;")
         result.append("}")
         result.append("}")
         result.append("")
         result.append("")