map: fix delete in for-in (#9336)

pull/9343/head
ka-weihe 2021-03-17 01:42:33 +01:00 committed by GitHub
parent 149151b1e8
commit 2991cad4e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 10 deletions

View File

@ -255,6 +255,78 @@ fn test_delete_size() {
}
}
fn test_nested_for_in() {
mut m := map[string]int{}
for i in 0 .. 1000 {
m[i.str()] = i
}
mut i := 0
for key1, _ in m {
assert key1 == i.str()
i++
mut j := 0
for key2, _ in m {
assert key2 == j.str()
j++
}
}
}
fn test_delete_in_for_in() {
mut m := map[string]string{}
for i in 0 .. 1000 {
m[i.str()] = i.str()
}
mut i := 0
for key, _ in m {
assert key == i.str()
m.delete(key)
i++
}
assert m.str() == '{}'
assert m.len == 0
}
fn test_set_in_for_in() {
mut m := map[string]string{}
for i in 0 .. 10 {
m[i.str()] = i.str()
}
mut last_key := ''
mut i := 0
for key, _ in m {
m['10'] = '10'
assert key == i.str()
last_key = key
i++
}
assert last_key == '10'
}
fn test_delete_and_set_in_for_in() {
mut m := map[string]string{}
for i in 0 .. 1000 {
m[i.str()] = i.str()
}
mut i := 0
for key, _ in m {
assert key == i.str()
m.delete(key)
m[key] = i.str()
if i == 999 {
break
}
i++
}
assert m.len == 1000
i = 0
for key, _ in m {
assert m[key] == i.str()
i++
}
assert i == 1000
}
struct Mstruct1 {
pub mut:
mymap map[string]int
@ -326,7 +398,7 @@ fn test_assign_directly() {
}
fn test_map_in_directly() {
for k, v in {
for k, v in map{
'aa': 1
} {
assert k == 'aa'

View File

@ -1475,40 +1475,51 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
}
arw_or_pt := if node.cond_type.is_ptr() { '->' } else { '.' }
idx := g.new_tmp_var()
map_len := g.new_tmp_var()
g.empty_line = true
g.writeln('for (int $idx = 0; $idx < $cond_var${arw_or_pt}key_values.len; ++$idx) {')
g.writeln('int $map_len = $cond_var${arw_or_pt}key_values.len;')
g.writeln('for (int $idx = 0; $idx < $map_len; ++$idx ) {')
// TODO: don't have this check when the map has no deleted elements
g.writeln('\tif (!DenseArray_has_index(&$cond_var${arw_or_pt}key_values, $idx)) {continue;}')
g.indent++
diff := g.new_tmp_var()
g.writeln('int $diff = $cond_var${arw_or_pt}key_values.len - $map_len;')
g.writeln('$map_len = $cond_var${arw_or_pt}key_values.len;')
// TODO: optimize this
g.writeln('if ($diff < 0) {')
g.writeln('\t$idx = -1;')
g.writeln('\tcontinue;')
g.writeln('}')
g.writeln('if (!DenseArray_has_index(&$cond_var${arw_or_pt}key_values, $idx)) {continue;}')
if node.key_var != '_' {
key_styp := g.typ(node.key_type)
key := c_name(node.key_var)
g.writeln('\t$key_styp $key = /*key*/ *($key_styp*)DenseArray_key(&$cond_var${arw_or_pt}key_values, $idx);')
g.writeln('$key_styp $key = /*key*/ *($key_styp*)DenseArray_key(&$cond_var${arw_or_pt}key_values, $idx);')
// TODO: analyze whether node.key_type has a .clone() method and call .clone() for all types:
if node.key_type == table.string_type {
g.writeln('\t$key = string_clone($key);')
g.writeln('$key = string_clone($key);')
}
}
if node.val_var != '_' {
val_sym := g.table.get_type_symbol(node.val_type)
if val_sym.kind == .function {
g.write('\t')
g.write_fn_ptr_decl(val_sym.info as table.FnType, c_name(node.val_var))
g.write(' = (*(voidptr*)')
g.writeln('DenseArray_value(&$cond_var${arw_or_pt}key_values, $idx));')
} else if val_sym.kind == .array_fixed && !node.val_is_mut {
val_styp := g.typ(node.val_type)
g.writeln('\t$val_styp ${c_name(node.val_var)};')
g.writeln('\tmemcpy(*($val_styp*)${c_name(node.val_var)}, (byte*)DenseArray_value(&$cond_var${arw_or_pt}key_values, $idx), sizeof($val_styp));')
g.writeln('$val_styp ${c_name(node.val_var)};')
g.writeln('memcpy(*($val_styp*)${c_name(node.val_var)}, (byte*)DenseArray_value(&$cond_var${arw_or_pt}key_values, $idx), sizeof($val_styp));')
} else {
val_styp := g.typ(node.val_type)
if node.val_type.is_ptr() {
g.write('\t$val_styp ${c_name(node.val_var)} = &(*($val_styp)')
g.write('$val_styp ${c_name(node.val_var)} = &(*($val_styp)')
} else {
g.write('\t$val_styp ${c_name(node.val_var)} = (*($val_styp*)')
g.write('$val_styp ${c_name(node.val_var)} = (*($val_styp*)')
}
g.writeln('DenseArray_value(&$cond_var${arw_or_pt}key_values, $idx));')
}
}
g.indent--
} else if node.kind == .string {
cond := if node.cond is ast.StringLiteral || node.cond is ast.StringInterLiteral {
ast.Expr(g.new_ctemp_var_then_gen(node.cond, table.string_type))
@ -1557,6 +1568,16 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
if node.label.len > 0 {
g.writeln('\t${node.label}__continue: {}')
}
if node.kind == .map {
// diff := g.new_tmp_var()
// g.writeln('int $diff = $cond_var${arw_or_pt}key_values.len - $map_len;')
// g.writeln('if ($diff < 0) {')
// g.writeln('\t$idx = -1;')
// g.writeln('\t$map_len = $cond_var${arw_or_pt}key_values.len;')
// g.writeln('}')
}
g.writeln('}')
if node.label.len > 0 {
g.writeln('\t${node.label}__break: {}')