From 3637bac71641dbd268b6d57e458dc8de79ab08f3 Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 2 Apr 2021 22:28:27 +0800 Subject: [PATCH] cgen: fix rune array sort (#9561) --- vlib/builtin/array_test.v | 15 +++++++ vlib/v/gen/c/array.v | 92 +++++++++++++++++++++++---------------- 2 files changed, 69 insertions(+), 38 deletions(-) diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index d7fc608048..238c6b10f6 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -807,6 +807,21 @@ fn test_sort() { // assert users.map(it.name).join(' ') == 'Alice Bob Peter' } +fn test_rune_sort() { + mut bs := [`f`, `e`, `d`, `b`, `c`, `a`] + bs.sort() + println(bs) + assert '$bs' == '[`a`, `b`, `c`, `d`, `e`, `f`]' + + bs.sort(a > b) + println(bs) + assert '$bs' == '[`f`, `e`, `d`, `c`, `b`, `a`]' + + bs.sort(a < b) + println(bs) + assert '$bs' == '[`a`, `b`, `c`, `d`, `e`, `f`]' +} + fn test_sort_by_different_order_of_a_b() { mut x := [1, 2, 3] x.sort(a < b) diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index cce6cd6c15..98da61b0cc 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -248,46 +248,62 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) { } // Register a new custom `compare_xxx` function for qsort() g.table.register_fn(name: compare_fn, return_type: ast.int_type) - infix_expr := node.args[0].expr as ast.InfixExpr - // Variables `a` and `b` are used in the `.sort(a < b)` syntax, so we can reuse them - // when generating the function as long as the args are named the same. - styp_arg := g.typ(typ) - g.definitions.writeln('int $compare_fn ($styp_arg* a, $styp_arg* b) {') - sym := g.table.get_type_symbol(typ) - if !is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 { - g.definitions.writeln('\tif (${styp}__lt(*a, *b)) { return -1; } else { return 1; }}') - } else if is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 { - g.definitions.writeln('\tif (${styp}__lt(*b, *a)) { return -1; } else { return 1; }}') - } else { - field_type := g.typ(infix_expr.left_type) - mut left_expr_str := g.write_expr_to_string(infix_expr.left) - mut right_expr_str := g.write_expr_to_string(infix_expr.right) - if typ.is_ptr() { - left_expr_str = left_expr_str.replace_once('a', '(*a)') - right_expr_str = right_expr_str.replace_once('b', '(*b)') - } - g.definitions.writeln('$field_type a_ = $left_expr_str;') - g.definitions.writeln('$field_type b_ = $right_expr_str;') - mut op1, mut op2 := '', '' - if infix_expr.left_type == ast.string_type { - if is_reverse { - op1 = 'string_gt(a_, b_)' - op2 = 'string_lt(a_, b_)' - } else { - op1 = 'string_lt(a_, b_)' - op2 = 'string_gt(a_, b_)' - } + + if node.args.len == 0 { + styp_arg := g.typ(typ) + g.definitions.writeln('int $compare_fn ($styp_arg* a, $styp_arg* b) {') + sym := g.table.get_type_symbol(typ) + if !is_reverse && sym.has_method('<') { + g.definitions.writeln('\tif (${styp}__lt(*a, *b)) { return -1; } else { return 1; }}') + } else if is_reverse && sym.has_method('<') { + g.definitions.writeln('\tif (${styp}__lt(*b, *a)) { return -1; } else { return 1; }}') } else { - if is_reverse { - op1 = 'a_ > b_' - op2 = 'a_ < b_' - } else { - op1 = 'a_ < b_' - op2 = 'a_ > b_' - } + g.definitions.writeln('if (*a < *b) return -1;') + g.definitions.writeln('if (*a > *b) return 1; return 0; }\n') + } + } else { + infix_expr := node.args[0].expr as ast.InfixExpr + // Variables `a` and `b` are used in the `.sort(a < b)` syntax, so we can reuse them + // when generating the function as long as the args are named the same. + styp_arg := g.typ(typ) + g.definitions.writeln('int $compare_fn ($styp_arg* a, $styp_arg* b) {') + sym := g.table.get_type_symbol(typ) + if !is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 { + g.definitions.writeln('\tif (${styp}__lt(*a, *b)) { return -1; } else { return 1; }}') + } else if is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 { + g.definitions.writeln('\tif (${styp}__lt(*b, *a)) { return -1; } else { return 1; }}') + } else { + field_type := g.typ(infix_expr.left_type) + mut left_expr_str := g.write_expr_to_string(infix_expr.left) + mut right_expr_str := g.write_expr_to_string(infix_expr.right) + if typ.is_ptr() { + left_expr_str = left_expr_str.replace_once('a', '(*a)') + right_expr_str = right_expr_str.replace_once('b', '(*b)') + } + g.definitions.writeln('$field_type a_ = $left_expr_str;') + g.definitions.writeln('$field_type b_ = $right_expr_str;') + mut op1, mut op2 := '', '' + if infix_expr.left_type == ast.string_type { + if is_reverse { + op1 = 'string_gt(a_, b_)' + op2 = 'string_lt(a_, b_)' + } else { + op1 = 'string_lt(a_, b_)' + op2 = 'string_gt(a_, b_)' + } + } else { + deref_str := if infix_expr.left_type.is_ptr() { '*' } else { '' } + if is_reverse { + op1 = '${deref_str}a_ > ${deref_str}b_' + op2 = '${deref_str}a_ < ${deref_str}b_' + } else { + op1 = '${deref_str}a_ < ${deref_str}b_' + op2 = '${deref_str}a_ > ${deref_str}b_' + } + } + g.definitions.writeln('if ($op1) return -1;') + g.definitions.writeln('if ($op2) return 1; return 0; }\n') } - g.definitions.writeln('if ($op1) return -1;') - g.definitions.writeln('if ($op2) return 1; return 0; }\n') } } if is_reverse && !compare_fn.ends_with('_reverse') {