mirror of
https://github.com/vlang/v.git
synced 2025-09-11 00:20:26 -04:00
checker, cgen: implement methods sort_with_compare()/sorted_with_compare() for fixed arrays (#22702)
This commit is contained in:
parent
730b3f5e0f
commit
4e9b21f9d0
@ -69,3 +69,98 @@ fn test_sorted_by_len() {
|
|||||||
c := a.sorted(a.len < b.len)
|
c := a.sorted(a.len < b.len)
|
||||||
assert c == ['a', 'hi', 'abc', 'zzzzz']!
|
assert c == ['a', 'hi', 'abc', 'zzzzz']!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_sort_with_compare_1() {
|
||||||
|
mut a := ['hi', '1', '5', '3']!
|
||||||
|
a.sort_with_compare(fn (a &string, b &string) int {
|
||||||
|
if a < b {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if a > b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
assert a == ['1', '3', '5', 'hi']!
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_sorted_with_compare_1() {
|
||||||
|
a := ['hi', '1', '5', '3']!
|
||||||
|
b := a.sorted_with_compare(fn (a &string, b &string) int {
|
||||||
|
if a < b {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if a > b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
assert a == ['hi', '1', '5', '3']!
|
||||||
|
assert b == ['1', '3', '5', 'hi']!
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Ka {
|
||||||
|
s string
|
||||||
|
i int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_sort_with_compare_2() {
|
||||||
|
mut arr := [
|
||||||
|
Ka{
|
||||||
|
s: 'bbb'
|
||||||
|
i: 100
|
||||||
|
},
|
||||||
|
Ka{
|
||||||
|
s: 'aaa'
|
||||||
|
i: 101
|
||||||
|
},
|
||||||
|
Ka{
|
||||||
|
s: 'ccc'
|
||||||
|
i: 102
|
||||||
|
},
|
||||||
|
]!
|
||||||
|
cmp := fn (a &Ka, b &Ka) int {
|
||||||
|
return compare_strings(a.s, b.s)
|
||||||
|
}
|
||||||
|
arr.sort_with_compare(cmp)
|
||||||
|
assert arr[0].s == 'aaa'
|
||||||
|
assert arr[0].i == 101
|
||||||
|
assert arr[1].s == 'bbb'
|
||||||
|
assert arr[1].i == 100
|
||||||
|
assert arr[2].s == 'ccc'
|
||||||
|
assert arr[2].i == 102
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_sorted_with_compare_2() {
|
||||||
|
arr := [
|
||||||
|
Ka{
|
||||||
|
s: 'bbb'
|
||||||
|
i: 100
|
||||||
|
},
|
||||||
|
Ka{
|
||||||
|
s: 'aaa'
|
||||||
|
i: 101
|
||||||
|
},
|
||||||
|
Ka{
|
||||||
|
s: 'ccc'
|
||||||
|
i: 102
|
||||||
|
},
|
||||||
|
]!
|
||||||
|
cmp := fn (a &Ka, b &Ka) int {
|
||||||
|
return compare_strings(a.s, b.s)
|
||||||
|
}
|
||||||
|
b := arr.sorted_with_compare(cmp)
|
||||||
|
assert arr[0].s == 'bbb'
|
||||||
|
assert arr[0].i == 100
|
||||||
|
assert arr[1].s == 'aaa'
|
||||||
|
assert arr[1].i == 101
|
||||||
|
assert arr[2].s == 'ccc'
|
||||||
|
assert arr[2].i == 102
|
||||||
|
|
||||||
|
assert b[0].s == 'aaa'
|
||||||
|
assert b[0].i == 101
|
||||||
|
assert b[1].s == 'bbb'
|
||||||
|
assert b[1].i == 100
|
||||||
|
assert b[2].s == 'ccc'
|
||||||
|
assert b[2].i == 102
|
||||||
|
}
|
||||||
|
@ -33,7 +33,7 @@ pub const array_builtin_methods = ['filter', 'clone', 'repeat', 'reverse', 'map'
|
|||||||
'first', 'last', 'pop', 'delete', 'insert', 'prepend']
|
'first', 'last', 'pop', 'delete', 'insert', 'prepend']
|
||||||
pub const array_builtin_methods_chk = token.new_keywords_matcher_from_array_trie(array_builtin_methods)
|
pub const array_builtin_methods_chk = token.new_keywords_matcher_from_array_trie(array_builtin_methods)
|
||||||
pub const fixed_array_builtin_methods = ['contains', 'index', 'any', 'all', 'wait', 'map', 'sort',
|
pub const fixed_array_builtin_methods = ['contains', 'index', 'any', 'all', 'wait', 'map', 'sort',
|
||||||
'sorted']
|
'sorted', 'sort_with_compare', 'sorted_with_compare']
|
||||||
pub const fixed_array_builtin_methods_chk = token.new_keywords_matcher_from_array_trie(fixed_array_builtin_methods)
|
pub const fixed_array_builtin_methods_chk = token.new_keywords_matcher_from_array_trie(fixed_array_builtin_methods)
|
||||||
// TODO: remove `byte` from this list when it is no longer supported
|
// TODO: remove `byte` from this list when it is no longer supported
|
||||||
pub const reserved_type_names = ['byte', 'bool', 'char', 'i8', 'i16', 'int', 'i64', 'u8', 'u16',
|
pub const reserved_type_names = ['byte', 'bool', 'char', 'i8', 'i16', 'int', 'i64', 'u8', 'u16',
|
||||||
|
@ -3622,6 +3622,52 @@ fn (mut c Checker) fixed_array_builtin_method_call(mut node ast.CallExpr, left_t
|
|||||||
} else {
|
} else {
|
||||||
node.return_type = node.left_type
|
node.return_type = node.left_type
|
||||||
}
|
}
|
||||||
|
} else if method_name in ['sort_with_compare', 'sorted_with_compare'] {
|
||||||
|
if node.args.len != 1 {
|
||||||
|
c.error('`.${method_name}()` expected 1 argument, but got ${node.args.len}',
|
||||||
|
node.pos)
|
||||||
|
} else {
|
||||||
|
if mut node.args[0].expr is ast.LambdaExpr {
|
||||||
|
c.support_lambda_expr_in_sort(elem_typ.ref(), ast.int_type, mut node.args[0].expr)
|
||||||
|
}
|
||||||
|
arg_type := c.expr(mut node.args[0].expr)
|
||||||
|
arg_sym := c.table.sym(arg_type)
|
||||||
|
if arg_sym.kind == .function {
|
||||||
|
func_info := arg_sym.info as ast.FnType
|
||||||
|
if func_info.func.params.len == 2 {
|
||||||
|
if func_info.func.params[0].typ.nr_muls() != elem_typ.nr_muls() + 1 {
|
||||||
|
arg_typ_str := c.table.type_to_str(func_info.func.params[0].typ)
|
||||||
|
expected_typ_str := c.table.type_to_str(elem_typ.ref())
|
||||||
|
c.error('${method_name} callback function parameter `${func_info.func.params[0].name}` with type `${arg_typ_str}` should be `${expected_typ_str}`',
|
||||||
|
func_info.func.params[0].type_pos)
|
||||||
|
}
|
||||||
|
if func_info.func.params[1].typ.nr_muls() != elem_typ.nr_muls() + 1 {
|
||||||
|
arg_typ_str := c.table.type_to_str(func_info.func.params[1].typ)
|
||||||
|
expected_typ_str := c.table.type_to_str(elem_typ.ref())
|
||||||
|
c.error('${method_name} callback function parameter `${func_info.func.params[1].name}` with type `${arg_typ_str}` should be `${expected_typ_str}`',
|
||||||
|
func_info.func.params[1].type_pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.args[0].typ = arg_type
|
||||||
|
if method := c.table.find_method(left_sym, method_name) {
|
||||||
|
c.check_expected_call_arg(arg_type, method.params[1].typ, node.language,
|
||||||
|
node.args[0]) or {
|
||||||
|
c.error('${err.msg()} in argument 1 to `${left_sym.name}.${method_name}`',
|
||||||
|
node.args[0].pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for mut arg in node.args {
|
||||||
|
c.check_expr_option_or_result_call(arg.expr, c.expr(mut arg.expr))
|
||||||
|
}
|
||||||
|
if method_name == 'sort_with_compare' {
|
||||||
|
node.return_type = ast.void_type
|
||||||
|
node.receiver_type = node.left_type.ref()
|
||||||
|
} else {
|
||||||
|
node.return_type = node.left_type
|
||||||
|
node.receiver_type = node.left_type
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return node.return_type
|
return node.return_type
|
||||||
}
|
}
|
||||||
|
@ -776,17 +776,56 @@ fn (mut g Gen) gen_array_sort_call(node ast.CallExpr, compare_fn string, is_arra
|
|||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write('${deref_field}len, ')
|
g.write('${deref_field}len, ')
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write2('${deref_field}element_size, (int (*)(const void *, const void *))&${compare_fn});',
|
g.write2('${deref_field}element_size, (voidptr)${compare_fn});', ' }')
|
||||||
' }')
|
|
||||||
} else {
|
} else {
|
||||||
info := g.table.final_sym(node.left_type).info as ast.ArrayFixed
|
info := g.table.final_sym(node.left_type).info as ast.ArrayFixed
|
||||||
elem_styp := g.styp(info.elem_type)
|
elem_styp := g.styp(info.elem_type)
|
||||||
g.write('qsort(&')
|
g.write('qsort(&')
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write(', ${info.size}, sizeof(${elem_styp}), (int (*)(const void *, const void *))&${compare_fn});')
|
g.write(', ${info.size}, sizeof(${elem_styp}), (voidptr)${compare_fn});')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_fixed_array_sorted_with_compare(node ast.CallExpr) {
|
||||||
|
past := g.past_tmp_var_new()
|
||||||
|
defer {
|
||||||
|
g.past_tmp_var_done(past)
|
||||||
|
}
|
||||||
|
atype := g.styp(node.return_type)
|
||||||
|
g.writeln('${atype} ${past.tmp_var};')
|
||||||
|
g.write('memcpy(&${past.tmp_var}, &')
|
||||||
|
g.expr(node.left)
|
||||||
|
g.writeln(', sizeof(${atype}));')
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
node.left = ast.Expr(ast.Ident{
|
||||||
|
name: past.tmp_var
|
||||||
|
})
|
||||||
|
}
|
||||||
|
g.gen_fixed_array_sort_with_compare(node)
|
||||||
|
g.writeln(';')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_fixed_array_sort_with_compare(node ast.CallExpr) {
|
||||||
|
mut compare_fn := ''
|
||||||
|
if node.args[0].expr is ast.LambdaExpr {
|
||||||
|
lambda_fn_name := node.args[0].expr.func.decl.name
|
||||||
|
compare_fn = '${lambda_fn_name}_lambda_wrapper'
|
||||||
|
mut lambda_node := unsafe { node.args[0].expr }
|
||||||
|
g.gen_anon_fn_decl(mut lambda_node.func)
|
||||||
|
} else if node.args[0].expr is ast.AnonFn {
|
||||||
|
mut fn_expr := unsafe { node.args[0].expr }
|
||||||
|
g.gen_anon_fn_decl(mut fn_expr)
|
||||||
|
compare_fn = node.args[0].expr.decl.name
|
||||||
|
} else if node.args[0].expr is ast.Ident {
|
||||||
|
compare_fn = node.args[0].expr.name
|
||||||
|
} else {
|
||||||
|
compare_fn = node.args[0].expr.str()
|
||||||
|
}
|
||||||
|
// write call to the generated function
|
||||||
|
g.gen_array_sort_call(node, compare_fn, false)
|
||||||
|
}
|
||||||
|
|
||||||
// `nums.filter(it % 2 == 0)`
|
// `nums.filter(it % 2 == 0)`
|
||||||
fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
|
fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
|
||||||
past := g.past_tmp_var_new()
|
past := g.past_tmp_var_new()
|
||||||
|
@ -1210,6 +1210,12 @@ fn (mut g Gen) gen_fixed_array_method_call(node ast.CallExpr, left_type ast.Type
|
|||||||
'sorted' {
|
'sorted' {
|
||||||
g.gen_array_sorted(node)
|
g.gen_array_sorted(node)
|
||||||
}
|
}
|
||||||
|
'sort_with_compare' {
|
||||||
|
g.gen_fixed_array_sort_with_compare(node)
|
||||||
|
}
|
||||||
|
'sorted_with_compare' {
|
||||||
|
g.gen_fixed_array_sorted_with_compare(node)
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user