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 var gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
61 gnew
.add_argument (new
CCodeIdentifier (get_ccode_name (expr
.element_type
)));
64 CCodeExpression cexpr
= null;
66 // iterate over each dimension
67 foreach (Expression size
in expr
.get_sizes ()) {
68 CCodeExpression csize
= get_cvalue (size
);
69 append_array_length (expr
, csize
);
75 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cexpr
, csize
);
79 // add extra item to have array NULL-terminated for all reference types
80 if (expr
.element_type
.data_type
!= null && expr
.element_type
.data_type
.is_reference_type ()) {
81 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, cexpr
, new
CCodeConstant ("1"));
84 gnew
.add_argument (cexpr
);
86 var temp_var
= get_temp_variable (expr
.value_type
, true, expr
);
87 var name_cnode
= get_variable_cexpression (temp_var
.name
);
90 emit_temp_var (temp_var
);
92 ccode
.add_assignment (name_cnode
, gnew
);
94 if (expr
.initializer_list
!= null) {
95 append_initializer_list (name_cnode
, expr
.initializer_list
, expr
.rank
, ref i
);
98 set_cvalue (expr
, name_cnode
);
101 public override string get_array_length_cname (string array_cname
, int dim
) {
102 return "%s_length%d".printf (array_cname
, dim
);
105 public override string get_parameter_array_length_cname (Parameter param
, int dim
) {
106 if (get_ccode_array_length_name (param
) != null) {
107 return get_ccode_array_length_name (param
);
109 return get_array_length_cname (get_variable_cname (param
.name
), dim
);
113 public override CCodeExpression
get_array_length_cexpression (Expression array_expr
, int dim
= -1) {
114 return get_array_length_cvalue (array_expr
.target_value
, dim
);
117 public override CCodeExpression
get_array_length_cvalue (TargetValue value
, int dim
= -1) {
118 var array_type
= value
.value_type as ArrayType
;
120 if (array_type
!= null && array_type
.fixed_length
) {
121 return get_ccodenode (array_type
.length
);
124 // dim == -1 => total size over all dimensions
126 if (array_type
!= null && array_type
.rank
> 1) {
127 CCodeExpression cexpr
= get_array_length_cvalue (value
, 1);
128 for (dim
= 2; dim
<= array_type
.rank
; dim
++) {
129 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cexpr
, get_array_length_cvalue (value
, dim
));
137 List
<CCodeExpression
> size
= ((GLibValue
) value
).array_length_cvalues
;
138 assert (size
!= null && size
.size
>= dim
);
139 return size
[dim
- 1];
142 public override string get_array_size_cname (string array_cname
) {
143 return "_%s_size_".printf (array_cname
);
146 public override void visit_element_access (ElementAccess expr
) {
147 List
<Expression
> indices
= expr
.get_indices ();
148 int rank
= indices
.size
;
150 var ccontainer
= get_cvalue (expr
.container
);
151 var cindex
= get_cvalue (indices
[0]);
152 if (expr
.container
.symbol_reference is ArrayLengthField
) {
153 /* Figure if cindex is a constant expression and calculate dim...*/
154 var lit
= indices
[0] as IntegerLiteral
;
155 var memberaccess
= expr
.container as MemberAccess
;
156 if (lit
!= null && memberaccess
!= null) {
157 int dim
= int.parse (lit
.value
);
158 set_cvalue (expr
, get_array_length_cexpression (memberaccess
.inner
, dim
+ 1));
160 Report
.error (expr
.source_reference
, "only integer literals supported as index");
163 // access to element in an array
164 for (int i
= 1; i
< rank
; i
++) {
165 var cmul
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cindex
, get_array_length_cexpression (expr
.container
, i
+ 1));
166 cindex
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, cmul
, get_cvalue (indices
[i
]));
168 set_cvalue (expr
, new
CCodeElementAccess (ccontainer
, cindex
));
171 expr
.target_value
.value_type
= expr
.value_type
.copy ();
173 expr
.target_value
= store_temp_value (expr
.target_value
, expr
);
175 ((GLibValue
) expr
.target_value
).lvalue
= true;
178 public override void visit_slice_expression (SliceExpression expr
) {
179 var ccontainer
= get_cvalue (expr
.container
);
180 var cstart
= get_cvalue (expr
.start
);
181 var cstop
= get_cvalue (expr
.stop
);
183 var cstartpointer
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, ccontainer
, cstart
);
184 var splicelen
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, cstop
, cstart
);
186 set_cvalue (expr
, cstartpointer
);
187 append_array_length (expr
, splicelen
);
190 void append_struct_array_free_loop (Struct st
) {
191 var cforinit
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
192 var cforcond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("array_length"));
193 var cforiter
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("i"), new
CCodeConstant ("1")));
194 ccode
.open_for (cforinit
, cforcond
, cforiter
);
196 var cptrarray
= new
CCodeIdentifier ("array");
197 var cea
= new
CCodeElementAccess (cptrarray
, new
CCodeIdentifier ("i"));
199 var cfreecall
= new
CCodeFunctionCall (get_destroy_func_expression (new
StructValueType (st
)));
200 cfreecall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cea
));
201 ccode
.add_expression (cfreecall
);
206 public override string?
append_struct_array_free (Struct st
) {
207 string cname
= "_vala_%s_array_free".printf (get_ccode_name (st
));
209 if (cfile
.add_declaration (cname
)) {
213 var fun
= new
CCodeFunction (cname
, "void");
214 fun
.modifiers
= CCodeModifiers
.STATIC
;
215 fun
.add_parameter (new
CCodeParameter ("array", "%s *".printf (get_ccode_name (st
))));
216 fun
.add_parameter (new
CCodeParameter ("array_length", "gint"));
220 var ccondarr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("array"), new
CCodeConstant ("NULL"));
221 ccode
.open_if (ccondarr
);
223 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
224 append_struct_array_free_loop (st
);
228 var carrfree
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
229 carrfree
.add_argument (new
CCodeIdentifier ("array"));
230 ccode
.add_expression (carrfree
);
234 cfile
.add_function_declaration (fun
);
235 cfile
.add_function (fun
);
240 void append_vala_array_free_loop () {
241 var cforinit
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
242 var cforcond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("array_length"));
243 var cforiter
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("i"), new
CCodeConstant ("1")));
244 ccode
.open_for (cforinit
, cforcond
, cforiter
);
246 var cptrarray
= new
CCodeCastExpression (new
CCodeIdentifier ("array"), "gpointer*");
247 var cea
= new
CCodeElementAccess (cptrarray
, new
CCodeIdentifier ("i"));
249 var cfreecond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, cea
, new
CCodeConstant ("NULL"));
250 ccode
.open_if (cfreecond
);
252 var cfreecall
= new
CCodeFunctionCall (new
CCodeIdentifier ("destroy_func"));
253 cfreecall
.add_argument (cea
);
254 ccode
.add_expression (cfreecall
);
259 public override void append_vala_array_free () {
260 // _vala_array_destroy only frees elements but not the array itself
262 var fun
= new
CCodeFunction ("_vala_array_destroy", "void");
263 fun
.modifiers
= CCodeModifiers
.STATIC
;
264 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
265 fun
.add_parameter (new
CCodeParameter ("array_length", "gint"));
266 fun
.add_parameter (new
CCodeParameter ("destroy_func", "GDestroyNotify"));
270 var ccondarr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("array"), new
CCodeConstant ("NULL"));
271 var ccondfunc
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("destroy_func"), new
CCodeConstant ("NULL"));
272 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, ccondarr
, ccondfunc
));
274 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
275 append_vala_array_free_loop ();
281 cfile
.add_function_declaration (fun
);
282 cfile
.add_function (fun
);
284 // _vala_array_free frees elements and array
286 fun
= new
CCodeFunction ("_vala_array_free", "void");
287 fun
.modifiers
= CCodeModifiers
.STATIC
;
288 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
289 fun
.add_parameter (new
CCodeParameter ("array_length", "gint"));
290 fun
.add_parameter (new
CCodeParameter ("destroy_func", "GDestroyNotify"));
294 // call _vala_array_destroy to free the array elements
295 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
296 ccall
.add_argument (new
CCodeIdentifier ("array"));
297 ccall
.add_argument (new
CCodeIdentifier ("array_length"));
298 ccall
.add_argument (new
CCodeIdentifier ("destroy_func"));
299 ccode
.add_expression (ccall
);
301 var carrfree
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
302 carrfree
.add_argument (new
CCodeIdentifier ("array"));
303 ccode
.add_expression (carrfree
);
307 cfile
.add_function_declaration (fun
);
308 cfile
.add_function (fun
);
311 public override void append_vala_array_move () {
312 cfile
.add_include ("string.h");
314 // assumes that overwritten array elements are null before invocation
315 // FIXME will leak memory if that's not the case
316 var fun
= new
CCodeFunction ("_vala_array_move", "void");
317 fun
.modifiers
= CCodeModifiers
.STATIC
;
318 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
319 fun
.add_parameter (new
CCodeParameter ("element_size", "gsize"));
320 fun
.add_parameter (new
CCodeParameter ("src", "gint"));
321 fun
.add_parameter (new
CCodeParameter ("dest", "gint"));
322 fun
.add_parameter (new
CCodeParameter ("length", "gint"));
326 var array
= new
CCodeCastExpression (new
CCodeIdentifier ("array"), "char*");
327 var element_size
= new
CCodeIdentifier ("element_size");
328 var length
= new
CCodeIdentifier ("length");
329 var src
= new
CCodeIdentifier ("src");
330 var src_end
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, src
, length
);
331 var dest
= new
CCodeIdentifier ("dest");
332 var dest_end
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, dest
, length
);
333 var src_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, src
, element_size
));
334 var dest_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, dest
, element_size
));
335 var dest_end_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, dest_end
, element_size
));
337 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memmove"));
338 ccall
.add_argument (dest_address
);
339 ccall
.add_argument (src_address
);
340 ccall
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, length
, element_size
));
341 ccode
.add_expression (ccall
);
343 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, src
, dest
), new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, src_end
, dest
)));
345 var czero1
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
346 czero1
.add_argument (src_address
);
347 czero1
.add_argument (new
CCodeConstant ("0"));
348 czero1
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, dest
, src
), element_size
));
349 ccode
.add_expression (czero1
);
351 ccode
.else_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, src
, dest
), new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, src
, dest_end
)));
353 var czero2
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
354 czero2
.add_argument (dest_end_address
);
355 czero2
.add_argument (new
CCodeConstant ("0"));
356 czero2
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, src
, dest
), element_size
));
357 ccode
.add_expression (czero2
);
359 ccode
.else_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, src
, dest
));
361 var czero3
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
362 czero3
.add_argument (src_address
);
363 czero3
.add_argument (new
CCodeConstant ("0"));
364 czero3
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, length
, element_size
));
365 ccode
.add_expression (czero3
);
371 cfile
.add_function_declaration (fun
);
372 cfile
.add_function (fun
);
375 public override void append_vala_array_length () {
376 var fun
= new
CCodeFunction ("_vala_array_length", "gint");
377 fun
.modifiers
= CCodeModifiers
.STATIC
;
378 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
382 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("length", new
CCodeConstant ("0")));
384 // return 0 if the array is NULL
385 // avoids an extra NULL check on the caller side
386 var array_check
= new
CCodeIdentifier ("array");
387 ccode
.open_if (array_check
);
389 var array_element_check
= new
CCodeElementAccess (new
CCodeCastExpression (new
CCodeIdentifier ("array"), "gpointer*"), new
CCodeConstant ("length"));
390 ccode
.open_while (array_element_check
);
391 ccode
.add_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("length")));
396 ccode
.add_return (new
CCodeIdentifier ("length"));
400 cfile
.add_function_declaration (fun
);
401 cfile
.add_function (fun
);
404 public override TargetValue?
copy_value (TargetValue value
, CodeNode node
) {
405 var type
= value
.value_type
;
406 var cexpr
= get_cvalue_ (value
);
408 if (type is ArrayType
) {
409 var array_type
= (ArrayType
) type
;
411 if (!array_type
.fixed_length
) {
412 return base.copy_value (value
, node
);
415 var temp_value
= create_temp_value (type
, false, node
);
417 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_copy_wrapper (array_type
)));
418 copy_call
.add_argument (cexpr
);
419 copy_call
.add_argument (get_cvalue_ (temp_value
));
420 ccode
.add_expression (copy_call
);
424 return base.copy_value (value
, node
);
428 public override CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
) {
429 if (type is ArrayType
) {
430 var array_type
= (ArrayType
) type
;
431 // fixed length arrays use different code
432 // generated by overridden get_ref_cexpression method
433 assert (!array_type
.fixed_length
);
434 return new
CCodeIdentifier (generate_array_dup_wrapper (array_type
));
436 return base.get_dup_func_expression (type
, source_reference
, is_chainup
);
440 public override CCodeExpression
destroy_value (TargetValue value
, bool is_macro_definition
= false) {
441 var type
= value
.value_type
;
443 if (type is ArrayType
) {
444 var array_type
= (ArrayType
) type
;
446 if (!array_type
.fixed_length
) {
447 return base.destroy_value (value
, is_macro_definition
);
450 requires_array_free
= true;
452 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
454 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
455 ccall
.add_argument (get_cvalue_ (value
));
456 ccall
.add_argument (get_ccodenode (array_type
.length
));
457 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
461 return base.destroy_value (value
, is_macro_definition
);
465 string generate_array_dup_wrapper (ArrayType array_type
) {
466 string dup_func
= "_vala_array_dup%d".printf (++next_array_dup_id
);
468 if (!add_wrapper (dup_func
)) {
469 // wrapper already defined
475 var function
= new
CCodeFunction (dup_func
, get_ccode_name (array_type
));
476 function
.modifiers
= CCodeModifiers
.STATIC
;
478 function
.add_parameter (new
CCodeParameter ("self", get_ccode_name (array_type
)));
479 // total length over all dimensions
480 function
.add_parameter (new
CCodeParameter ("length", "int"));
481 if (array_type
.element_type is GenericType
) {
482 // dup function array elements
483 string func_name
= "%s_dup_func".printf (array_type
.element_type
.type_parameter
.name
.down ());
484 function
.add_parameter (new
CCodeParameter (func_name
, "GBoxedCopyFunc"));
489 push_context (new
EmitContext ());
490 push_function (function
);
492 if (requires_copy (array_type
.element_type
)) {
493 var cvardecl
= new
CCodeVariableDeclarator ("result");
494 var gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
495 gnew
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
497 CCodeExpression length_expr
= new
CCodeIdentifier ("length");
498 // add extra item to have array NULL-terminated for all reference types
499 if (array_type
.element_type
.data_type
!= null && array_type
.element_type
.data_type
.is_reference_type ()) {
500 length_expr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, length_expr
, new
CCodeConstant ("1"));
502 gnew
.add_argument (length_expr
);
504 ccode
.add_declaration (get_ccode_name (array_type
), cvardecl
);
505 ccode
.add_assignment (new
CCodeIdentifier ("result"), gnew
);
507 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
509 ccode
.open_for (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")),
510 new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("length")),
511 new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
513 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
)));
516 ccode
.add_return (new
CCodeIdentifier ("result"));
518 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memdup"));
519 dup_call
.add_argument (new
CCodeIdentifier ("self"));
521 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
522 sizeof_call
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
523 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeIdentifier ("length"), sizeof_call
));
525 ccode
.add_return (dup_call
);
530 cfile
.add_function_declaration (function
);
531 cfile
.add_function (function
);
538 string generate_array_copy_wrapper (ArrayType array_type
) {
539 string dup_func
= "_vala_array_copy%d".printf (++next_array_dup_id
);
541 if (!add_wrapper (dup_func
)) {
542 // wrapper already defined
548 var function
= new
CCodeFunction (dup_func
, "void");
549 function
.modifiers
= CCodeModifiers
.STATIC
;
551 function
.add_parameter (new
CCodeParameter ("self", "%s *".printf (get_ccode_name (array_type
))));
552 function
.add_parameter (new
CCodeParameter ("dest", "%s *".printf (get_ccode_name (array_type
))));
556 push_context (new
EmitContext ());
557 push_function (function
);
559 if (requires_copy (array_type
.element_type
)) {
560 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
562 ccode
.open_for (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")),
563 new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), get_ccodenode (array_type
.length
)),
564 new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
567 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
)));
569 cfile
.add_include ("string.h");
571 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
572 dup_call
.add_argument (new
CCodeIdentifier ("dest"));
573 dup_call
.add_argument (new
CCodeIdentifier ("self"));
575 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
576 sizeof_call
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
577 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, get_ccodenode (array_type
.length
), sizeof_call
));
579 ccode
.add_expression (dup_call
);
584 cfile
.add_function_declaration (function
);
585 cfile
.add_function (function
);
592 string generate_array_add_wrapper (ArrayType array_type
) {
593 string add_func
= "_vala_array_add%d".printf (++next_array_add_id
);
595 if (!add_wrapper (add_func
)) {
596 // wrapper already defined
600 var function
= new
CCodeFunction (add_func
, "void");
601 function
.modifiers
= CCodeModifiers
.STATIC
;
603 function
.add_parameter (new
CCodeParameter ("array", "%s *".printf (get_ccode_name (array_type
))));
604 function
.add_parameter (new
CCodeParameter ("length", "int*"));
605 function
.add_parameter (new
CCodeParameter ("size", "int*"));
607 push_function (function
);
609 string typename
= get_ccode_name (array_type
.element_type
);
610 CCodeExpression value
= new
CCodeIdentifier ("value");
611 if (array_type
.element_type
.is_real_struct_type ()) {
612 if (!array_type
.element_type
.nullable
|| !array_type
.element_type
.value_owned
) {
613 typename
= "const " + typename
;
615 if (!array_type
.element_type
.nullable
) {
617 value
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, value
);
620 function
.add_parameter (new
CCodeParameter ("value", typename
));
622 var array
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("array"));
623 var length
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("length"));
624 var size
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("size"));
626 var renew_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_renew"));
627 renew_call
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
628 renew_call
.add_argument (array
);
629 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
630 // NULL terminate array
631 renew_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, size
, new
CCodeConstant ("1")));
633 renew_call
.add_argument (size
);
636 var csizecheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, length
, size
);
637 ccode
.open_if (csizecheck
);
638 ccode
.add_assignment (size
, new
CCodeConditionalExpression (size
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("2"), size
), new
CCodeConstant ("4")));
639 ccode
.add_assignment (array
, renew_call
);
642 ccode
.add_assignment (new
CCodeElementAccess (array
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, length
)), value
);
644 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
645 // NULL terminate array
646 ccode
.add_assignment (new
CCodeElementAccess (array
, length
), new
CCodeConstant ("NULL"));
651 cfile
.add_function_declaration (function
);
652 cfile
.add_function (function
);
657 bool is_array_add (Assignment assignment
) {
658 var binary
= assignment
.right as BinaryExpression
;
659 if (binary
!= null && binary
.left
.value_type is ArrayType
) {
660 if (binary
.operator
== BinaryOperator
.PLUS
) {
661 if (assignment
.left
.symbol_reference
== binary
.left
.symbol_reference
) {
670 public override void visit_assignment (Assignment assignment
) {
671 if (!is_array_add (assignment
)) {
672 base.visit_assignment (assignment
);
676 var binary
= (BinaryExpression
) assignment
.right
;
678 var array
= assignment
.left
;
679 var array_type
= (ArrayType
) array
.value_type
;
680 var element
= binary
.right
;
682 var array_var
= array
.symbol_reference
;
683 if (array_type
.rank
== 1 && array_var
!= null && array_var
.is_internal_symbol ()
684 && (array_var is LocalVariable
|| array_var is Field
)) {
687 Report
.error (assignment
.source_reference
, "Array concatenation not supported for public array variables and parameters");
691 var value_param
= new
Parameter ("value", element
.target_type
);
693 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_add_wrapper (array_type
)));
694 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (array
)));
695 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cexpression (array
)));
696 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_size_cvalue (array
.target_value
)));
697 ccall
.add_argument (handle_struct_argument (value_param
, element
, get_cvalue (element
)));
699 ccode
.add_expression (ccall
);
702 public override CCodeParameter
generate_parameter (Parameter param
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
703 if (!(param
.variable_type is ArrayType
)) {
704 return base.generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
707 string ctypename
= get_ccode_name (param
.variable_type
);
709 if (param
.direction
!= ParameterDirection
.IN
) {
713 var main_cparam
= new
CCodeParameter (get_variable_cname (param
.name
), ctypename
);
715 var array_type
= (ArrayType
) param
.variable_type
;
717 generate_type_declaration (array_type
.element_type
, decl_space
);
719 cparam_map
.set (get_param_pos (get_ccode_pos (param
)), main_cparam
);
720 if (carg_map
!= null) {
721 carg_map
.set (get_param_pos (get_ccode_pos (param
)), get_variable_cexpression (param
.name
));
724 if (get_ccode_array_length (param
)) {
725 string length_ctype
= "int";
726 if (get_ccode_array_length_type (param
) != null) {
727 length_ctype
= get_ccode_array_length_type (param
);
729 if (param
.direction
!= ParameterDirection
.IN
) {
730 length_ctype
= "%s*".printf (length_ctype
);
733 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
734 var cparam
= new
CCodeParameter (get_parameter_array_length_cname (param
, dim
), length_ctype
);
735 cparam_map
.set (get_param_pos (get_ccode_array_length_pos (param
) + 0.01 * dim
), cparam
);
736 if (carg_map
!= null) {
737 carg_map
.set (get_param_pos (get_ccode_array_length_pos (param
) + 0.01 * dim
), get_variable_cexpression (cparam
.name
));