v2 / vlib / v / gen / c / auto_eq_methods.v
724 lines · 661 sloc · 29.98 KB · ba60fc20382bc75dcb22e8e9db12bb32e45afc56
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
3module c
4
5import strings
6import v.ast
7
8fn (mut g Gen) equality_fn(typ ast.Type) string {
9 eq_key := g.eq_fn_key(typ)
10 g.needed_equality_fns << eq_key
11 st2 := g.styp(eq_key)
12 res := st2.replace('struct ', '')
13 return res
14}
15
16@[inline]
17fn string_eq_expr(left string, right string, is_ptr bool) string {
18 return if is_ptr {
19 '(${left} == ${right} || (${left} != 0 && ${right} != 0 && (((*${left}).len == (*${right}).len && (*${left}).len == 0) || builtin__fast_string_eq(*${left}, *${right}))))'
20 } else {
21 '(((${left}).len == (${right}).len && (${left}).len == 0) || builtin__fast_string_eq(${left}, ${right}))'
22 }
23}
24
25@[inline]
26fn (mut g Gen) eq_fn_key(typ ast.Type) ast.Type {
27 return g.unwrap_generic(typ).set_nr_muls(0)
28}
29
30fn (mut g Gen) gen_equality_fns() {
31 for needed_typ in g.needed_equality_fns {
32 eq_key := g.eq_fn_key(needed_typ)
33 if eq_key in g.generated_eq_fns {
34 continue
35 }
36 sym := g.table.sym(eq_key)
37 match sym.kind {
38 .sum_type {
39 g.gen_sumtype_equality_fn(eq_key)
40 }
41 .struct {
42 g.gen_struct_equality_fn(eq_key)
43 }
44 .array {
45 g.gen_array_equality_fn(eq_key)
46 }
47 .array_fixed {
48 g.gen_fixed_array_equality_fn(eq_key)
49 }
50 .map {
51 g.gen_map_equality_fn(eq_key)
52 }
53 .alias {
54 g.gen_alias_equality_fn(eq_key)
55 }
56 .interface {
57 g.gen_interface_equality_fn(eq_key)
58 }
59 else {
60 verror('could not generate equality function for type ${sym.kind}')
61 }
62 }
63 }
64}
65
66fn (mut g Gen) gen_sumtype_equality_fn(left_type ast.Type) string {
67 left := g.unwrap(left_type)
68 ptr_styp := g.styp(left.typ.set_nr_muls(0))
69
70 left_no_ptr := g.eq_fn_key(left_type)
71 if left_no_ptr in g.generated_eq_fns {
72 return ptr_styp
73 }
74 g.generated_eq_fns << left_no_ptr
75
76 info := left.sym.sumtype_info()
77 g.definitions.writeln('${g.static_non_parallel}bool ${ptr_styp}_sumtype_eq(${ptr_styp} a, ${ptr_styp} b);')
78
79 left_typ := g.read_field(left_type, '_typ', 'a')
80 right_typ := g.read_field(left_type, '_typ', 'b')
81
82 mut fn_builder := strings.new_builder(512)
83 fn_builder.writeln('${g.static_non_parallel}inline bool ${ptr_styp}_sumtype_eq(${ptr_styp} a, ${ptr_styp} b) {')
84 fn_builder.writeln('\tif (${left_typ} != ${right_typ}) { return false; }')
85 fn_builder.writeln('\tif (${left_typ} == ${right_typ} && ${right_typ} == 0) { return true; } // uninitialized')
86 for typ in info.variants {
87 variant := g.unwrap(typ)
88 fn_builder.writeln('\tif (${left_typ} == ${int(variant.typ)}) {')
89 name := '_${g.get_sumtype_variant_name(variant.typ, variant.sym)}'
90
91 left_arg := g.read_field(left_type, name, 'a')
92 right_arg := g.read_field(left_type, name, 'b')
93
94 if variant.typ.has_flag(.option) {
95 fn_builder.writeln('\t\treturn ((*${left_arg}).state == 2 && (*${right_arg}).state == 2) || !memcmp(&(*${left_arg}).data, &(*${right_arg}).data, sizeof(${g.base_type(variant.typ)}));')
96 } else if variant.sym.kind == .string {
97 fn_builder.writeln('\t\treturn builtin__string__eq(*${left_arg}, *${right_arg});')
98 } else if variant.sym.kind == .sum_type && !typ.is_ptr() {
99 eq_fn := g.gen_sumtype_equality_fn(typ)
100 fn_builder.writeln('\t\treturn ${eq_fn}_sumtype_eq(*${left_arg}, *${right_arg});')
101 } else if variant.sym.kind == .struct && !typ.is_ptr() {
102 eq_fn := g.gen_struct_equality_fn(typ)
103 fn_builder.writeln('\t\treturn ${eq_fn}_struct_eq(*${left_arg}, *${right_arg});')
104 } else if variant.sym.kind == .array && !typ.is_ptr() {
105 eq_fn := g.gen_array_equality_fn(typ)
106 fn_builder.writeln('\t\treturn ${eq_fn}_arr_eq(*${left_arg}, *${right_arg});')
107 } else if variant.sym.kind == .array_fixed && !typ.is_ptr() {
108 eq_fn := g.gen_fixed_array_equality_fn(typ)
109 fn_builder.writeln('\t\treturn ${eq_fn}_arr_eq(*${left_arg}, *${right_arg});')
110 } else if variant.sym.kind == .map && !typ.is_ptr() {
111 eq_fn := g.gen_map_equality_fn(typ)
112 fn_builder.writeln('\t\treturn ${eq_fn}_map_eq(*${left_arg}, *${right_arg});')
113 } else if variant.sym.kind == .alias && !typ.is_ptr() {
114 if g.no_eq_method_types[typ] {
115 fn_builder.writeln('\t\treturn *${left_arg} == *${right_arg};')
116 } else {
117 eq_fn := g.gen_alias_equality_fn(typ)
118 fn_builder.writeln('\t\treturn ${eq_fn}_alias_eq(*${left_arg}, *${right_arg});')
119 }
120 } else if variant.sym.kind == .function {
121 fn_builder.writeln('\t\treturn *((voidptr*)(*${left_arg})) == *((voidptr*)(*${right_arg}));')
122 } else {
123 fn_builder.writeln('\t\treturn *${left_arg} == *${right_arg};')
124 }
125 fn_builder.writeln('\t}')
126 }
127 fn_builder.writeln('\treturn false;')
128 fn_builder.writeln('}')
129 g.auto_fn_definitions << fn_builder.str()
130 return ptr_styp
131}
132
133// read_opt generates C code accessing option data
134@[inline]
135fn (mut g Gen) read_opt(typ ast.Type, var_name string) string {
136 return '(${g.base_type(typ)}*)${var_name}.data'
137}
138
139// read_field generates C code for reading option/no-option struct field
140@[inline]
141fn (mut g Gen) read_field(struct_type ast.Type, field_name string, var_name string) string {
142 return if struct_type.has_flag(.option) {
143 '(${g.read_opt(struct_type, var_name)})->${field_name}'
144 } else {
145 '${var_name}.${field_name}'
146 }
147}
148
149// read_map generates C code for reading option/no-option struct field
150@[inline]
151fn (mut g Gen) read_map_from_option(typ ast.Type, var_name string) string {
152 return if typ.has_flag(.option) {
153 return '(${g.base_type(typ)}*)&${var_name}.data'
154 } else {
155 var_name
156 }
157}
158
159// read_map_field generates C code for reading option/no-option struct field
160@[inline]
161fn (mut g Gen) read_map_field_from_option(typ ast.Type, field_name string, var_name string) string {
162 return if typ.has_flag(.option) {
163 '(*(${g.base_type(typ)}*)${var_name}.data).${field_name}'
164 } else {
165 '${var_name}.${field_name}'
166 }
167}
168
169// read_opt_field generates C code for reading option/no-option struct field
170@[inline]
171fn (mut g Gen) read_opt_field(struct_type ast.Type, field_name string, var_name string, field_typ ast.Type) string {
172 return if field_typ.has_flag(.option) {
173 '*(${g.base_type(field_typ)}*)${g.read_field(struct_type, field_name, var_name)}.data'
174 } else {
175 g.read_field(struct_type, field_name, var_name)
176 }
177}
178
179// read_map_opt_field generates C code for reading option/no-option map field
180@[inline]
181fn (mut g Gen) read_map_opt_field(struct_type ast.Type, field_name string, var_name string, field_typ ast.Type) string {
182 return if field_typ.has_flag(.option) {
183 '*(${g.base_type(field_typ)}*)${g.read_field(struct_type, field_name, var_name)}.data'
184 } else {
185 g.read_field(struct_type, field_name, var_name)
186 }
187}
188
189fn (mut g Gen) gen_struct_equality_fn(left_type ast.Type) string {
190 left := g.unwrap(left_type)
191 ptr_styp := g.styp(left.typ.set_nr_muls(0))
192 fn_name := ptr_styp.replace('struct ', '')
193
194 left_no_ptr := g.eq_fn_key(left_type)
195 if left_no_ptr in g.generated_eq_fns {
196 return fn_name
197 }
198 g.generated_eq_fns << left_no_ptr
199
200 info := left.sym.struct_info()
201 if left.sym.language == .c && info.fields.len == 0 {
202 g.definitions.writeln('#define ${fn_name}_struct_eq(a, b) (false)')
203 return fn_name
204 }
205 g.definitions.writeln('${g.static_non_parallel}bool ${fn_name}_struct_eq(${ptr_styp} a, ${ptr_styp} b);')
206
207 mut fn_builder := strings.new_builder(512)
208 defer {
209 g.auto_fn_definitions << fn_builder.str()
210 }
211 fn_builder.writeln('${g.static_non_parallel}inline bool ${fn_name}_struct_eq(${ptr_styp} a, ${ptr_styp} b) {')
212
213 // overloaded
214 if left.sym.has_method('==') {
215 if left.typ.has_flag(.option) {
216 opt_ptr_styp := g.styp(left.typ.set_nr_muls(0).clear_flag(.option))
217 opt_fn_name := opt_ptr_styp.replace('struct ', '')
218 fn_builder.writeln('\treturn (a.state == b.state && b.state == 2) || ${opt_fn_name}__eq(*(${opt_ptr_styp}*)a.data, *(${opt_ptr_styp}*)b.data);')
219 } else {
220 fn_builder.writeln('\treturn ${fn_name}__eq(a, b);')
221 }
222 fn_builder.writeln('}')
223 return fn_name
224 }
225
226 fn_builder.write_string('\treturn ')
227 if info.fields.len > 0 {
228 for i, field in info.fields {
229 if i > 0 {
230 fn_builder.write_string('\n\t\t&& ')
231 }
232 field_type := g.unwrap(field.typ)
233 field_name := c_name(field.name)
234
235 mut left_arg := g.read_field(left_type, field_name, 'a')
236 mut right_arg := g.read_field(left_type, field_name, 'b')
237
238 if field.typ.has_flag(.option) {
239 fn_builder.write_string('((${left_arg}.state == ${right_arg}.state && ${right_arg}.state == 2) || (${left_arg}.state != 2 && ${right_arg}.state != 2 && (')
240 }
241 if field_type.sym.kind == .string {
242 if field.typ.has_flag(.option) {
243 left_arg = g.read_opt_field(left_type, field_name, 'a', field.typ)
244 right_arg = g.read_opt_field(left_type, field_name, 'b', field.typ)
245 }
246
247 if field.typ.is_ptr() {
248 fn_builder.write_string('(${left_arg} == ${right_arg} || (${left_arg} != 0 && ${right_arg} != 0 && ((${left_arg})->len == (${right_arg})->len && (${left_arg})->len == 0) || builtin__fast_string_eq(*(${left_arg}), *(${right_arg}))))')
249 } else {
250 fn_builder.write_string('(((${left_arg}).len == (${right_arg}).len && (${left_arg}).len == 0) || builtin__fast_string_eq(${left_arg}, ${right_arg}))')
251 }
252 } else if field_type.sym.kind == .sum_type && !field.typ.is_ptr() {
253 eq_fn := g.gen_sumtype_equality_fn(field.typ)
254 fn_builder.write_string('${eq_fn}_sumtype_eq(${left_arg}, ${right_arg})')
255 } else if field_type.sym.kind == .struct && !field.typ.is_ptr() {
256 eq_fn := g.gen_struct_equality_fn(field.typ)
257 if field_type.sym.struct_info().is_anon && !field.typ.has_flag(.option)
258 && !field.typ.has_flag(.shared_f) {
259 styp := g.styp(field.typ)
260 fn_name_ := styp.replace('struct ', '')
261 fn_builder.write_string('${eq_fn}_struct_eq(*(${fn_name_}*)&(${left_arg}), *(${fn_name_}*)&(${right_arg}))')
262 } else {
263 fn_builder.write_string('${eq_fn}_struct_eq(${left_arg}, ${right_arg})')
264 }
265 } else if field_type.sym.kind == .array && !field.typ.is_ptr() {
266 eq_fn := g.gen_array_equality_fn(field.typ)
267 fn_builder.write_string('${eq_fn}_arr_eq(${left_arg}, ${right_arg})')
268 } else if field_type.sym.kind == .array_fixed && !field.typ.is_ptr() {
269 eq_fn := g.gen_fixed_array_equality_fn(field.typ)
270 fn_builder.write_string('${eq_fn}_arr_eq(${left_arg}, ${right_arg})')
271 } else if field_type.sym.kind == .map && !field.typ.is_ptr() {
272 eq_fn := g.gen_map_equality_fn(field.typ)
273 fn_builder.write_string('${eq_fn}_map_eq(${left_arg}, ${right_arg})')
274 } else if field_type.sym.kind == .alias && !field.typ.is_ptr() {
275 if g.no_eq_method_types[field.typ] {
276 fn_builder.write_string('${left_arg} == ${right_arg}')
277 } else {
278 eq_fn := g.gen_alias_equality_fn(field.typ)
279 fn_builder.write_string('${eq_fn}_alias_eq(${left_arg}, ${right_arg})')
280 }
281 } else if field_type.sym.kind == .function && !field.typ.has_flag(.option) {
282 fn_builder.write_string('((voidptr*)(${left_arg})) == ((voidptr*)(${right_arg}))')
283 } else if field_type.sym.kind == .interface
284 && (!field.typ.has_flag(.option) || !field.typ.is_ptr()) {
285 ptr := if field.typ.is_ptr() { '*'.repeat(field.typ.nr_muls()) } else { '' }
286 eq_fn := g.gen_interface_equality_fn(field.typ)
287 if ptr != '' {
288 fn_builder.write_string('((${left_arg} == (void*)0 && ${right_arg} == (void*)0) || (${left_arg} != (void*)0 && ${right_arg} != (void*)0 && ')
289 }
290 fn_builder.write_string('${eq_fn}_interface_eq(${ptr}${left_arg}, ${ptr}${right_arg})')
291 if ptr != '' {
292 fn_builder.write_string('))')
293 }
294 } else if field.typ.has_flag(.option) {
295 fn_builder.write_string('!memcmp(&${left_arg}.data, &${right_arg}.data, sizeof(${g.base_type(field.typ)}))')
296 } else {
297 fn_builder.write_string('${left_arg} == ${right_arg}')
298 }
299 if field.typ.has_flag(.option) {
300 fn_builder.write_string(')))')
301 }
302 }
303 } else {
304 fn_builder.write_string('true')
305 }
306 fn_builder.writeln(';')
307 fn_builder.writeln('}')
308 return fn_name
309}
310
311fn (mut g Gen) gen_alias_equality_fn(left_type ast.Type) string {
312 left := g.unwrap(left_type)
313 ptr_styp := g.styp(left.typ.set_nr_muls(0))
314
315 left_no_ptr := g.eq_fn_key(left_type)
316 if left_no_ptr in g.generated_eq_fns {
317 return ptr_styp
318 }
319 g.generated_eq_fns << left_no_ptr
320
321 info := left.sym.info as ast.Alias
322 g.definitions.writeln('${g.static_non_parallel}bool ${ptr_styp}_alias_eq(${ptr_styp} a, ${ptr_styp} b);')
323
324 mut fn_builder := strings.new_builder(512)
325 fn_builder.writeln('${g.static_non_parallel}inline bool ${ptr_styp}_alias_eq(${ptr_styp} a, ${ptr_styp} b) {')
326
327 is_option := left.typ.has_flag(.option)
328
329 mut left_var := if is_option { '*' + g.read_opt(info.parent_type, 'a') } else { 'a' }
330 mut right_var := if is_option { '*' + g.read_opt(info.parent_type, 'b') } else { 'b' }
331
332 sym := g.table.sym(info.parent_type)
333 if sym.kind == .string {
334 if info.parent_type.has_flag(.option) {
335 left_var = '*' + g.read_opt(info.parent_type, 'a')
336 right_var = '*' + g.read_opt(info.parent_type, 'b')
337 fn_builder.writeln('\treturn ((${left_var}).len == (${right_var}).len && (${left_var}).len == 0) || builtin__fast_string_eq(${left_var}, ${right_var});')
338 } else {
339 fn_builder.writeln('\treturn builtin__string__eq(a, b);')
340 }
341 } else if sym.kind == .sum_type && !left.typ.is_ptr() {
342 eq_fn := g.gen_sumtype_equality_fn(info.parent_type)
343 fn_builder.writeln('\treturn ${eq_fn}_sumtype_eq(${left_var}, ${right_var});')
344 } else if sym.kind == .struct && !left.typ.is_ptr() {
345 eq_fn := g.gen_struct_equality_fn(info.parent_type)
346 fn_builder.writeln('\treturn ${eq_fn}_struct_eq(${left_var}, ${right_var});')
347 } else if sym.kind == .interface && !left.typ.is_ptr() {
348 eq_fn := g.gen_interface_equality_fn(info.parent_type)
349 fn_builder.writeln('\treturn ${eq_fn}_interface_eq(${left_var}, ${right_var});')
350 } else if sym.kind == .array && !left.typ.is_ptr() {
351 eq_fn := g.gen_array_equality_fn(info.parent_type)
352 fn_builder.writeln('\treturn ${eq_fn}_arr_eq(${left_var}, ${right_var});')
353 } else if sym.kind == .array_fixed && !left.typ.is_ptr() {
354 eq_fn := g.gen_fixed_array_equality_fn(info.parent_type)
355 fn_builder.writeln('\treturn ${eq_fn}_arr_eq(${left_var}, ${right_var});')
356 } else if sym.kind == .map && !left.typ.is_ptr() {
357 eq_fn := g.gen_map_equality_fn(info.parent_type)
358 fn_builder.writeln('\treturn ${eq_fn}_map_eq(${left_var}, ${right_var});')
359 } else if sym.kind == .function && !left.typ.has_flag(.option) {
360 fn_builder.writeln('\treturn *((voidptr*)(a)) == *((voidptr*)(b));')
361 } else if info.parent_type.has_flag(.option) || left.typ.has_flag(.option) {
362 fn_builder.writeln('\treturn a.state == b.state && !memcmp(&a.data, &b.data, sizeof(${g.base_type(info.parent_type)}));')
363 } else {
364 fn_builder.writeln('\treturn a == b;')
365 }
366 fn_builder.writeln('}')
367 g.auto_fn_definitions << fn_builder.str()
368 return ptr_styp
369}
370
371fn (mut g Gen) gen_array_equality_fn(left_type ast.Type) string {
372 left := g.unwrap(left_type)
373 ptr_styp := g.styp(left.typ.set_nr_muls(0))
374
375 left_no_ptr := g.eq_fn_key(left_type)
376 if left_no_ptr in g.generated_eq_fns {
377 return ptr_styp
378 }
379 g.generated_eq_fns << left_no_ptr
380
381 elem := g.unwrap(left.sym.array_info().elem_type)
382 ptr_elem_styp := g.styp(elem.typ)
383 g.definitions.writeln('${g.static_non_parallel}bool ${ptr_styp}_arr_eq(${ptr_styp} a, ${ptr_styp} b);')
384
385 mut fn_builder := strings.new_builder(512)
386 fn_builder.writeln('${g.static_non_parallel}inline bool ${ptr_styp}_arr_eq(${ptr_styp} a, ${ptr_styp} b) {')
387
388 left_len := g.read_field(left_type, 'len', 'a')
389 right_len := g.read_field(left_type, 'len', 'b')
390
391 left_data := g.read_field(left_type, 'data', 'a')
392 right_data := g.read_field(left_type, 'data', 'b')
393
394 left_elem := g.read_field(left_type, 'element_size', 'a')
395 right_elem := g.read_field(left_type, 'element_size', 'b')
396
397 if left_type.has_flag(.option) {
398 fn_builder.writeln('\tif (a.state != b.state) return false;')
399 fn_builder.writeln('\tif (a.state == 2 && a.state == b.state) return true;')
400 }
401
402 fn_builder.writeln('\tif (${left_len} != ${right_len}) {')
403 fn_builder.writeln('\t\treturn false;')
404 fn_builder.writeln('\t}')
405 fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < ${left_len}; ++i) {')
406 // compare every pair of elements of the two arrays
407 if elem.sym.kind == .string {
408 left_arg := '*((${ptr_elem_styp}*)((byte*)${left_data}+(i*${left_elem})))'
409 right_arg := '*((${ptr_elem_styp}*)((byte*)${right_data}+(i*${right_elem})))'
410 fn_builder.writeln('\t\tif (!${string_eq_expr(left_arg, right_arg, elem.typ.is_ptr())}) {')
411 } else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() {
412 eq_fn := g.gen_sumtype_equality_fn(elem.typ)
413 fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
414 } else if elem.sym.kind == .struct && !elem.typ.is_ptr() {
415 eq_fn := g.gen_struct_equality_fn(elem.typ)
416 fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
417 } else if elem.sym.kind == .interface && !elem.typ.is_ptr() {
418 eq_fn := g.gen_interface_equality_fn(elem.typ)
419 fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
420 } else if elem.sym.kind == .array && !elem.typ.is_ptr() {
421 eq_fn := g.gen_array_equality_fn(elem.typ)
422 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
423 } else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() {
424 eq_fn := g.gen_fixed_array_equality_fn(elem.typ)
425 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
426 } else if elem.sym.kind == .map && !elem.typ.is_ptr() {
427 eq_fn := g.gen_map_equality_fn(elem.typ)
428 fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
429 } else if elem.sym.kind == .alias && !elem.typ.is_ptr() {
430 if g.no_eq_method_types[elem.typ] {
431 fn_builder.writeln('\t\tif (((${ptr_elem_styp}*)${left_data})[i] != ((${ptr_elem_styp}*)${right_data})[i]) {')
432 } else {
433 eq_fn := g.gen_alias_equality_fn(elem.typ)
434 fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(((${ptr_elem_styp}*)${left_data})[i], ((${ptr_elem_styp}*)${right_data})[i])) {')
435 }
436 } else if elem.sym.kind == .function {
437 fn_builder.writeln('\t\tif (*((voidptr*)((byte*)${left_data}+(i*${left_elem}))) != *((voidptr*)((byte*)${right_data}+(i*${right_elem})))) {')
438 } else {
439 if elem.typ.has_flag(.option) {
440 fn_builder.writeln('\t\t${ptr_elem_styp}* left = ((${ptr_elem_styp}*)${left_data})+(i*${left_elem});')
441 fn_builder.writeln('\t\t${ptr_elem_styp}* right = ((${ptr_elem_styp}*)${right_data})+(i*${right_elem});')
442 fn_builder.writeln('\t\tif (!(left->state == 2 && left->state == right->state) && memcmp(left->data, right->data, sizeof(${g.base_type(elem.typ)}))) {')
443 } else {
444 fn_builder.writeln('\t\tif (*((${ptr_elem_styp}*)((byte*)${left_data}+(i*${left_elem}))) != *((${ptr_elem_styp}*)((byte*)${right_data}+(i*${right_elem})))) {')
445 }
446 }
447 fn_builder.writeln('\t\t\treturn false;')
448 fn_builder.writeln('\t\t}')
449 fn_builder.writeln('\t}')
450 fn_builder.writeln('\treturn true;')
451 fn_builder.writeln('}')
452 g.auto_fn_definitions << fn_builder.str()
453 return ptr_styp
454}
455
456fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string {
457 left_typ := g.unwrap(left_type)
458 ptr_styp := g.styp(left_typ.typ.set_nr_muls(0))
459
460 left_no_ptr := g.eq_fn_key(left_type)
461 if left_no_ptr in g.generated_eq_fns {
462 return ptr_styp
463 }
464 g.generated_eq_fns << left_no_ptr
465
466 elem_info := left_typ.sym.array_fixed_info()
467 elem := g.unwrap(elem_info.elem_type)
468 ptr_elem_styp := g.styp(elem.typ)
469 size := elem_info.size
470 mut arg_styp := ptr_styp
471 if elem_info.is_fn_ret {
472 arg_styp = ptr_styp[3..] // removes the _v_ prefix for returning fixed array
473 }
474 g.definitions.writeln('${g.static_non_parallel}bool ${ptr_styp}_arr_eq(${arg_styp} a, ${arg_styp} b);')
475
476 is_option := left_type.has_flag(.option)
477 left_item := if is_option { '((${ptr_elem_styp}*)a.data)' } else { 'a' }
478 right_item := if is_option { '((${ptr_elem_styp}*)b.data)' } else { 'b' }
479
480 mut fn_builder := strings.new_builder(512)
481 fn_builder.writeln('${g.static_non_parallel}inline bool ${ptr_styp}_arr_eq(${arg_styp} a, ${arg_styp} b) {')
482 if is_option {
483 fn_builder.writeln('\tif (a.state != b.state) return false;')
484 fn_builder.writeln('\tif (a.state == 2 && a.state == b.state) return true;')
485 }
486 if left_typ.sym.is_primitive_fixed_array() {
487 suffix := if is_option { '.data' } else { '[0]' }
488 size_styp := if is_option {
489 g.base_type(left_typ.typ.set_nr_muls(0))
490 } else {
491 arg_styp
492 }
493 fn_builder.writeln('\tif (!memcmp(&a${suffix}, &b${suffix}, sizeof(${size_styp}))) {')
494 fn_builder.writeln('\t\treturn true;')
495 fn_builder.writeln('\t}')
496 }
497 fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < ${size}; ++i) {')
498 // compare every pair of elements of the two fixed arrays
499 if elem.sym.kind == .string {
500 left_arg := '${left_item}[i]'
501 right_arg := '${right_item}[i]'
502 fn_builder.writeln('\t\tif (!${string_eq_expr(left_arg, right_arg, elem.typ.is_ptr())}) {')
503 } else if elem.sym.kind == .sum_type && !elem.typ.is_ptr() {
504 eq_fn := g.gen_sumtype_equality_fn(elem.typ)
505 fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(${left_item}[i], ${right_item}[i])) {')
506 } else if elem.sym.kind == .struct && !elem.typ.is_ptr() {
507 eq_fn := g.gen_struct_equality_fn(elem.typ)
508 fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(${left_item}[i], ${right_item}[i])) {')
509 } else if elem.sym.kind == .interface && !elem.typ.is_ptr() {
510 eq_fn := g.gen_interface_equality_fn(elem.typ)
511 fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(${left_item}[i], ${right_item}[i])) {')
512 } else if elem.sym.kind == .array && !elem.typ.is_ptr() {
513 eq_fn := g.gen_array_equality_fn(elem.typ)
514 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(${left_item}[i], ${right_item}[i])) {')
515 } else if elem.sym.kind == .array_fixed && !elem.typ.is_ptr() {
516 eq_fn := g.gen_fixed_array_equality_fn(elem.typ)
517 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(${left_item}[i], ${right_item}[i])) {')
518 } else if elem.sym.kind == .map && !elem.typ.is_ptr() {
519 eq_fn := g.gen_map_equality_fn(elem.typ)
520 fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(${left_item}[i], ${right_item}[i])) {')
521 } else if elem.sym.kind == .alias && !elem.typ.is_ptr() {
522 eq_fn := g.gen_alias_equality_fn(elem.typ)
523 fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(${left_item}[i], ${right_item}[i])) {')
524 } else if elem.sym.kind == .function {
525 fn_builder.writeln('\t\tif (${left_item}[i] != ${right_item}[i]) {')
526 } else {
527 fn_builder.writeln('\t\tif (${left_item}[i] != ${right_item}[i]) {')
528 }
529 fn_builder.writeln('\t\t\treturn false;')
530 fn_builder.writeln('\t\t}')
531 fn_builder.writeln('\t}')
532 fn_builder.writeln('\treturn true;')
533 fn_builder.writeln('}')
534 g.auto_fn_definitions << fn_builder.str()
535 return ptr_styp
536}
537
538fn (mut g Gen) gen_map_equality_fn(left_type ast.Type) string {
539 left := g.unwrap(left_type)
540 ptr_styp := g.styp(left.typ.set_nr_muls(0))
541
542 left_no_ptr := g.eq_fn_key(left_type)
543 if left_no_ptr in g.generated_eq_fns {
544 return ptr_styp
545 }
546 g.generated_eq_fns << left_no_ptr
547
548 value := g.unwrap(left.sym.map_info().value_type)
549 ptr_value_styp := g.styp(value.typ)
550 g.definitions.writeln('${g.static_non_parallel}bool ${ptr_styp}_map_eq(${ptr_styp} a, ${ptr_styp} b);')
551
552 left_len := g.read_map_field_from_option(left.typ, 'len', 'a')
553 right_len := g.read_map_field_from_option(left.typ, 'len', 'b')
554 key_values := g.read_map_field_from_option(left.typ, 'key_values', 'a')
555
556 a := if left.typ.has_flag(.option) { g.read_map_from_option(left.typ, 'a') } else { '&a' }
557 b := if left.typ.has_flag(.option) { g.read_map_from_option(left.typ, 'b') } else { '&b' }
558
559 mut fn_builder := strings.new_builder(512)
560 fn_builder.writeln('${g.static_non_parallel}inline bool ${ptr_styp}_map_eq(${ptr_styp} a, ${ptr_styp} b) {')
561 fn_builder.writeln('\tif (${left_len} != ${right_len}) {')
562 fn_builder.writeln('\t\treturn false;')
563 fn_builder.writeln('\t}')
564 fn_builder.writeln('\tfor (${ast.int_type_name} i = 0; i < ${key_values}.len; ++i) {')
565 fn_builder.writeln('\t\tif (!builtin__DenseArray_has_index(&${key_values}, i)) continue;')
566 fn_builder.writeln('\t\tvoidptr k = builtin__DenseArray_key(&${key_values}, i);')
567 fn_builder.writeln('\t\tif (!builtin__map_exists(${b}, k)) return false;')
568 sym := g.table.sym(value.typ)
569 kind := g.table.type_kind(value.typ)
570 initializer := if !(sym.info is ast.Struct && sym.info.is_empty_struct()) { '0' } else { '' }
571 if kind == .function {
572 info := value.sym.info as ast.FnType
573 sig := g.fn_var_signature(ast.void_type, info.func.return_type,
574 info.func.params.map(it.typ), 'v')
575 fn_builder.writeln('\t\t${sig} = *(voidptr*)builtin__map_get(${a}, k, &(voidptr[]){ 0 });')
576 } else {
577 fn_builder.writeln('\t\t${ptr_value_styp} v = *(${ptr_value_styp}*)builtin__map_get(${a}, k, &(${ptr_value_styp}[]){ ${initializer} });')
578 }
579 match kind {
580 .string {
581 fn_builder.writeln('\t\tif (!builtin__fast_string_eq(*(string*)builtin__map_get(${b}, k, &(string[]){_S("")}), v)) {')
582 }
583 .sum_type {
584 eq_fn := g.gen_sumtype_equality_fn(value.typ)
585 fn_builder.writeln('\t\tif (!${eq_fn}_sumtype_eq(*(${ptr_value_styp}*)builtin__map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
586 }
587 .struct {
588 eq_fn := g.gen_struct_equality_fn(value.typ)
589 fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(*(${ptr_value_styp}*)builtin__map_get(${b}, k, &(${ptr_value_styp}[]){ ${initializer} }), v)) {')
590 }
591 .interface {
592 eq_fn := g.gen_interface_equality_fn(value.typ)
593 fn_builder.writeln('\t\tif (!${eq_fn}_interface_eq(*(${ptr_value_styp}*)builtin__map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
594 }
595 .array {
596 eq_fn := g.gen_array_equality_fn(value.typ)
597 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(*(${ptr_value_styp}*)builtin__map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
598 }
599 .array_fixed {
600 eq_fn := g.gen_fixed_array_equality_fn(value.typ)
601 fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(*(${ptr_value_styp}*)builtin__map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
602 }
603 .map {
604 eq_fn := g.gen_map_equality_fn(value.typ)
605 fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(*(${ptr_value_styp}*)builtin__map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
606 }
607 .alias {
608 eq_fn := g.gen_alias_equality_fn(value.typ)
609 fn_builder.writeln('\t\tif (!${eq_fn}_alias_eq(*(${ptr_value_styp}*)builtin__map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }), v)) {')
610 }
611 .function {
612 fn_builder.writeln('\t\tif (*(voidptr*)builtin__map_get(${b}, k, &(voidptr[]){ 0 }) != v) {')
613 }
614 else {
615 if value.typ.has_flag(.option) {
616 // For option types, use the unaliased type to get the correct sizeof
617 unaliased_typ := g.table.unaliased_type(value.typ)
618 fn_builder.writeln('\t\tif (memcmp(v.data, ((${ptr_value_styp}*)builtin__map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }))->data, sizeof(${g.base_type(unaliased_typ)})) != 0) {')
619 } else {
620 fn_builder.writeln('\t\tif (*(${ptr_value_styp}*)builtin__map_get(${b}, k, &(${ptr_value_styp}[]){ 0 }) != v) {')
621 }
622 }
623 }
624
625 fn_builder.writeln('\t\t\treturn false;')
626 fn_builder.writeln('\t\t}')
627 fn_builder.writeln('\t}')
628 fn_builder.writeln('\treturn true;')
629 fn_builder.writeln('}')
630 g.auto_fn_definitions << fn_builder.str()
631 return ptr_styp
632}
633
634fn (mut g Gen) gen_interface_equality_fn(left_type ast.Type) string {
635 left := g.unwrap(left_type)
636 ptr_styp := g.styp(left.typ.set_nr_muls(0))
637 idx_fn := g.styp(left.typ.set_nr_muls(0).clear_flag(.option))
638 fn_name := ptr_styp.replace('interface ', '')
639
640 left_no_ptr := g.eq_fn_key(left_type)
641 if left_no_ptr in g.generated_eq_fns {
642 return fn_name
643 }
644 g.generated_eq_fns << left_no_ptr
645
646 info := left.sym.info
647 g.definitions.writeln('${g.static_non_parallel}bool ${ptr_styp}_interface_eq(${ptr_styp} a, ${ptr_styp} b);')
648
649 mut fn_builder := strings.new_builder(512)
650 defer {
651 g.auto_fn_definitions << fn_builder.str()
652 }
653
654 left_arg := g.read_field(left_type, '_typ', 'a')
655 right_arg := g.read_field(left_type, '_typ', 'b')
656
657 fn_builder.writeln('${g.static_non_parallel}inline bool ${fn_name}_interface_eq(${ptr_styp} a, ${ptr_styp} b) {')
658 fn_builder.writeln('\tif (${left_arg} == ${right_arg}) {')
659 fn_builder.writeln('\t\tu32 idx = v_typeof_interface_idx_${idx_fn}(${left_arg});')
660 if info is ast.Interface {
661 for typ in info.types {
662 sym := g.table.sym(typ.set_nr_muls(0))
663 if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms {
664 continue
665 }
666 fn_builder.writeln('\t\tif (idx == ${typ.idx()}) {')
667 fn_builder.write_string('\t\t\treturn ')
668 match sym.kind {
669 .struct {
670 eq_fn := g.gen_struct_equality_fn(typ)
671 l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
672 r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
673 fn_builder.write_string('${eq_fn}_struct_eq(*(${l_eqfn}), *(${r_eqfn}))')
674 }
675 .string {
676 l_str := g.read_field(left_type, '_string', 'a')
677 r_str := g.read_field(left_type, '_string', 'b')
678 fn_builder.write_string('builtin__string__eq(*(${l_str}), *(${r_str}))')
679 }
680 .sum_type {
681 eq_fn := g.gen_sumtype_equality_fn(typ)
682 l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
683 r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
684 fn_builder.write_string('${eq_fn}_sumtype_eq(*(${l_eqfn}), *(${r_eqfn}))')
685 }
686 .array {
687 eq_fn := g.gen_array_equality_fn(typ)
688 l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
689 r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
690 fn_builder.write_string('${eq_fn}_arr_eq(*(${l_eqfn}), *(${r_eqfn}))')
691 }
692 .array_fixed {
693 eq_fn := g.gen_fixed_array_equality_fn(typ)
694 l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
695 r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
696 fn_builder.write_string('${eq_fn}_arr_eq(*(${l_eqfn}), *(${r_eqfn}))')
697 }
698 .map {
699 eq_fn := g.gen_map_equality_fn(typ)
700 l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
701 r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
702 fn_builder.write_string('${eq_fn}_map_eq(*(${l_eqfn}), *(${r_eqfn}))')
703 }
704 .alias {
705 eq_fn := g.gen_alias_equality_fn(typ)
706 l_eqfn := g.read_field(left_type, '_${eq_fn}', 'a')
707 r_eqfn := g.read_field(left_type, '_${eq_fn}', 'b')
708 fn_builder.write_string('${eq_fn}_alias_eq(*(${l_eqfn}), *(${r_eqfn}))')
709 }
710 else {
711 fn_builder.write_string('true')
712 }
713 }
714
715 fn_builder.writeln(';')
716 fn_builder.writeln('\t\t}')
717 }
718 }
719 fn_builder.writeln('\t}')
720 fn_builder.writeln('\treturn false;')
721 fn_builder.writeln('}')
722
723 return fn_name
724}
725