cgen: add gen_fixed_array_equality_fn (#8006)

pull/8056/head
yuyi 2021-01-12 08:35:18 +08:00 committed by GitHub
parent 55e3e50b9b
commit 1559e72d0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 104 additions and 17 deletions

View File

@ -10,3 +10,37 @@ fn test_eq() {
assert [{'bob': 22}, {'tom': 33}] == [{'bob': 22}, {'tom': 33}] assert [{'bob': 22}, {'tom': 33}] == [{'bob': 22}, {'tom': 33}]
assert [[1, 2, 3], [4]] == [[1, 2, 3], [4]] assert [[1, 2, 3], [4]] == [[1, 2, 3], [4]]
} }
fn test_fixed_array_eq() {
a1 := [1, 2, 3]!!
assert a1 == [1, 2, 3]!!
assert a1 != [2, 3, 4]!!
a2 := [[1, 2]!!, [3, 4]!!]!!
assert a2 == [[1, 2]!!, [3, 4]!!]!!
assert a2 != [[3, 4]!!, [1, 2]!!]!!
a3 := [[1, 2], [3, 4]]!!
assert a3 == [[1, 2], [3, 4]]!!
assert a3 != [[1, 1], [2, 2]]!!
a4 := [[`a`, `b`], [`c`, `d`]]!!
assert a4 == [[`a`, `b`], [`c`, `d`]]!!
assert a4 != [[`c`, `a`], [`a`, `b`]]!!
a5 := [['aaa', 'bbb'], ['ccc', 'ddd']]!!
assert a5 == [['aaa', 'bbb'], ['ccc', 'ddd']]!!
assert a5 != [['abc', 'def'], ['ccc', 'ddd']]!!
a6 := [['aaa', 'bbb']!!, ['ccc', 'ddd']!!]!!
assert a6 == [['aaa', 'bbb']!!, ['ccc', 'ddd']!!]!!
assert a6 != [['aaa', 'bbb']!!, ['aaa', 'ddd']!!]!!
a7 := [[1, 2]!!, [3, 4]!!]
assert a7 == [[1, 2]!!, [3, 4]!!]
assert a7 != [[2, 3]!!, [1, 2]!!]
a8 := [['aaa', 'bbb']!!, ['ccc', 'ddd']!!]
assert a8 == [['aaa', 'bbb']!!, ['ccc', 'ddd']!!]
assert a8 != [['bbb', 'aaa']!!, ['cccc', 'dddd']!!]
}

View File

