Add support for copying arrays, fixes bug 477107
authorJürg Billeter <j@bitron.ch>
Sat, 11 Oct 2008 11:18:49 +0000 (11:18 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Sat, 11 Oct 2008 11:18:49 +0000 (11:18 +0000)
2008-10-11  Jürg Billeter  <j@bitron.ch>

* gobject/valaccodegenerator.vala:

Add support for copying arrays, fixes bug 477107

svn path=/trunk/; revision=1832

ChangeLog
gobject/valaccodegenerator.vala

index 09b03c4..146a96b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2008-10-11  Jürg Billeter  <j@bitron.ch>
 
+       * gobject/valaccodegenerator.vala:
+
+       Add support for copying arrays, fixes bug 477107
+
+2008-10-11  Jürg Billeter  <j@bitron.ch>
+
        * vapi/atk.vapi:
        * vapi/gdk-2.0.vapi:
        * vapi/gdk-pixbuf-2.0.vapi:
index 7066d3b..2c58630 100644 (file)
@@ -81,6 +81,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
        public int next_temp_var_id = 0;
        private int current_try_id = 0;
        private int next_try_id = 0;
+       private int next_array_dup_id = 0;
        public bool in_creation_method = false;
        private bool in_constructor = false;
        public bool in_static_or_class_ctor = false;
@@ -1392,7 +1393,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
                                        dup_function = "";
                                }
                        } else {
-                               // duplicating non-reference counted structs may cause side-effects (and performance issues)
+                               // duplicating non-reference counted objects may cause side-effects (and performance issues)
                                Report.error (source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (type.data_type.name));
                                return null;
                        }
@@ -1402,8 +1403,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
                        string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
                        return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
                } else if (type is ArrayType) {
-                       Report.error (source_reference, "internal error: duplicating %s instances not yet supported".printf (type.to_string ()));
-                       return null;
+                       return new CCodeIdentifier (generate_array_dup_wrapper ((ArrayType) type));
                } else if (type is PointerType) {
                        var pointer_type = (PointerType) type;
                        return get_dup_func_expression (pointer_type.base_type, source_reference);
@@ -1412,6 +1412,77 @@ public class Vala.CCodeGenerator : CodeGenerator {
                }
        }
 
+       string generate_array_dup_wrapper (ArrayType array_type) {
+               string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
+
+               if (!add_wrapper (dup_func)) {
+                       // wrapper already defined
+                       return dup_func;
+               }
+
+               // declaration
+
+               var function = new CCodeFunction (dup_func, array_type.get_cname ());
+               function.modifiers = CCodeModifiers.STATIC;
+
+               function.add_parameter (new CCodeFormalParameter ("self", array_type.get_cname ()));
+               // total length over all dimensions
+               function.add_parameter (new CCodeFormalParameter ("length", "int"));
+
+               // definition
+
+               var block = new CCodeBlock ();
+
+               if (requires_copy (array_type.element_type)) {
+                       var old_temp_vars = temp_vars;
+
+                       var cdecl = new CCodeDeclaration (array_type.get_cname ());
+                       var cvardecl = new CCodeVariableDeclarator ("result");
+                       cdecl.add_declarator (cvardecl);
+                       var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+                       gnew.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+                       gnew.add_argument (new CCodeIdentifier ("length"));
+                       cvardecl.initializer = gnew;
+                       block.add_statement (cdecl);
+
+                       var idx_decl = new CCodeDeclaration ("int");
+                       idx_decl.add_declarator (new CCodeVariableDeclarator ("i"));
+                       block.add_statement (idx_decl);
+
+                       var loop_body = new CCodeBlock ();
+                       loop_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("result"), new CCodeIdentifier ("i")), get_ref_cexpression (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), null, array_type))));
+
+                       var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")), loop_body);
+                       cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
+                       cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
+                       block.add_statement (cfor);
+
+                       block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+
+                       var cfrag = new CCodeFragment ();
+                       append_temp_decl (cfrag, temp_vars);
+                       block.add_statement (cfrag);
+                       temp_vars = old_temp_vars;
+               } else {
+                       var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
+                       dup_call.add_argument (new CCodeIdentifier ("self"));
+
+                       var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+                       sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+                       dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("length"), sizeof_call));
+
+                       block.add_statement (new CCodeReturnStatement (dup_call));
+               }
+
+               // append to file
+
+               source_type_member_declaration.append (function.copy ());
+
+               function.block = block;
+               source_type_member_definition.append (function);
+
+               return dup_func;
+       }
 
        private string generate_struct_dup_wrapper (ValueType value_type) {
                string dup_func = "_%sdup".printf (value_type.type_symbol.get_lower_case_cprefix ());
@@ -3092,7 +3163,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
                        var ctemp = new CCodeIdentifier (decl.name);
                        
                        var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
-                       if (expression_type.data_type == null) {
+                       if (expression_type.type_parameter != null) {
                                if (!(current_type_symbol is Class)) {
                                        return cexpr;
                                }
@@ -3102,11 +3173,27 @@ public class Vala.CCodeGenerator : CodeGenerator {
                                cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cdupisnull);
                        }
 
-                       if (expression_type.data_type != null) {
-                               ccall.add_argument (ctemp);
-                       } else {
+                       if (expression_type.type_parameter != null) {
                                // cast from gconstpointer to gpointer as GBoxedCopyFunc expects gpointer
                                ccall.add_argument (new CCodeCastExpression (ctemp, "gpointer"));
+                       } else {
+                               ccall.add_argument (ctemp);
+                       }
+
+                       if (expression_type is ArrayType) {
+                               var array_type = (ArrayType) expression_type;
+                               bool first = true;
+                               CCodeExpression csizeexpr = null;
+                               for (int dim = 1; dim <= array_type.rank; dim++) {
+                                       if (first) {
+                                               csizeexpr = get_array_length_cexpression (expr, dim);
+                                               first = false;
+                                       } else {
+                                               csizeexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeexpr, get_array_length_cexpression (expr, dim));
+                                       }
+                               }
+
+                               ccall.add_argument (csizeexpr);
                        }
 
                        var ccomma = new CCodeCommaExpression ();