map: fix delete in for-in (#9336)
							parent
							
								
									149151b1e8
								
							
						
					
					
						commit
						2991cad4e8
					
				| 
						 | 
				
			
			@ -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'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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: {}')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue