1 /* valaccodearraymodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 public class Vala.CCodeArrayModule : CCodeMethodCallModule {
27 int next_array_dup_id = 0;
28 int next_array_add_id = 0;
30 void append_initializer_list (CCodeExpression name_cnode, InitializerList initializer_list, int rank, ref int i) {
31 foreach (Expression e in initializer_list.get_initializers ()) {
33 append_initializer_list (name_cnode, (InitializerList) e, rank - 1, ref i);
35 ccode.add_assignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), get_cvalue (e));
41 public override void visit_array_creation_expression (ArrayCreationExpression expr) {
42 var array_type = expr.target_type as ArrayType;
43 if (array_type != null && array_type.fixed_length) {
44 // no heap allocation for fixed-length arrays
46 var temp_var = get_temp_variable (array_type, true, expr);
48 var name_cnode = get_variable_cexpression (temp_var.name);
51 emit_temp_var (temp_var);
53 append_initializer_list (name_cnode, expr.initializer_list, expr.rank, ref i);
55 set_cvalue (expr, name_cnode);
60 CCodeFunctionCall gnew;
61 if (context.profile == Profile.POSIX) {
62 cfile.add_include ("stdlib.h");
63 gnew = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
65 gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
66 gnew.add_argument (new CCodeIdentifier (get_ccode_name (expr.element_type)));
70 CCodeExpression cexpr = null;
72 // iterate over each dimension
73 foreach (Expression size in expr.get_sizes ()) {
74 CCodeExpression csize = get_cvalue (size);
75 append_array_length (expr, csize);
81 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, csize);
85 // add extra item to have array NULL-terminated for all reference types
86 if (expr.element_type.type_symbol != null && expr.element_type.type_symbol.is_reference_type ()) {
87 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cexpr, new CCodeConstant ("1"));
90 gnew.add_argument (cexpr);
92 if (context.profile == Profile.POSIX) {
93 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
94 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (expr.element_type)));
95 gnew.add_argument (csizeof);
98 var temp_var = get_temp_variable (expr.value_type, true, expr);
99 var name_cnode = get_variable_cexpression (temp_var.name);
102 emit_temp_var (temp_var);
104 ccode.add_assignment (name_cnode, gnew);
106 if (expr.initializer_list != null) {
107 append_initializer_list (name_cnode, expr.initializer_list, expr.rank, ref i);
110 set_cvalue (expr, name_cnode);
113 public override string get_array_length_cname (string array_cname, int dim) {
114 return "%s_length%d".printf (array_cname, dim);
117 public override string get_variable_array_length_cname (Variable variable, int dim) {
118 string? length_cname = get_ccode_array_length_name (variable);
119 if (length_cname == null) {
120 length_cname = get_array_length_cname (get_ccode_name (variable), dim);
122 return (!) length_cname;
125 public override CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
126 return get_array_length_cvalue (array_expr.target_value, dim);
129 public override CCodeExpression get_array_length_cvalue (TargetValue value, int dim = -1) {
130 var array_type = value.value_type as ArrayType;
132 if (array_type != null && array_type.fixed_length) {
133 return get_ccodenode (array_type.length);
136 // dim == -1 => total size over all dimensions
138 if (array_type != null && array_type.rank > 1) {
139 CCodeExpression cexpr = get_array_length_cvalue (value, 1);
140 for (dim = 2; dim <= array_type.rank; dim++) {
141 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, get_array_length_cvalue (value, dim));
149 List<CCodeExpression> size = ((GLibValue) value).array_length_cvalues;
150 if (size == null || size.size < dim) {
151 Report.error (array_type.source_reference, "internal: invalid array_length for given dimension");
152 return new CCodeInvalidExpression ();
154 return size[dim - 1];
157 public override string get_array_size_cname (string array_cname) {
158 return "_%s_size_".printf (array_cname);
161 public override void visit_element_access (ElementAccess expr) {
162 List<Expression> indices = expr.get_indices ();
163 int rank = indices.size;
165 var ccontainer = get_cvalue (expr.container);
166 var cindex = get_cvalue (indices[0]);
167 if (expr.container.symbol_reference is ArrayLengthField) {
168 /* Figure if cindex is a constant expression and calculate dim...*/
169 var lit = indices[0] as IntegerLiteral;
170 var memberaccess = expr.container as MemberAccess;
171 if (lit != null && memberaccess != null) {
172 int dim = int.parse (lit.value);
173 set_cvalue (expr, get_array_length_cexpression (memberaccess.inner, dim + 1));
175 Report.error (expr.source_reference, "internal error: only integer literals supported as index");
177 } else if (expr.container.symbol_reference is Constant && rank > 1) {
178 // access to element in a multi-dimensional array constant
179 var cindices = new ArrayList<CCodeExpression> ();
180 cindices.add (cindex);
181 for (int i = 1; i < rank; i++) {
182 cindices.add (get_cvalue (indices[i]));
184 set_cvalue (expr, new CCodeElementAccess.with_indices (ccontainer, cindices));
186 // access to element in an array
187 for (int i = 1; i < rank; i++) {
188 var cmul = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cindex, get_array_length_cexpression (expr.container, i + 1));
189 cindex = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cmul, get_cvalue (indices[i]));
190 if (expr.container.is_constant ()) {
191 ccontainer = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, ccontainer);
194 set_cvalue (expr, new CCodeElementAccess (ccontainer, cindex));
197 expr.target_value.value_type = expr.value_type.copy ();
199 expr.target_value = store_temp_value (expr.target_value, expr);
201 ((GLibValue) expr.target_value).lvalue = true;
204 public override void visit_slice_expression (SliceExpression expr) {
205 var ccontainer = get_cvalue (expr.container);
206 var cstart = get_cvalue (expr.start);
207 var cstop = get_cvalue (expr.stop);
209 var cstartpointer = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, ccontainer, cstart);
210 var splicelen = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, cstop, cstart);
212 set_cvalue (expr, cstartpointer);
213 ((GLibValue) expr.target_value).non_null = get_non_null (expr.container.target_value);
214 // Make sure no previous length values are preserved
215 set_array_length (expr, splicelen);
218 void append_struct_array_free_loop (Struct st) {
219 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
220 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
221 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1")));
222 ccode.open_for (cforinit, cforcond, cforiter);
224 var cptrarray = new CCodeIdentifier ("array");
225 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
227 var cfreecall = new CCodeFunctionCall (get_destroy_func_expression (new StructValueType (st)));
228 cfreecall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cea));
229 ccode.add_expression (cfreecall);
234 public override string? append_struct_array_free (Struct st) {
235 string cname = "_vala_%s_array_free".printf (get_ccode_name (st));
237 if (cfile.add_declaration (cname)) {
241 generate_type_declaration (ssize_t_type, cfile);
243 var fun = new CCodeFunction (cname, "void");
244 fun.modifiers = CCodeModifiers.STATIC;
245 fun.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (st))));
246 fun.add_parameter (new CCodeParameter ("array_length", get_ccode_name (ssize_t_type)));
250 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
251 ccode.open_if (ccondarr);
253 ccode.add_declaration (get_ccode_name (ssize_t_type), new CCodeVariableDeclarator ("i"));
254 append_struct_array_free_loop (st);
258 CCodeFunctionCall carrfree;
259 if (context.profile == Profile.POSIX) {
260 cfile.add_include ("stdlib.h");
261 carrfree = new CCodeFunctionCall (new CCodeIdentifier ("free"));
263 carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
265 carrfree.add_argument (new CCodeIdentifier ("array"));
266 ccode.add_expression (carrfree);
270 cfile.add_function_declaration (fun);
271 cfile.add_function (fun);
276 public override string? append_struct_array_destroy (Struct st) {
277 string cname = "_vala_%s_array_destroy".printf (get_ccode_name (st));
279 if (cfile.add_declaration (cname)) {
283 generate_type_declaration (ssize_t_type, cfile);
285 var fun = new CCodeFunction (cname, "void");
286 fun.modifiers = CCodeModifiers.STATIC;
287 fun.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (st))));
288 fun.add_parameter (new CCodeParameter ("array_length", get_ccode_name (ssize_t_type)));
292 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
293 ccode.open_if (ccondarr);
295 ccode.add_declaration (get_ccode_name (ssize_t_type), new CCodeVariableDeclarator ("i"));
296 append_struct_array_free_loop (st);
302 cfile.add_function_declaration (fun);
303 cfile.add_function (fun);
308 void append_vala_array_free_loop () {
309 var cforinit = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0"));
310 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
311 var cforiter = new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1")));
312 ccode.open_for (cforinit, cforcond, cforiter);
314 var cptrarray = new CCodeCastExpression (new CCodeIdentifier ("array"), "%s*".printf (get_ccode_name (pointer_type)));
315 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
317 var cfreecond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL"));
318 ccode.open_if (cfreecond);
320 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier ("destroy_func"));
321 cfreecall.add_argument (cea);
322 ccode.add_expression (cfreecall);
327 public override void append_vala_array_free () {
328 // _vala_array_destroy only frees elements but not the array itself
329 generate_type_declaration (delegate_target_destroy_type, cfile);
330 generate_type_declaration (ssize_t_type, cfile);
332 var fun = new CCodeFunction ("_vala_array_destroy", "void");
333 fun.modifiers = CCodeModifiers.STATIC;
334 fun.add_parameter (new CCodeParameter ("array", get_ccode_name (pointer_type)));
335 fun.add_parameter (new CCodeParameter ("array_length", get_ccode_name (ssize_t_type)));
336 fun.add_parameter (new CCodeParameter ("destroy_func", get_ccode_name (delegate_target_destroy_type)));
340 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
341 var ccondfunc = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("destroy_func"), new CCodeConstant ("NULL"));
342 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccondarr, ccondfunc));
344 ccode.add_declaration (get_ccode_name (ssize_t_type), new CCodeVariableDeclarator ("i"));
345 append_vala_array_free_loop ();
351 cfile.add_function_declaration (fun);
352 cfile.add_function (fun);
354 // _vala_array_free frees elements and array
356 fun = new CCodeFunction ("_vala_array_free", "void");
357 fun.modifiers = CCodeModifiers.STATIC;
358 fun.add_parameter (new CCodeParameter ("array", get_ccode_name (pointer_type)));
359 fun.add_parameter (new CCodeParameter ("array_length", get_ccode_name (ssize_t_type)));
360 fun.add_parameter (new CCodeParameter ("destroy_func", get_ccode_name (delegate_target_destroy_type)));
364 // call _vala_array_destroy to free the array elements
365 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
366 ccall.add_argument (new CCodeIdentifier ("array"));
367 ccall.add_argument (new CCodeIdentifier ("array_length"));
368 ccall.add_argument (new CCodeIdentifier ("destroy_func"));
369 ccode.add_expression (ccall);
371 CCodeFunctionCall carrfree;
372 if (context.profile == Profile.POSIX) {
373 cfile.add_include ("stdlib.h");
374 carrfree = new CCodeFunctionCall (new CCodeIdentifier ("free"));
376 carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
378 carrfree.add_argument (new CCodeIdentifier ("array"));
379 ccode.add_expression (carrfree);
383 cfile.add_function_declaration (fun);
384 cfile.add_function (fun);
387 public override void append_vala_array_move () {
388 cfile.add_include ("string.h");
389 generate_type_declaration (ssize_t_type, cfile);
391 // assumes that overwritten array elements are null before invocation
392 // FIXME will leak memory if that's not the case
393 var fun = new CCodeFunction ("_vala_array_move", "void");
394 fun.modifiers = CCodeModifiers.STATIC;
395 fun.add_parameter (new CCodeParameter ("array", get_ccode_name (pointer_type)));
396 fun.add_parameter (new CCodeParameter ("element_size", get_ccode_name (size_t_type)));
397 fun.add_parameter (new CCodeParameter ("src", get_ccode_name (ssize_t_type)));
398 fun.add_parameter (new CCodeParameter ("dest", get_ccode_name (ssize_t_type)));
399 fun.add_parameter (new CCodeParameter ("length", get_ccode_name (ssize_t_type)));
403 var array = new CCodeCastExpression (new CCodeIdentifier ("array"), "char*");
404 var element_size = new CCodeIdentifier ("element_size");
405 var length = new CCodeIdentifier ("length");
406 var src = new CCodeIdentifier ("src");
407 var src_end = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, src, length);
408 var dest = new CCodeIdentifier ("dest");
409 var dest_end = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, dest, length);
410 var src_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, src, element_size));
411 var dest_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest, element_size));
412 var dest_end_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest_end, element_size));
414 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("memmove"));
415 ccall.add_argument (dest_address);
416 ccall.add_argument (src_address);
417 ccall.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
418 ccode.add_expression (ccall);
420 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest), new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, src_end, dest)));
422 var czero1 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
423 czero1.add_argument (src_address);
424 czero1.add_argument (new CCodeConstant ("0"));
425 czero1.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, dest, src), element_size));
426 ccode.add_expression (czero1);
428 ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, src, dest), new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest_end)));
430 var czero2 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
431 czero2.add_argument (dest_end_address);
432 czero2.add_argument (new CCodeConstant ("0"));
433 czero2.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, src, dest), element_size));
434 ccode.add_expression (czero2);
436 ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, src, dest));
438 var czero3 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
439 czero3.add_argument (src_address);
440 czero3.add_argument (new CCodeConstant ("0"));
441 czero3.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
442 ccode.add_expression (czero3);
448 cfile.add_function_declaration (fun);
449 cfile.add_function (fun);
452 public override void append_vala_array_length () {
453 generate_type_declaration (ssize_t_type, cfile);
455 var fun = new CCodeFunction ("_vala_array_length", get_ccode_name (ssize_t_type));
456 fun.modifiers = CCodeModifiers.STATIC;
457 fun.add_parameter (new CCodeParameter ("array", get_ccode_name (pointer_type)));
461 ccode.add_declaration (get_ccode_name (ssize_t_type), new CCodeVariableDeclarator ("length", new CCodeConstant ("0")));
463 // return 0 if the array is NULL
464 // avoids an extra NULL check on the caller side
465 var array_check = new CCodeIdentifier ("array");
466 ccode.open_if (array_check);
468 var array_element_check = new CCodeElementAccess (new CCodeCastExpression (new CCodeIdentifier ("array"), "%s*".printf (get_ccode_name (pointer_type))), new CCodeConstant ("length"));
469 ccode.open_while (array_element_check);
470 ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("length")));
475 ccode.add_return (new CCodeIdentifier ("length"));
479 cfile.add_function_declaration (fun);
480 cfile.add_function (fun);
483 public override TargetValue? copy_value (TargetValue value, CodeNode node) {
484 var type = value.value_type;
485 var cexpr = get_cvalue_ (value);
487 if (type is ArrayType) {
488 var array_type = (ArrayType) type;
490 if (!array_type.fixed_length) {
491 return base.copy_value (value, node);
494 var temp_value = create_temp_value (type, false, node);
496 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (generate_array_copy_wrapper (array_type)));
497 copy_call.add_argument (cexpr);
498 copy_call.add_argument (get_cvalue_ (temp_value));
499 ccode.add_expression (copy_call);
503 return base.copy_value (value, node);
507 public override CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup) {
508 if (type is ArrayType) {
509 var array_type = (ArrayType) type;
510 // fixed length arrays use different code
511 // generated by overridden get_ref_cexpression method
512 assert (!array_type.fixed_length);
513 return new CCodeIdentifier (generate_array_dup_wrapper (array_type));
515 return base.get_dup_func_expression (type, source_reference, is_chainup);
519 public override CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
520 unowned ArrayType? array_type = value.value_type as ArrayType;
522 if (array_type != null && array_type.fixed_length) {
523 unowned Struct? st = array_type.element_type.type_symbol as Struct;
524 if (st != null && !array_type.element_type.nullable) {
525 var ccall = new CCodeFunctionCall (new CCodeIdentifier (append_struct_array_destroy (st)));
526 ccall.add_argument (get_cvalue_ (value));
527 ccall.add_argument (get_ccodenode (array_type.length));
531 requires_array_free = true;
532 generate_type_declaration (delegate_target_destroy_type, cfile);
534 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
535 ccall.add_argument (get_cvalue_ (value));
536 ccall.add_argument (get_ccodenode (array_type.length));
537 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), get_ccode_name (delegate_target_destroy_type)));
541 return base.destroy_value (value, is_macro_definition);
545 string generate_array_dup_wrapper (ArrayType array_type) {
546 string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
548 if (!add_wrapper (dup_func)) {
549 // wrapper already defined
554 generate_type_declaration (ssize_t_type, cfile);
556 var function = new CCodeFunction (dup_func, get_ccode_name (array_type));
557 function.modifiers = CCodeModifiers.STATIC;
559 function.add_parameter (new CCodeParameter ("self", get_ccode_name (array_type)));
560 // total length over all dimensions
561 function.add_parameter (new CCodeParameter ("length", get_ccode_name (ssize_t_type)));
562 if (array_type.element_type is GenericType) {
563 // dup function array elements
564 function.add_parameter (new CCodeParameter (get_ccode_copy_function (((GenericType) array_type.element_type).type_parameter), "GBoxedCopyFunc"));
569 push_context (new EmitContext ());
570 push_function (function);
572 if (requires_copy (array_type.element_type)) {
573 var cvardecl = new CCodeVariableDeclarator ("result");
574 CCodeFunctionCall gnew;
575 if (context.profile == Profile.POSIX) {
576 cfile.add_include ("stdlib.h");
577 gnew = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
579 gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
580 gnew.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
583 CCodeExpression length_expr = new CCodeIdentifier ("length");
584 CCodeBinaryOperator length_check_op;
585 // add extra item to have array NULL-terminated for all reference types
586 if (array_type.element_type.type_symbol != null && array_type.element_type.type_symbol.is_reference_type ()) {
587 length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, length_expr, new CCodeConstant ("1"));
588 length_check_op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
590 length_check_op = CCodeBinaryOperator.GREATER_THAN;
592 gnew.add_argument (length_expr);
594 if (context.profile == Profile.POSIX) {
595 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
596 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
597 gnew.add_argument (csizeof);
600 // only attempt to dup if length >=/> 0, this deals with negative lengths and returns NULL
601 var length_check = new CCodeBinaryExpression (length_check_op, new CCodeIdentifier ("length"), new CCodeConstant ("0"));
602 ccode.open_if (length_check);
604 ccode.add_declaration (get_ccode_name (array_type), cvardecl);
605 ccode.add_assignment (new CCodeIdentifier ("result"), gnew);
607 ccode.add_declaration (get_ccode_name (ssize_t_type), new CCodeVariableDeclarator ("i"));
609 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
610 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")),
611 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
613 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("result"), new CCodeIdentifier ("i")), get_cvalue_ (copy_value (new GLibValue (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), true), array_type)));
616 ccode.add_return (new CCodeIdentifier ("result"));
619 ccode.add_return (new CCodeConstant ("NULL"));
621 // only dup if length > 0, this deals with negative lengths and returns NULL
622 var length_check = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("length"), new CCodeConstant ("0"));
623 ccode.open_if (length_check);
625 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
626 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
627 var length_expr = new CCodeIdentifier ("length");
629 if (context.profile == Profile.POSIX) {
630 cfile.add_include ("stdlib.h");
631 cfile.add_include ("string.h");
633 var alloc = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
634 alloc.add_argument (length_expr);
635 alloc.add_argument (sizeof_call);
637 var cvardecl = new CCodeVariableDeclarator ("result");
638 ccode.add_declaration (get_ccode_name (array_type), cvardecl);
639 ccode.add_assignment (new CCodeIdentifier ("result"), alloc);
641 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
642 dup_call.add_argument (new CCodeIdentifier ("result"));
643 dup_call.add_argument (new CCodeIdentifier ("self"));
644 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length_expr, sizeof_call));
645 ccode.add_expression (dup_call);
647 ccode.add_return (new CCodeIdentifier ("result"));
649 CCodeFunctionCall dup_call;
650 if (context.require_glib_version (2, 68)) {
651 dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup2"));
653 requires_memdup2 = true;
654 dup_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_memdup2"));
656 dup_call.add_argument (new CCodeIdentifier ("self"));
657 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length_expr, sizeof_call));
659 ccode.add_return (dup_call);
663 ccode.add_return (new CCodeConstant ("NULL"));
668 cfile.add_function_declaration (function);
669 cfile.add_function (function);
676 string generate_array_copy_wrapper (ArrayType array_type) {
677 string dup_func = "_vala_array_copy%d".printf (++next_array_dup_id);
679 if (!add_wrapper (dup_func)) {
680 // wrapper already defined
686 var function = new CCodeFunction (dup_func, "void");
687 function.modifiers = CCodeModifiers.STATIC;
689 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (array_type))));
690 function.add_parameter (new CCodeParameter ("dest", "%s *".printf (get_ccode_name (array_type))));
694 push_context (new EmitContext ());
695 push_function (function);
697 if (requires_copy (array_type.element_type)) {
698 ccode.add_declaration (get_ccode_name (array_type.length_type), new CCodeVariableDeclarator ("i"));
700 ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")),
701 new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), get_ccodenode (array_type.length)),
702 new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
705 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("dest"), new CCodeIdentifier ("i")), get_cvalue_ (copy_value (new GLibValue (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), true), array_type)));
707 cfile.add_include ("string.h");
709 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
710 dup_call.add_argument (new CCodeIdentifier ("dest"));
711 dup_call.add_argument (new CCodeIdentifier ("self"));
713 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
714 sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
715 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode (array_type.length), sizeof_call));
717 ccode.add_expression (dup_call);
722 cfile.add_function_declaration (function);
723 cfile.add_function (function);
730 string generate_array_add_wrapper (ArrayType array_type) {
731 string add_func = "_vala_array_add%d".printf (++next_array_add_id);
733 if (!add_wrapper (add_func)) {
734 // wrapper already defined
738 var function = new CCodeFunction (add_func, "void");
739 function.modifiers = CCodeModifiers.STATIC;
741 function.add_parameter (new CCodeParameter ("array", "%s *".printf (get_ccode_name (array_type))));
742 function.add_parameter (new CCodeParameter ("length", "%s*".printf (get_ccode_name (array_type.length_type))));
743 function.add_parameter (new CCodeParameter ("size", "%s*".printf (get_ccode_name (array_type.length_type))));
745 push_function (function);
747 string typename = get_ccode_name (array_type.element_type);
748 CCodeExpression value = new CCodeIdentifier ("value");
749 if (array_type.element_type.is_real_struct_type ()) {
750 if (!array_type.element_type.nullable || !array_type.element_type.value_owned) {
751 typename = "const " + typename;
753 if (!array_type.element_type.nullable) {
755 value = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, value);
758 function.add_parameter (new CCodeParameter ("value", typename));
760 var array = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("array"));
761 var length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("length"));
762 var size = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("size"));
764 CCodeFunctionCall renew_call;
765 if (context.profile == Profile.POSIX) {
766 cfile.add_include ("stdlib.h");
767 renew_call = new CCodeFunctionCall (new CCodeIdentifier ("realloc"));
768 renew_call.add_argument (array);
770 renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
771 renew_call.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
772 renew_call.add_argument (array);
774 CCodeExpression renew_call_size;
775 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
776 // NULL terminate array
777 renew_call_size = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, size, new CCodeConstant ("1"));
779 renew_call_size = size;
781 if (context.profile == Profile.POSIX) {
782 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
783 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
784 renew_call_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, size, csizeof);
786 renew_call.add_argument (renew_call_size);
788 var csizecheck = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, length, size);
789 ccode.open_if (csizecheck);
790 ccode.add_assignment (size, new CCodeConditionalExpression (size, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), size), new CCodeConstant ("4")));
791 ccode.add_assignment (array, renew_call);
794 ccode.add_assignment (new CCodeElementAccess (array, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, length)), value);
796 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
797 // NULL terminate array
798 ccode.add_assignment (new CCodeElementAccess (array, length), new CCodeConstant ("NULL"));
803 cfile.add_function_declaration (function);
804 cfile.add_function (function);
809 bool is_array_add (Assignment assignment) {
810 var binary = assignment.right as BinaryExpression;
811 if (binary != null && binary.left.value_type is ArrayType) {
812 if (binary.operator == BinaryOperator.PLUS) {
813 if (assignment.left.symbol_reference == binary.left.symbol_reference) {
822 public override void visit_assignment (Assignment assignment) {
823 if (!is_array_add (assignment)) {
824 base.visit_assignment (assignment);
828 var binary = (BinaryExpression) assignment.right;
830 var array = assignment.left;
831 var array_type = (ArrayType) array.value_type;
832 var element = binary.right;
834 var array_var = array.symbol_reference;
835 if (array_type.rank == 1 && array_var != null && array_var.is_internal_symbol ()
836 && (array_var is LocalVariable || array_var is Field)) {
839 Report.error (assignment.source_reference, "Array concatenation not supported for public array variables and parameters");
843 var value_param = new Parameter ("value", element.target_type);
845 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (array_type)));
846 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (array)));
847 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cexpression (array)));
848 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_size_cvalue (array.target_value)));
849 ccall.add_argument (handle_struct_argument (value_param, element, get_cvalue (element)));
851 ccode.add_expression (ccall);
854 public override CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
855 unowned ArrayType? array_type = param.variable_type as ArrayType;
856 if (array_type == null || param.params_array) {
857 return base.generate_parameter (param, decl_space, cparam_map, carg_map);
860 string? ctypename = get_ccode_type (param);
861 if (ctypename == null) {
862 ctypename = get_ccode_name (param.variable_type);
864 if (param.direction != ParameterDirection.IN) {
869 var main_cparam = new CCodeParameter.with_declarator (ctypename, new CCodeVariableDeclarator (get_ccode_name (param), null, get_ccode_declarator_suffix (array_type)));
871 generate_type_declaration (array_type.element_type, decl_space);
873 cparam_map.set (get_param_pos (get_ccode_pos (param)), main_cparam);
874 if (carg_map != null) {
875 carg_map.set (get_param_pos (get_ccode_pos (param)), get_parameter_cexpression (param));
878 if (!array_type.fixed_length && get_ccode_array_length (param)) {
879 var length_ctype = get_ccode_array_length_type (param);
880 if (param.direction != ParameterDirection.IN) {
881 length_ctype = "%s*".printf (length_ctype);
884 for (int dim = 1; dim <= array_type.rank; dim++) {
885 var cparam = new CCodeParameter (get_variable_array_length_cname (param, dim), length_ctype);
886 cparam_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), cparam);
887 if (carg_map != null) {
888 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), get_cexpression (cparam.name));
896 public override void append_params_array (Method m) {
897 var local = m.params_array_var;
898 var array_type = (ArrayType) local.variable_type;
900 var local_length = new LocalVariable (array_type.length_type.copy (), get_array_length_cname (local.name, 1), null, local.source_reference);
901 var local_size = new LocalVariable (array_type.length_type.copy (), get_array_size_cname (get_local_cname (local)));
903 CCodeFunctionCall gnew;
904 if (context.profile == Profile.POSIX) {
905 cfile.add_include ("stdlib.h");
906 gnew = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
908 gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
909 gnew.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
912 CCodeExpression length_expr = get_local_cexpression (local_length);
913 // add extra item to have array NULL-terminated for all reference types
914 if (array_type.element_type.type_symbol != null && array_type.element_type.type_symbol.is_reference_type ()) {
915 length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, length_expr, new CCodeConstant ("1"));
917 gnew.add_argument (length_expr);
918 if (context.profile == Profile.POSIX) {
919 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
920 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
921 gnew.add_argument (csizeof);
923 ccode.add_assignment (get_local_cexpression (local), gnew);
925 var element = new LocalVariable (array_type.element_type.copy (), "_%s_element".printf (get_ccode_name (local)), null, local.source_reference);
926 emit_temp_var (element);
928 if (context.profile == Profile.POSIX) {
929 cfile.add_include ("stdarg.h");
932 if (!(m is CreationMethod) || m.parent_symbol is Struct) {
933 ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_va_list_%s".printf (get_ccode_name (local))));
934 var vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
935 vastart.add_argument (new CCodeIdentifier ("_va_list_%s".printf (get_ccode_name (local))));
936 vastart.add_argument (new CCodeIdentifier ("_first_%s".printf (get_ccode_name (local))));
937 ccode.add_expression (vastart);
940 ccode.add_assignment (get_local_cexpression (element), new CCodeIdentifier ("_first_%s".printf (get_ccode_name (local))));
941 ccode.open_while (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_local_cexpression (element), new CCodeConstant ("NULL")));
943 var vaarg = new CCodeFunctionCall (new CCodeIdentifier ("va_arg"));
944 vaarg.add_argument (new CCodeIdentifier ("_va_list_%s".printf (get_ccode_name (local))));
945 vaarg.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
947 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (array_type)));
948 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_local_cexpression (local)));
949 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_local_cexpression (local_length)));
950 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_local_cexpression (local_size)));
951 ccall.add_argument (get_local_cexpression (element));
953 ccode.add_expression (ccall);
954 ccode.add_assignment (get_local_cexpression (element), vaarg);
958 var vaend = new CCodeFunctionCall (new CCodeIdentifier ("va_end"));
959 vaend.add_argument (new CCodeIdentifier ("_va_list_%s".printf (get_ccode_name (local))));
960 ccode.add_expression (vaend);