gen: more efficient `for in` with a map (#6961)
							parent
							
								
									5e59718970
								
							
						
					
					
						commit
						ea8adfdbf9
					
				| 
						 | 
					@ -1173,33 +1173,34 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
 | 
				
			||||||
	} else if it.kind == .map {
 | 
						} else if it.kind == .map {
 | 
				
			||||||
		// `for key, val in map {`
 | 
							// `for key, val in map {`
 | 
				
			||||||
		g.writeln('// FOR 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()
 | 
							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 := g.new_tmp_var()
 | 
				
			||||||
		atmp_styp := g.typ(it.cond_type)
 | 
							atmp_styp := g.typ(it.cond_type)
 | 
				
			||||||
		g.write('$atmp_styp $atmp = ')
 | 
							g.write('$atmp_styp $atmp = ')
 | 
				
			||||||
		g.expr(it.cond)
 | 
							g.expr(it.cond)
 | 
				
			||||||
		g.writeln(';')
 | 
							g.writeln(';')
 | 
				
			||||||
		g.writeln('array_$key_styp $keys_tmp = map_keys(&$atmp);')
 | 
							g.writeln('for (int $idx = 0; $idx < $atmp\.key_values.len; ++$idx) {')
 | 
				
			||||||
		g.writeln('for (int $idx = 0; $idx < ${keys_tmp}.len; ++$idx) {')
 | 
							g.writeln('\tif ($atmp\.key_values.keys[$idx].str == 0) {continue;}')
 | 
				
			||||||
		// TODO: analyze whether it.key_type has a .clone() method and call .clone() for all types:
 | 
							if it.key_var != '_' {
 | 
				
			||||||
		if it.key_type == table.string_type {
 | 
								key_styp := g.typ(it.key_type)
 | 
				
			||||||
			g.writeln('\t$key_styp $key = /*kkkk*/ string_clone( (($key_styp*)${keys_tmp}.data)[$idx] );')
 | 
								key := c_name(it.key_var)
 | 
				
			||||||
		} else {
 | 
								// TODO: analyze whether it.key_type has a .clone() method and call .clone() for all types:
 | 
				
			||||||
			g.writeln('\t$key_styp $key = /*kkkk*/ (($key_styp*)${keys_tmp}.data)[$idx];')
 | 
								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 != '_' {
 | 
							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 {
 | 
								if val_sym.kind == .function {
 | 
				
			||||||
				g.write('\t')
 | 
									g.write('\t')
 | 
				
			||||||
				g.write_fn_ptr_decl(val_sym.info as table.FnType, c_name(it.val_var))
 | 
									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 {
 | 
								} 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)
 | 
							g.stmts(it.stmts)
 | 
				
			||||||
| 
						 | 
					@ -1213,9 +1214,6 @@ fn (mut g Gen) for_in(it ast.ForInStmt) {
 | 
				
			||||||
		if it.label.len > 0 {
 | 
							if it.label.len > 0 {
 | 
				
			||||||
			g.writeln('\t$it.label\__break: {}')
 | 
								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
 | 
							return
 | 
				
			||||||
	} else if it.cond_type.has_flag(.variadic) {
 | 
						} else if it.cond_type.has_flag(.variadic) {
 | 
				
			||||||
		g.writeln('// FOR IN cond_type/variadic')
 | 
							g.writeln('// FOR IN cond_type/variadic')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,9 +103,11 @@ fn test_for_in_map_val() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn test_for_in_map_both() {
 | 
					fn test_for_in_map_both() {
 | 
				
			||||||
 | 
						mut i := 0
 | 
				
			||||||
	for _, _ in m {
 | 
						for _, _ in m {
 | 
				
			||||||
		assert true
 | 
							i++
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						assert i == 1
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn test_nested_for_in_map_key() {
 | 
					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() {
 | 
					fn test_nested_for_in_map_both() {
 | 
				
			||||||
 | 
						mut i := 0
 | 
				
			||||||
	for _, _ in m {
 | 
						for _, _ in m {
 | 
				
			||||||
		for _, _ in m {
 | 
							for _, _ in m {
 | 
				
			||||||
			assert true
 | 
								i++
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						assert i == 1
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn fn_for_in_variadic_args_simple(arr ...string) {
 | 
					fn fn_for_in_variadic_args_simple(arr ...string) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,16 +43,24 @@ fn test_for_char_in_string() {
 | 
				
			||||||
	assert sum == 394 // ascii codes of `a` + `b` + `c` + `d`
 | 
						assert sum == 394 // ascii codes of `a` + `b` + `c` + `d`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn test_for_char_in_map() {
 | 
					fn test_for_string_in_map() {
 | 
				
			||||||
	m := {
 | 
						m := {
 | 
				
			||||||
		'a': 'b'
 | 
							'a': 'b'
 | 
				
			||||||
		'c': 'd'
 | 
							'c': 'd'
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mut acc := ''
 | 
						mut acc := ''
 | 
				
			||||||
	for k, char in m {
 | 
						for k, v in m {
 | 
				
			||||||
		acc += '$k: $char, '
 | 
							acc += '$k: $v, '
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	assert acc == 'a: b, c: d, '
 | 
						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() {
 | 
					fn test_mut_for() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue