cgen: optimize .map(), .any(), .filter() and .all() when using closure (#21256)

This commit is contained in:
Felipe Pena 2024-04-12 10:32:56 -03:00 committed by GitHub
parent 1a35a783f1
commit eb44844ccf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 104 additions and 17 deletions

View File

@ -463,15 +463,23 @@ fn (mut g Gen) array_init_with_fields(node ast.ArrayInit, elem_type Type, is_amp
}
}
fn (mut g Gen) write_closure_fn(mut expr ast.AnonFn, var_name string) {
past := g.past_tmp_var_new()
fn_ptr_name := g.fn_var_signature(expr.decl.return_type, expr.decl.params.map(it.typ),
past.tmp_var)
g.write('${fn_ptr_name} = ')
fn (mut g Gen) declare_closure_fn(mut expr ast.AnonFn, var_name string) {
decl_var := g.fn_var_signature(expr.decl.return_type, expr.decl.params.map(it.typ),
var_name)
g.write('${decl_var} = ')
g.gen_anon_fn(mut expr)
g.writeln(';')
g.past_tmp_var_done(past)
g.write('(${var_name})') // usually `it`
}
fn (mut g Gen) write_closure_fn(mut expr ast.AnonFn, var_name string, declared_var string) {
if declared_var == '' {
past := g.past_tmp_var_new()
g.declare_closure_fn(mut expr, past.var_name)
g.past_tmp_var_done(past)
g.write('(${var_name})') // usually `it`
} else {
g.write('${declared_var}(${var_name})')
}
}
// `nums.map(it % 2 == 0)`
@ -515,6 +523,15 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, ret_typ,
'{0}')
g.writeln('${past.tmp_var} = __new_array${noscan}(0, ${past.tmp_var}_len, sizeof(${ret_elem_type}));\n')
mut closure_var := ''
if mut expr is ast.AnonFn {
if expr.inherited_vars.len > 0 {
closure_var = g.new_tmp_var()
g.declare_closure_fn(mut expr, closure_var)
}
}
i := g.new_tmp_var()
g.writeln('for (int ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
g.indent++
@ -526,7 +543,7 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
ast.AnonFn {
g.write('${ret_elem_type} ${tmp_map_expr_result_name} = ')
if expr.inherited_vars.len > 0 {
g.write_closure_fn(mut expr, var_name)
g.write_closure_fn(mut expr, var_name, closure_var)
} else {
g.gen_anon_fn_decl(mut expr)
g.write('${expr.decl.name}(${var_name})')
@ -769,11 +786,21 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
noscan := g.check_noscan(info.elem_type)
has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, styp, '{0}')
g.writeln('${past.tmp_var} = __new_array${noscan}(0, ${past.tmp_var}_len, sizeof(${elem_type_str}));\n')
mut expr := node.args[0].expr
var_name := g.get_array_expr_param_name(mut expr)
mut closure_var := ''
if mut expr is ast.AnonFn {
if expr.inherited_vars.len > 0 {
closure_var = g.new_tmp_var()
g.declare_closure_fn(mut expr, closure_var)
}
}
i := g.new_tmp_var()
g.writeln('for (int ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
g.indent++
mut expr := node.args[0].expr
var_name := g.get_array_expr_param_name(mut expr)
g.write_prepared_var(var_name, info, elem_type_str, past.tmp_var, i)
g.set_current_pos_as_last_stmt_pos()
mut is_embed_map_filter := false
@ -781,7 +808,7 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
ast.AnonFn {
g.write('if (')
if expr.inherited_vars.len > 0 {
g.write_closure_fn(mut expr, var_name)
g.write_closure_fn(mut expr, var_name, closure_var)
} else {
g.gen_anon_fn_decl(mut expr)
g.write('${expr.decl.name}(${var_name})')
@ -1163,11 +1190,21 @@ fn (mut g Gen) gen_array_any(node ast.CallExpr) {
elem_type_str := g.typ(info.elem_type)
has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, 'bool',
'false')
mut expr := node.args[0].expr
var_name := g.get_array_expr_param_name(mut expr)
mut closure_var := ''
if mut expr is ast.AnonFn {
if expr.inherited_vars.len > 0 {
closure_var = g.new_tmp_var()
g.declare_closure_fn(mut expr, closure_var)
}
}
i := g.new_tmp_var()
g.writeln('for (int ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
g.indent++
mut expr := node.args[0].expr
var_name := g.get_array_expr_param_name(mut expr)
g.write_prepared_var(var_name, info, elem_type_str, past.tmp_var, i)
g.set_current_pos_as_last_stmt_pos()
mut is_embed_map_filter := false
@ -1175,7 +1212,7 @@ fn (mut g Gen) gen_array_any(node ast.CallExpr) {
ast.AnonFn {
g.write('if (')
if expr.inherited_vars.len > 0 {
g.write_closure_fn(mut expr, var_name)
g.write_closure_fn(mut expr, var_name, closure_var)
} else {
g.gen_anon_fn_decl(mut expr)
g.write('${expr.decl.name}(${var_name})')
@ -1244,10 +1281,20 @@ fn (mut g Gen) gen_array_all(node ast.CallExpr) {
has_infix_left_var_name := g.write_prepared_tmp_value(past.tmp_var, node, 'bool',
'true')
i := g.new_tmp_var()
g.writeln('for (int ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
g.indent++
mut expr := node.args[0].expr
var_name := g.get_array_expr_param_name(mut expr)
mut closure_var := ''
if mut expr is ast.AnonFn {
if expr.inherited_vars.len > 0 {
closure_var = g.new_tmp_var()
g.declare_closure_fn(mut expr, closure_var)
}
}
g.writeln('for (int ${i} = 0; ${i} < ${past.tmp_var}_len; ++${i}) {')
g.indent++
g.write_prepared_var(var_name, info, elem_type_str, past.tmp_var, i)
g.empty_line = true
g.set_current_pos_as_last_stmt_pos()
@ -1256,7 +1303,7 @@ fn (mut g Gen) gen_array_all(node ast.CallExpr) {
ast.AnonFn {
g.write('if (!(')
if expr.inherited_vars.len > 0 {
g.write_closure_fn(mut expr, var_name)
g.write_closure_fn(mut expr, var_name, closure_var)
} else {
g.gen_anon_fn_decl(mut expr)
g.write('${expr.decl.name}(${var_name})')

View File

@ -0,0 +1,40 @@
fn setup(fname string) (int, int, []int) {
println(fname)
return C._closure_cap, 42, []int{len: 5, init: index * 5}
}
fn test_array_filter() {
start_closure_cap, x, a := setup(@LOCATION)
println(a.filter(fn [x] (i int) bool {
println('x: ${x} | i: ${i}')
return i < 20
}))
assert start_closure_cap - C._closure_cap == 1
}
fn test_array_map() {
start_closure_cap, x, a := setup(@LOCATION)
println(a.map(fn [x] (i int) int {
println('x: ${x} | i: ${i}')
return x + i
}))
assert start_closure_cap - C._closure_cap == 1
}
fn test_array_any() {
start_closure_cap, x, a := setup(@LOCATION)
println(a.any(fn [x] (i int) bool {
println('x: ${x} | i: ${i}')
return i < x
}))
assert start_closure_cap - C._closure_cap == 1
}
fn test_array_all() {
start_closure_cap, x, a := setup(@LOCATION)
println(a.all(fn [x] (i int) bool {
println('x: ${x} | i: ${i}')
return i < x
}))
assert start_closure_cap - C._closure_cap == 1
}