mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: add gen_map_equality_fn
to compare maps (#5770)
This commit is contained in:
parent
0c9c66dd6b
commit
bf14e666ea
@ -79,6 +79,7 @@ mut:
|
||||
str_types []string // types that need automatic str() generation
|
||||
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
|
||||
array_fn_definitions []string // array equality functions that have been defined
|
||||
map_fn_definitions []string // map equality functions that have been defined
|
||||
is_json_fn bool // inside json.encode()
|
||||
json_types []string // to avoid json gen duplicates
|
||||
pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name
|
||||
@ -1955,7 +1956,24 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||
} else if node.op == .ne {
|
||||
g.write('!${ptr_typ}_arr_eq(')
|
||||
}
|
||||
if node.left_type.is_ptr() {
|
||||
if node.left_type.is_ptr() {
|
||||
g.write('*')
|
||||
}
|
||||
g.expr(node.left)
|
||||
g.write(', ')
|
||||
if node.right_type.is_ptr() {
|
||||
g.write('*')
|
||||
}
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} else if node.op in [.eq, .ne] && left_sym.kind == .map && right_sym.kind == .map {
|
||||
ptr_typ := g.gen_map_equality_fn(left_type)
|
||||
if node.op == .eq {
|
||||
g.write('${ptr_typ}_map_eq(')
|
||||
} else if node.op == .ne {
|
||||
g.write('!${ptr_typ}_map_eq(')
|
||||
}
|
||||
if node.left_type.is_ptr() {
|
||||
g.write('*')
|
||||
}
|
||||
g.expr(node.left)
|
||||
@ -3029,6 +3047,41 @@ fn (mut g Gen) gen_array_equality_fn(left table.Type) string {
|
||||
return ptr_typ
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_map_equality_fn(left table.Type) string {
|
||||
left_sym := g.table.get_type_symbol(left)
|
||||
typ_name := g.typ(left)
|
||||
ptr_typ := typ_name[typ_name.index_after('_', 0) + 1..].trim('*')
|
||||
value_sym := g.table.get_type_symbol(left_sym.map_info().value_type)
|
||||
value_typ := g.typ(left_sym.map_info().value_type)
|
||||
if value_sym.kind == .map {
|
||||
// Recursively generate map element comparison function code if array element is map type
|
||||
g.gen_map_equality_fn(left_sym.map_info().value_type)
|
||||
}
|
||||
if ptr_typ in g.map_fn_definitions {
|
||||
return ptr_typ
|
||||
}
|
||||
g.map_fn_definitions << ptr_typ
|
||||
g.definitions.writeln('bool ${ptr_typ}_map_eq(map_$ptr_typ a, map_$ptr_typ b) {')
|
||||
g.definitions.writeln('\tif (a.len != b.len) {')
|
||||
g.definitions.writeln('\t\treturn false;')
|
||||
g.definitions.writeln('\t}')
|
||||
g.definitions.writeln('\tarray_string _keys = map_keys(&a);')
|
||||
g.definitions.writeln('\tfor (int i = 0; i < _keys.len; ++i) {')
|
||||
g.definitions.writeln('\t\tstring k = string_clone( ((string*)_keys.data)[i]);')
|
||||
g.definitions.writeln('\t\t$value_typ v = (*($value_typ*)map_get(a, k, &($value_typ[]){ 0 }));')
|
||||
if value_sym.kind == .string {
|
||||
g.definitions.writeln('\t\tif (!map_exists(b, k) || string_ne((*($value_typ*)map_get(b, k, &($value_typ[]){tos_lit("")})), v)) {')
|
||||
} else {
|
||||
g.definitions.writeln('\t\tif (!map_exists(b, k) || (*($value_typ*)map_get(b, k, &($value_typ[]){ 0 })) != v) {')
|
||||
}
|
||||
g.definitions.writeln('\t\t\treturn false;')
|
||||
g.definitions.writeln('\t\t}')
|
||||
g.definitions.writeln('\t}')
|
||||
g.definitions.writeln('\treturn true;')
|
||||
g.definitions.writeln('}')
|
||||
return ptr_typ
|
||||
}
|
||||
|
||||
fn verror(s string) {
|
||||
util.verror('cgen error', s)
|
||||
}
|
||||
|
18
vlib/v/tests/map_equality_test.v
Normal file
18
vlib/v/tests/map_equality_test.v
Normal file
@ -0,0 +1,18 @@
|
||||
fn test_map_equality() {
|
||||
a1 := {'a':1, 'b':2}
|
||||
b1 := {'b':2, 'a':1}
|
||||
c1 := {'a':2, 'b':1}
|
||||
|
||||
assert a1 == b1
|
||||
assert a1 != c1
|
||||
|
||||
a2 := {'a':1}
|
||||
b2 := {'a':1, 'b':2}
|
||||
|
||||
assert a2 != b2
|
||||
|
||||
a3 := {'a':'1', 'b':'2'}
|
||||
b3 := {'b':'2', 'a':'1'}
|
||||
|
||||
assert a3 == b3
|
||||
}
|
Loading…
Reference in New Issue
Block a user