@ -26,6 +26,9 @@ fn (mut g Gen) gen_struct_equality_fn(left table.Type) string {
} else if sym.kind == .array && !field.typ.is_ptr() { } else if sym.kind == .array && !field.typ.is_ptr() {
eq_fn := g.gen_array_equality_fn(field.typ) eq_fn := g.gen_array_equality_fn(field.typ)
fn_builder.writeln('\tif (!${eq_fn}_arr_eq(a.$field.name, b.$field.name)) {') fn_builder.writeln('\tif (!${eq_fn}_arr_eq(a.$field.name, b.$field.name)) {')
} else if sym.kind == .array_fixed && !field.typ.is_ptr() {
eq_fn := g.gen_fixed_array_equality_fn(field.typ)
fn_builder.writeln('\tif (!${eq_fn}_arr_eq(a.$field.name, b.$field.name)) {')
} else if sym.kind == .map && !field.typ.is_ptr() { } else if sym.kind == .map && !field.typ.is_ptr() {
eq_fn := g.gen_map_equality_fn(field.typ) eq_fn := g.gen_map_equality_fn(field.typ)
fn_builder.writeln('\tif (!${eq_fn}_map_eq(a.$field.name, b.$field.name)) {') fn_builder.writeln('\tif (!${eq_fn}_map_eq(a.$field.name, b.$field.name)) {')
@ -69,6 +72,9 @@ fn (mut g Gen) gen_array_equality_fn(left table.Type) string {
} else if elem_sym.kind == .array && !elem_typ.is_ptr() { } else if elem_sym.kind == .array && !elem_typ.is_ptr() {
eq_fn := g.gen_array_equality_fn(elem_typ) eq_fn := g.gen_array_equality_fn(elem_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq((($ptr_elem_typ*)a.data)[i], (($ptr_elem_typ*)b.data)[i])) {') fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq((($ptr_elem_typ*)a.data)[i], (($ptr_elem_typ*)b.data)[i])) {')
} else if elem_sym.kind == .array_fixed && !elem_typ.is_ptr() {
eq_fn := g.gen_fixed_array_equality_fn(elem_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq((($ptr_elem_typ*)a.data)[i], (($ptr_elem_typ*)b.data)[i])) {')
} else if elem_sym.kind == .map && !elem_typ.is_ptr() { } else if elem_sym.kind == .map && !elem_typ.is_ptr() {
eq_fn := g.gen_map_equality_fn(elem_typ) eq_fn := g.gen_map_equality_fn(elem_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq((($ptr_elem_typ*)a.data)[i], (($ptr_elem_typ*)b.data)[i])) {') fn_builder.writeln('\t\tif (!${eq_fn}_map_eq((($ptr_elem_typ*)a.data)[i], (($ptr_elem_typ*)b.data)[i])) {')
@ -86,6 +92,50 @@ fn (mut g Gen) gen_array_equality_fn(left table.Type) string {
return ptr_typ return ptr_typ
} }
fn (mut g Gen) gen_fixed_array_equality_fn(left table.Type) string {
ptr_typ := g.typ(left).trim('*')
if ptr_typ in g.array_fn_definitions {
return ptr_typ
}
g.array_fn_definitions << ptr_typ
left_sym := g.table.get_type_symbol(left)
elem_info := left_sym.array_fixed_info()
elem_typ := elem_info.elem_type
size := elem_info.size
elem_sym := g.table.get_type_symbol(elem_typ)
g.type_definitions.writeln('static bool ${ptr_typ}_arr_eq($ptr_typ a, $ptr_typ b); // auto')
mut fn_builder := strings.new_builder(512)
fn_builder.writeln('static bool ${ptr_typ}_arr_eq($ptr_typ a, $ptr_typ b) {')
fn_builder.writeln('\tfor (int i = 0; i < $size; ++i) {')
// compare every pair of elements of the two fixed arrays
if elem_sym.kind == .string {
fn_builder.writeln('\t\tif (string_ne(a[i], b[i])) {')
} else if elem_sym.kind == .struct_ && !elem_typ.is_ptr() {
eq_fn := g.gen_struct_equality_fn(elem_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_struct_eq(a[i], b[i])) {')
} else if elem_sym.kind == .array && !elem_typ.is_ptr() {
eq_fn := g.gen_array_equality_fn(elem_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a[i], b[i])) {')
} else if elem_sym.kind == .array_fixed && !elem_typ.is_ptr() {
eq_fn := g.gen_fixed_array_equality_fn(elem_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(a[i], b[i])) {')
} else if elem_sym.kind == .map && !elem_typ.is_ptr() {
eq_fn := g.gen_map_equality_fn(elem_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(a[i], b[i])) {')
} else if elem_sym.kind == .function {
fn_builder.writeln('\t\tif (a[i] != b[i]) {')
} else {
fn_builder.writeln('\t\tif (a[i] != b[i]) {')
}
fn_builder.writeln('\t\t\treturn false;')
fn_builder.writeln('\t\t}')
fn_builder.writeln('\t}')
fn_builder.writeln('\treturn true;')
fn_builder.writeln('}')
g.auto_fn_definitions << fn_builder.str()
return ptr_typ
}
fn (mut g Gen) gen_map_equality_fn(left table.Type) string { fn (mut g Gen) gen_map_equality_fn(left table.Type) string {
ptr_typ := g.typ(left).trim('*') ptr_typ := g.typ(left).trim('*')
if ptr_typ in g.map_fn_definitions { if ptr_typ in g.map_fn_definitions {
@ -135,6 +185,10 @@ fn (mut g Gen) gen_map_equality_fn(left table.Type) string {
eq_fn := g.gen_array_equality_fn(value_typ) eq_fn := g.gen_array_equality_fn(value_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(*($ptr_value_typ*)map_get_1(&b, k, &($ptr_value_typ[]){ 0 }), v)) {') fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(*($ptr_value_typ*)map_get_1(&b, k, &($ptr_value_typ[]){ 0 }), v)) {')
} }
.array_fixed {
eq_fn := g.gen_fixed_array_equality_fn(value_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_arr_eq(*($ptr_value_typ*)map_get_1(&b, k, &($ptr_value_typ[]){ 0 }), v)) {')
}
.map { .map {
eq_fn := g.gen_map_equality_fn(value_typ) eq_fn := g.gen_map_equality_fn(value_typ)
fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(*($ptr_value_typ*)map_get_1(&b, k, &($ptr_value_typ[]){ 0 }), v)) {') fn_builder.writeln('\t\tif (!${eq_fn}_map_eq(*($ptr_value_typ*)map_get_1(&b, k, &($ptr_value_typ[]){ 0 }), v)) {')

View File

@ -204,7 +204,12 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
if sym.kind == .function { if sym.kind == .function {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();') g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();')
} else { } else {
g.auto_str_funcs.writeln('\t\t$field_styp it = (*($field_styp*)array_get(a, i));') if sym.kind == .array_fixed {
g.auto_str_funcs.writeln('\t\t$field_styp it;')
g.auto_str_funcs.writeln('\t\tmemcpy(*($field_styp*)it, (byte*)array_get(a, i), sizeof($field_styp));')
} else {
g.auto_str_funcs.writeln('\t\t$field_styp it = *($field_styp*)array_get(a, i);')
}
if sym.kind == .struct_ && !sym_has_str_method { if sym.kind == .struct_ && !sym_has_str_method {
if is_elem_ptr { if is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(*it, indent_count);') g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(*it, indent_count);')

View File

@ -3011,11 +3011,10 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
} }
} else if node.op in [.eq, .ne] && left_sym.kind == .array && right_sym.kind == .array { } else if node.op in [.eq, .ne] && left_sym.kind == .array && right_sym.kind == .array {
ptr_typ := g.gen_array_equality_fn(left_type) ptr_typ := g.gen_array_equality_fn(left_type)
if node.op == .eq { if node.op == .ne {
g.write('${ptr_typ}_arr_eq(') g.write('!')
} else if node.op == .ne {
g.write('!${ptr_typ}_arr_eq(')
} }
g.write('${ptr_typ}_arr_eq(')
if node.left_type.is_ptr() { if node.left_type.is_ptr() {
g.write('*') g.write('*')
} }
@ -3028,12 +3027,14 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
g.write(')') g.write(')')
} else if node.op in [.eq, .ne] && } else if node.op in [.eq, .ne] &&
left_sym.kind == .array_fixed && right_sym.kind == .array_fixed { left_sym.kind == .array_fixed && right_sym.kind == .array_fixed {
info := left_sym.info as table.ArrayFixed ptr_typ := g.gen_fixed_array_equality_fn(left_type)
et := info.elem_type if node.op == .ne {
if !et.is_ptr() && !et.is_pointer() && !et.is_number() && et.idx() !in [table.bool_type_idx, table.char_type_idx] { g.write('!')
verror('`==` on fixed array only supported with POD element types ATM') }
g.write('${ptr_typ}_arr_eq(')
if node.left_type.is_ptr() {
g.write('*')
} }
g.write('(memcmp(')
g.expr(node.left) g.expr(node.left)
g.write(', ') g.write(', ')
if node.right is ast.ArrayInit { if node.right is ast.ArrayInit {
@ -3041,13 +3042,6 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
g.write('($s)') g.write('($s)')
} }
g.expr(node.right) g.expr(node.right)
g.write(', sizeof(')
g.expr(node.left)
if node.op == .eq {
g.write(')) == 0')
} else if node.op == .ne {
g.write(')) != 0')
}
g.write(')') g.write(')')
} else if node.op in [.eq, .ne] && left_sym.kind == .map && right_sym.kind == .map { } else if node.op in [.eq, .ne] && left_sym.kind == .map && right_sym.kind == .map {
ptr_typ := g.gen_map_equality_fn(left_type) ptr_typ := g.gen_map_equality_fn(left_type)