diff --git a/vlib/builtin/array_eq_test.v b/vlib/builtin/array_eq_test.v index b53f00fbc9..71d369f945 100644 --- a/vlib/builtin/array_eq_test.v +++ b/vlib/builtin/array_eq_test.v @@ -10,3 +10,37 @@ fn test_eq() { assert [{'bob': 22}, {'tom': 33}] == [{'bob': 22}, {'tom': 33}] 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']!!] +} diff --git a/vlib/v/gen/auto_eq_methods.v b/vlib/v/gen/auto_eq_methods.v index f8e95759a3..a23714403f 100644 --- a/vlib/v/gen/auto_eq_methods.v +++ b/vlib/v/gen/auto_eq_methods.v @@ -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() { eq_fn := g.gen_array_equality_fn(field.typ) 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() { eq_fn := g.gen_map_equality_fn(field.typ) 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() { 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])) {') + } 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() { 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])) {') @@ -86,6 +92,50 @@ fn (mut g Gen) gen_array_equality_fn(left table.Type) string { 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 { ptr_typ := g.typ(left).trim('*') 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) 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 { 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)) {') diff --git a/vlib/v/gen/auto_str_methods.v b/vlib/v/gen/auto_str_methods.v index 84df234f85..70bfbb0d60 100644 --- a/vlib/v/gen/auto_str_methods.v +++ b/vlib/v/gen/auto_str_methods.v @@ -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 { g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();') } 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 is_elem_ptr { g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(*it, indent_count);') diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 5a9e0eb4d7..21d25aef68 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -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 { ptr_typ := g.gen_array_equality_fn(left_type) - if node.op == .eq { - g.write('${ptr_typ}_arr_eq(') - } else if node.op == .ne { - g.write('!${ptr_typ}_arr_eq(') + if node.op == .ne { + g.write('!') } + g.write('${ptr_typ}_arr_eq(') if node.left_type.is_ptr() { g.write('*') } @@ -3028,12 +3027,14 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { g.write(')') } else if node.op in [.eq, .ne] && left_sym.kind == .array_fixed && right_sym.kind == .array_fixed { - info := left_sym.info as table.ArrayFixed - et := info.elem_type - if !et.is_ptr() && !et.is_pointer() && !et.is_number() && et.idx() !in [table.bool_type_idx, table.char_type_idx] { - verror('`==` on fixed array only supported with POD element types ATM') + ptr_typ := g.gen_fixed_array_equality_fn(left_type) + if node.op == .ne { + g.write('!') + } + g.write('${ptr_typ}_arr_eq(') + if node.left_type.is_ptr() { + g.write('*') } - g.write('(memcmp(') g.expr(node.left) g.write(', ') if node.right is ast.ArrayInit { @@ -3041,13 +3042,6 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { g.write('($s)') } 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(')') } else if node.op in [.eq, .ne] && left_sym.kind == .map && right_sym.kind == .map { ptr_typ := g.gen_map_equality_fn(left_type)