diff --git a/cmd/tools/bench/map_clear.v b/cmd/tools/bench/map_clear.v new file mode 100644 index 00000000000000..922fc3d1367f94 --- /dev/null +++ b/cmd/tools/bench/map_clear.v @@ -0,0 +1,19 @@ +import benchmark + +fn main() { + max_iterations := arguments()[1] or { '1_000_000' }.int() + assert max_iterations > 0 + mut m := { + 123: 456 + 789: 321 + } + mut volatile sum := u64(0) + mut b := benchmark.start() + for i in 0 .. max_iterations { + m.clear() + m[i] = i * 2 + sum += u64(m.len) + } + assert m.len == 1 + b.measure('m.clear(), iterations: ${max_iterations}, sum: ${sum}') +} diff --git a/cmd/tools/bench/map_clear_runner.vsh b/cmd/tools/bench/map_clear_runner.vsh new file mode 100755 index 00000000000000..0c82cc82fd1659 --- /dev/null +++ b/cmd/tools/bench/map_clear_runner.vsh @@ -0,0 +1,23 @@ +#!/usr/bin/env -S v -raw-vsh-tmp-prefix tmp + +import os + +const time_fmt = '"CPU: %Us\tReal: %es\tElapsed: %E\tRAM: %MKB\t%C"' +const flags = os.getenv('FLAGS') + +unbuffer_stdout() + +start := os.args[1] or { '1_000_000' }.int() +end := os.args[2] or { '10_000_000' }.int() +step := os.args[3] or { '500_000' }.int() + +os.chdir(os.dir(@VEXE))! +vcmd := 'v ${flags} cmd/tools/bench/map_clear.v' + +println('>> start: ${start} | end: ${end} | step: ${step} | workdir: "${os.getwd()}" | flags: "${flags}" | vcmd: "${vcmd}"') +assert os.system(vcmd) == 0 + +println('running...') +for i := start; i <= end; i += step { + os.system('/usr/bin/time -f ${time_fmt} cmd/tools/bench/map_clear ${i}') == 0 +} diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index a5a8a0682e98b3..2ed6e4de81da42 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -317,6 +317,14 @@ pub fn (mut m map) clear() { m.len = 0 m.even_index = 0 m.key_values.len = 0 + m.key_values.deletes = 0 + unsafe { + if m.key_values.all_deleted != 0 { + free(m.key_values.all_deleted) + } + vmemset(m.key_values.keys, 0, m.key_values.key_bytes * m.key_values.cap) + vmemset(m.metas, 0, sizeof(u32) * (m.even_index + 2 + m.extra_metas)) + } } @[inline] diff --git a/vlib/builtin/map_issue_22139_clear_test.v b/vlib/builtin/map_issue_22139_clear_test.v new file mode 100644 index 00000000000000..0c3a5da87d5be0 --- /dev/null +++ b/vlib/builtin/map_issue_22139_clear_test.v @@ -0,0 +1,59 @@ +fn test_map_clear_done_several_times() { + mut ints := map[int]int{} + + ints[5] = 5 + dump(ints.len) + assert ints.len == 1 + + ints.clear() + dump(ints.len) + assert ints.len == 0 + + ints[5] = 3 + dump(ints.len) + assert ints.len == 1 + + ints.clear() + dump(ints.len) + assert ints.len == 0 + + ints[5] = 123 + dump(ints.len) + assert ints.len == 1 +} + +fn test_map_clear_in_loop_metas_should_be_cleared_too() { + mut ints := map[int]int{} + for i in 0 .. 100 { + ints[i] = i * 123 + ints.clear() + assert ints.len == 0 + // dump(ints) + ints[i] = i + // dump(ints) + assert ints.len == 1 + ints[1000 + i] = 1000 * i + assert ints.len == 2 + } +} + +fn test_map_clear_in_loop_delete_keys() { + mut ints := map[int]int{} + for i in 0 .. 100 { + ints[i] = i * 123 + ints[i + 2] = i + ints.delete(i) + ints.delete(i + 1) + ints.delete(i + 2) + ints.delete(i + 3) + ints.delete(i + 4) + ints.clear() + assert ints.len == 0 + // dump(ints) + ints[i] = 5 + // dump(ints) + assert ints.len == 1 + ints[1000 + i] = 1000 * i + assert ints.len == 2 + } +}