sort: fix sorting by struct fields
parent
e5e31f7210
commit
f8be2110ec
|
@ -736,6 +736,9 @@ fn test_sort() {
|
||||||
assert(users[0].age == 25)
|
assert(users[0].age == 25)
|
||||||
assert(users[1].age == 22)
|
assert(users[1].age == 22)
|
||||||
assert(users[2].age == 20)
|
assert(users[2].age == 20)
|
||||||
|
//
|
||||||
|
users.sort(a.name < b.name) // Test sorting by string fields
|
||||||
|
//assert users.map(it.name).join(' ') == 'Alice Bob Peter'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_f32_sort() {
|
fn test_f32_sort() {
|
||||||
|
|
|
@ -183,3 +183,10 @@ fn (flags []Flag) contains(name string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn (mut flags []Flag) sort2() {
|
||||||
|
flags.sort_with_compare(fn (a, b &Flag) int {
|
||||||
|
return compare_strings(&a.name, &b.name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,10 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
struct Gen {
|
struct Gen {
|
||||||
table &table.Table
|
|
||||||
pref &pref.Preferences
|
pref &pref.Preferences
|
||||||
module_built string
|
module_built string
|
||||||
mut:
|
mut:
|
||||||
|
table &table.Table
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
cheaders strings.Builder
|
cheaders strings.Builder
|
||||||
includes strings.Builder // all C #includes required by V modules
|
includes strings.Builder // all C #includes required by V modules
|
||||||
|
@ -3739,14 +3739,14 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
||||||
// `users.sort(a.age < b.age)`
|
// `users.sort(a.age < b.age)`
|
||||||
fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
||||||
// println('filter s="$s"')
|
// println('filter s="$s"')
|
||||||
sym := g.table.get_type_symbol(node.return_type)
|
return_sym := g.table.get_type_symbol(node.return_type)
|
||||||
if sym.kind != .array {
|
if return_sym.kind != .array {
|
||||||
println(node.name)
|
println(node.name)
|
||||||
println(g.typ(node.receiver_type))
|
println(g.typ(node.receiver_type))
|
||||||
println(sym.kind)
|
// println(sym.kind)
|
||||||
verror('sort() requires an array')
|
verror('sort() requires an array')
|
||||||
}
|
}
|
||||||
info := sym.info as table.Array
|
info := return_sym.info as table.Array
|
||||||
// No arguments means we are sorting an array of builtins (e.g. `numbers.sort()`)
|
// No arguments means we are sorting an array of builtins (e.g. `numbers.sort()`)
|
||||||
// The type for the comparison fns is the type of the element itself.
|
// The type for the comparison fns is the type of the element itself.
|
||||||
mut typ := info.elem_type
|
mut typ := info.elem_type
|
||||||
|
@ -3756,29 +3756,73 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
||||||
// Get the type of the field that's being compared
|
// Get the type of the field that's being compared
|
||||||
// `a.age > b.age` => `age int` => int
|
// `a.age > b.age` => `age int` => int
|
||||||
infix_expr := node.args[0].expr as ast.InfixExpr
|
infix_expr := node.args[0].expr as ast.InfixExpr
|
||||||
typ = infix_expr.left_type
|
// typ = infix_expr.left_type
|
||||||
is_reverse = infix_expr.op == .gt
|
is_reverse = infix_expr.op == .gt
|
||||||
}
|
}
|
||||||
mut compare_fn := match typ {
|
mut compare_fn := ''
|
||||||
|
match typ {
|
||||||
table.int_type {
|
table.int_type {
|
||||||
'compare_ints'
|
compare_fn = 'compare_ints'
|
||||||
}
|
}
|
||||||
table.string_type {
|
table.string_type {
|
||||||
'compare_strings'
|
compare_fn = 'compare_strings'
|
||||||
}
|
}
|
||||||
table.f64_type {
|
table.f64_type {
|
||||||
'compare_floats'
|
compare_fn = 'compare_floats'
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
q := g.table.get_type_symbol(typ)
|
// Generate a comparison function for a custom type
|
||||||
if node.args.len == 0 {
|
if node.args.len == 0 {
|
||||||
verror('usage: .sort(a.field < b.field) $q.name')
|
verror('usage: .sort(a.field < b.field)')
|
||||||
|
}
|
||||||
|
// verror('sort(): unhandled type $typ $q.name')
|
||||||
|
compare_fn = 'compare_' + 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_)'
|
||||||
|
}
|
||||||
|
} 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')
|
||||||
}
|
}
|
||||||
verror('sort(): unhandled type $typ $q.name')
|
|
||||||
''
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_reverse {
|
if is_reverse && !compare_fn.ends_with('_reverse') {
|
||||||
compare_fn += '_reverse'
|
compare_fn += '_reverse'
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue