cgen: generate an unique sort comparator function for each .sort() call
parent
a46eda7c44
commit
35a0fe79f9
|
@ -4879,50 +4879,48 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
|||
verror('usage: .sort(a.field < b.field)')
|
||||
}
|
||||
// verror('sort(): unhandled type $typ $q.name')
|
||||
compare_fn = 'compare_' + g.typ(typ)
|
||||
tmp_name := g.new_tmp_var()
|
||||
compare_fn = 'compare_${tmp_name}_' + g.typ(typ)
|
||||
if is_reverse {
|
||||
compare_fn += '_reverse'
|
||||
}
|
||||
if _ := g.table.find_fn(compare_fn) {
|
||||
} else {
|
||||
// Register a new custom `compare_xxx` function for qsort()
|
||||
g.table.register_fn({
|
||||
name: compare_fn
|
||||
return_type: table.int_type
|
||||
})
|
||||
infix_expr := node.args[0].expr as ast.InfixExpr
|
||||
styp := g.typ(typ)
|
||||
// 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.
|
||||
g.definitions.writeln('int $compare_fn ($styp* a, $styp* b) {')
|
||||
field_type := g.typ(infix_expr.left_type)
|
||||
left_expr_str := g.write_expr_to_string(infix_expr.left).replace('.',
|
||||
'->')
|
||||
right_expr_str := g.write_expr_to_string(infix_expr.right).replace('.',
|
||||
'->')
|
||||
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 == table.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_)'
|
||||
}
|
||||
// Register a new custom `compare_xxx` function for qsort()
|
||||
g.table.register_fn({
|
||||
name: compare_fn
|
||||
return_type: table.int_type
|
||||
})
|
||||
infix_expr := node.args[0].expr as ast.InfixExpr
|
||||
styp := g.typ(typ)
|
||||
// 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.
|
||||
g.definitions.writeln('int $compare_fn ($styp* a, $styp* b) {')
|
||||
field_type := g.typ(infix_expr.left_type)
|
||||
left_expr_str := g.write_expr_to_string(infix_expr.left).replace_once('.',
|
||||
'->')
|
||||
right_expr_str := g.write_expr_to_string(infix_expr.right).replace_once('.',
|
||||
'->')
|
||||
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 == table.string_type {
|
||||
if is_reverse {
|
||||
op1 = 'string_gt(a_, b_)'
|
||||
op2 = 'string_lt(a_, b_)'
|
||||
} else {
|
||||
if is_reverse {
|
||||
op1 = 'a_ > b_'
|
||||
op2 = 'a_ < b_'
|
||||
} else {
|
||||
op1 = 'a_ < b_'
|
||||
op2 = 'a_ > b_'
|
||||
}
|
||||
op1 = 'string_lt(a_, b_)'
|
||||
op2 = 'string_gt(a_, b_)'
|
||||
}
|
||||
} else {
|
||||
if is_reverse {
|
||||
op1 = 'a_ > b_'
|
||||
op2 = 'a_ < b_'
|
||||
} else {
|
||||
op1 = 'a_ < b_'
|
||||
op2 = 'a_ > 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') {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
struct Child {
|
||||
f f64
|
||||
}
|
||||
|
||||
struct Parent {
|
||||
child Child
|
||||
name string
|
||||
}
|
||||
|
||||
fn test_sorting_by_different_criteria_in_same_function() {
|
||||
mut arr := [
|
||||
Parent{Child{0.2}, 'def'},
|
||||
Parent{Child{0.1}, 'xyz'},
|
||||
Parent{Child{0.3}, 'abc'},
|
||||
]
|
||||
assert arr[0].name == 'def'
|
||||
arr.sort(a.name < b.name)
|
||||
// println(arr)
|
||||
assert arr[0].name == 'abc'
|
||||
// println(arr)
|
||||
arr.sort(a.child.f < b.child.f)
|
||||
assert arr[0].name == 'xyz'
|
||||
}
|
Loading…
Reference in New Issue