gen: more efficient `for in` with a map (#6961)

pull/6975/head
Nick Treleaven 2020-11-26 22:22:14 +00:00 committed by GitHub
parent 5e59718970
commit ea8adfdbf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 23 deletions

View File

@ -1173,33 +1173,34 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
} else if it.kind == .map {
// `for key, val in map {`
g.writeln('// FOR IN map')
key_styp := g.typ(it.key_type)
val_styp := g.typ(it.val_type)
val_sym := g.table.get_type_symbol(it.val_type)
keys_tmp := 'keys_' + g.new_tmp_var()
idx := g.new_tmp_var()
key := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var }
zero := g.type_default(it.val_type)
atmp := g.new_tmp_var()
atmp_styp := g.typ(it.cond_type)
g.write('$atmp_styp $atmp = ')
g.expr(it.cond)
g.writeln(';')
g.writeln('array_$key_styp $keys_tmp = map_keys(&$atmp);')
g.writeln('for (int $idx = 0; $idx < ${keys_tmp}.len; ++$idx) {')
// TODO: analyze whether it.key_type has a .clone() method and call .clone() for all types:
if it.key_type == table.string_type {
g.writeln('\t$key_styp $key = /*kkkk*/ string_clone( (($key_styp*)${keys_tmp}.data)[$idx] );')
} else {
g.writeln('\t$key_styp $key = /*kkkk*/ (($key_styp*)${keys_tmp}.data)[$idx];')
g.writeln('for (int $idx = 0; $idx < $atmp\.key_values.len; ++$idx) {')
g.writeln('\tif ($atmp\.key_values.keys[$idx].str == 0) {continue;}')
if it.key_var != '_' {
key_styp := g.typ(it.key_type)
key := c_name(it.key_var)
// TODO: analyze whether it.key_type has a .clone() method and call .clone() for all types:
if it.key_type == table.string_type {
g.writeln('\t$key_styp $key = /*kkkk*/ string_clone($atmp\.key_values.keys[$idx]);')
} else {
g.writeln('\t$key_styp $key = /*kkkk*/ $atmp\.key_values.keys[$idx];')
}
}
if it.val_var != '_' {
val_sym := g.table.get_type_symbol(it.val_type)
valstr := '(void*)($atmp\.key_values.values + $idx * (u32)($atmp\.value_bytes))'
if val_sym.kind == .function {
g.write('\t')
g.write_fn_ptr_decl(val_sym.info as table.FnType, c_name(it.val_var))
g.writeln(' = (*(voidptr*)map_get($atmp, $key, &(voidptr[]){ $zero }));')
g.writeln(' = (*(voidptr*)$valstr);')
} else {
g.writeln('\t$val_styp ${c_name(it.val_var)} = (*($val_styp*)map_get($atmp, $key, &($val_styp[]){ $zero }));')
val_styp := g.typ(it.val_type)
g.writeln('\t$val_styp ${c_name(it.val_var)} = (*($val_styp*)$valstr);')
}
}
g.stmts(it.stmts)
@ -1213,9 +1214,6 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
if it.label.len > 0 {
g.writeln('\t$it.label\__break: {}')
}
g.writeln('/*for in map cleanup*/')
g.writeln('for (int $idx = 0; $idx < ${keys_tmp}.len; ++$idx) { string_free(&(($key_styp*)${keys_tmp}.data)[$idx]); }')
g.writeln('array_free(&$keys_tmp);')
return
} else if it.cond_type.has_flag(.variadic) {
g.writeln('// FOR IN cond_type/variadic')

View File

@ -103,9 +103,11 @@ fn test_for_in_map_val() {
}
fn test_for_in_map_both() {
mut i := 0
for _, _ in m {
assert true
i++
}
assert i == 1
}
fn test_nested_for_in_map_key() {
@ -127,11 +129,13 @@ fn test_nested_for_in_map_val() {
}
fn test_nested_for_in_map_both() {
mut i := 0
for _, _ in m {
for _, _ in m {
assert true
i++
}
}
assert i == 1
}
fn fn_for_in_variadic_args_simple(arr ...string) {

View File

@ -43,16 +43,24 @@ fn test_for_char_in_string() {
assert sum == 394 // ascii codes of `a` + `b` + `c` + `d`
}
fn test_for_char_in_map() {
fn test_for_string_in_map() {
m := {
'a': 'b'
'c': 'd'
}
mut acc := ''
for k, char in m {
acc += '$k: $char, '
for k, v in m {
acc += '$k: $v, '
}
assert acc == 'a: b, c: d, '
mut m2 := {'a': 3, 'b': 4, 'c': 5}
m2.delete('b')
acc = ''
for k, v in m2 {
acc += '$k: $v, '
}
assert acc == 'a: 3, c: 5, '
}
fn test_mut_for() {