diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 8b0f837a11..d66edfebf6 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -55,6 +55,7 @@ mut: defer_ifdef string 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 } const ( @@ -1300,7 +1301,6 @@ fn (g mut Gen) assign_expr(node ast.AssignExpr) { } fn (g mut Gen) infix_expr(node ast.InfixExpr) { - left_sym := g.table.get_type_symbol(node.left_type) // println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr') // g.write('/*infix*/') // if it.left_type == table.string_type_idx { @@ -1308,6 +1308,8 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) { // } // string + string, string == string etc // g.infix_op = node.op + left_sym := g.table.get_type_symbol(node.left_type) + right_sym := g.table.get_type_symbol(node.right_type) if node.left_type == table.string_type_idx && node.op != .key_in { fn_name := match node.op { .plus { @@ -1340,8 +1342,23 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) { g.write(', ') g.expr(node.right) g.write(')') + } else if node.op in [.eq, .ne] && left_sym.kind == .array && right_sym.kind == .array { + styp := g.table.value_type(node.left_type) + ptr_typ := g.typ(node.left_type).split('_')[1] + if !(ptr_typ in g.array_fn_definitions) { + sym := g.table.get_type_symbol(left_sym.array_info().elem_type) + g.generate_array_equality_fn(ptr_typ, styp, sym) + } + if node.op == .eq { + g.write('${ptr_typ}_arr_eq(') + } else if node.op == .ne { + g.write('!${ptr_typ}_arr_eq(') + } + g.expr(node.left) + g.write(', ') + g.expr(node.right) + g.write(')') } else if node.op == .key_in { - right_sym := g.table.get_type_symbol(node.right_type) if right_sym.kind == .array { match node.right { ast.ArrayInit { @@ -1379,7 +1396,6 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) { tmp := g.new_tmp_var() sym := g.table.get_type_symbol(node.left_type) info := sym.info as table.Array - right_sym := g.table.get_type_symbol(node.right_type) if right_sym.kind == .array && info.elem_type != node.right_type { // push an array => PUSH_MANY, but not if pushing an array to 2d array (`[][]int << []int`) g.write('_PUSH_MANY(&') @@ -2038,6 +2054,27 @@ fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) { } } +fn (g mut Gen) generate_array_equality_fn(ptr_typ string, styp table.Type, sym &table.TypeSymbol) { + g.array_fn_definitions << ptr_typ + g.definitions.writeln('bool ${ptr_typ}_arr_eq(array_${ptr_typ} a, array_${ptr_typ} b) {') + g.definitions.writeln('\tif (a.len != b.len) {') + g.definitions.writeln('\t\treturn false;') + g.definitions.writeln('\t}') + g.definitions.writeln('\tfor (int i = 0; i < a.len; i++) {') + if styp == table.string_type_idx { + g.definitions.writeln('\t\tif (string_ne(*((${ptr_typ}*)(a.data+(i*a.element_size))), *((${ptr_typ}*)(b.data+(i*b.element_size))))) {') + } else if sym.kind == .struct_ { + g.definitions.writeln('\t\tif (memcmp((void*)(a.data+(i*a.element_size)), (void*)(b.data+(i*b.element_size)), a.element_size)) {') + } else { + g.definitions.writeln('\t\tif (*((${ptr_typ}*)(a.data+(i*a.element_size))) != *((${ptr_typ}*)(b.data+(i*b.element_size)))) {') + } + g.definitions.writeln('\t\t\treturn false;') + g.definitions.writeln('\t\t}') + g.definitions.writeln('\t}') + g.definitions.writeln('\treturn true;') + g.definitions.writeln('}') +} + [inline] fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) { arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs diff --git a/vlib/v/tests/array_equality_test.v b/vlib/v/tests/array_equality_test.v new file mode 100644 index 0000000000..46da63e8f8 --- /dev/null +++ b/vlib/v/tests/array_equality_test.v @@ -0,0 +1,46 @@ +struct Tester { + b bool + i int +} + +enum Color { + red green blue +} + +fn test_array_equality() { + strs := ["a", "b", "c"] + assert strs == ["a", "b", "c"] + assert strs != ["a", "c", "b"] + assert strs != ["b", "c", "a"] + assert strs != ["b", "a", "c"] + assert strs != ["c", "b", "a"] + assert strs != ["c", "a", "b"] + bools := [true, true, false] + assert bools == [true, true, false] + assert bools != [true, false, false] + assert bools != [false, true, true] + assert bools != [false, false, true] + assert bools != [false, false, false] + assert bools != [false, true, false] + ints := [1, 2, 3] + assert ints == [1, 2, 3] + assert ints != [1, 3, 2] + assert ints != [2, 3, 1] + assert ints != [2, 1, 3] + assert ints != [3, 2, 1] + assert ints != [3, 1, 2] + a := Tester{true, 100} + b := Tester{false, 200} + testers := [a, b] + assert testers == [a, b] + assert testers != [a, a] + assert testers != [b, b] + assert testers != [b, a] + colors := [Color.red, Color.green, Color.blue] + assert colors == [Color.red, Color.green, Color.blue] + assert colors != [Color.red, Color.blue, Color.green] + assert colors != [Color.green, Color.blue, Color.red] + assert colors != [Color.green, Color.red, Color.blue] + assert colors != [Color.blue, Color.green, Color.red] + assert colors != [Color.blue, Color.red, Color.green] +}