Merge pull request #7182 from BigBoyBarney/shrink

Follow up fix of `shrink_map`
This commit is contained in:
Jeroen van Rijn
2026-08-01 13:51:37 +02:00
committed by GitHub
2 changed files with 26 additions and 7 deletions

View File

@@ -584,24 +584,30 @@ map_shrink_dynamic :: #force_no_inline proc "odin" (#no_alias m: ^Raw_Map, #no_a
}
// Don't shrink below the minimum.
log2_capacity := map_log2_cap(m^)
if log2_capacity <= MAP_MIN_LOG2_CAPACITY {
log2_capacity_current := map_log2_cap(m^)
if log2_capacity_current <= MAP_MIN_LOG2_CAPACITY {
return false, nil
}
// Cannot shrink the capacity if the number of items in the map would exceed
// one minus the current log2 capacity's resize threshold. That is the shrunk
// map needs to be within the max load factor.
load_factor := map_load_factor(log2_capacity - 1)
if m.len >= load_factor {
load_factor_new_max := map_load_factor(log2_capacity_current - 1)
if m.len >= load_factor_new_max {
return false, nil
}
log2_capacity = max(__ceil_log2(m.len), MAP_MIN_LOG2_CAPACITY)
log2_capacity_new := max(__ceil_log2(m.len), MAP_MIN_LOG2_CAPACITY)
load_factor_new := map_load_factor(log2_capacity_new)
shrunk := map_alloc_dynamic(info, log2_capacity, m.allocator) or_return
// The new log2 capacity's load factor needs to contain the current map as well.
if m.len > load_factor_new {
log2_capacity_new += 1
}
capacity := uintptr(1) << log2_capacity
shrunk := map_alloc_dynamic(info, log2_capacity_new, m.allocator) or_return
capacity := uintptr(1) << log2_capacity_new
ks, vs, hs, _, _ := map_kvh_data_dynamic(m^, info)

View File

@@ -234,6 +234,19 @@ map_shrink :: proc(t: ^testing.T) {
testing.expect_value(t, err, runtime.Allocator_Error.None)
testing.expect_value(t, cap(m), 128)
}
{
reserve(&m, 256)
for i in 0 ..< 50 {
m[i] = i
}
did_shrink, err := shrink(&m)
testing.expect_value(t, did_shrink, true)
testing.expect_value(t, err, runtime.Allocator_Error.None)
testing.expect_value(t, cap(m), 128)
}
}
@test