From f04e65bc09ab77eafc317b2d2981970509aae6af Mon Sep 17 00:00:00 2001 From: sentientwaffle Date: Fri, 9 Jun 2023 12:52:36 -0700 Subject: [PATCH] std.hash_map: fetchRemove increment available To avoid leaking slots, `fetchRemove` must increment `available` (when the "fetch" succeeds). Without the `available += 1`, the added test `"std.hash_map repeat fetchRemove"` fails with run test std-x86-linux-none-Debug: error: thread 432734 panic: integer overflow .../zig/lib/std/hash_map.zig:1365:28: 0x6471d5 in getOrPutAssumeCapacityAdapted__anon_47495 (test) self.available -= 1; ^ .../zig/lib/std/hash_map.zig:1308:62: 0x616950 in getOrPutAssumeCapacityContext (test) const result = self.getOrPutAssumeCapacityAdapted(key, ctx); ^ Alternatively, `fetchRemove` could call `removeByIndex`, though that would entail calling `header()` twice instead of once. --- lib/std/hash_map.zig | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/std/hash_map.zig b/lib/std/hash_map.zig index 50ff2f0c94..041d99606e 100644 --- a/lib/std/hash_map.zig +++ b/lib/std/hash_map.zig @@ -1113,6 +1113,7 @@ pub fn HashMapUnmanaged( old_key.* = undefined; old_val.* = undefined; self.size -= 1; + self.available += 1; return result; } @@ -2193,3 +2194,27 @@ test "std.hash_map removeByPtr 0 sized key" { try testing.expect(map.count() == 0); } + +test "std.hash_map repeat fetchRemove" { + var map = AutoHashMapUnmanaged(u64, void){}; + defer map.deinit(testing.allocator); + + try map.ensureTotalCapacity(testing.allocator, 4); + + map.putAssumeCapacity(0, {}); + map.putAssumeCapacity(1, {}); + map.putAssumeCapacity(2, {}); + map.putAssumeCapacity(3, {}); + + // fetchRemove() should make slots available. + var i: usize = 0; + while (i < 10) : (i += 1) { + try testing.expect(map.fetchRemove(3) != null); + map.putAssumeCapacity(3, {}); + } + + try testing.expect(map.get(0) != null); + try testing.expect(map.get(1) != null); + try testing.expect(map.get(2) != null); + try testing.expect(map.get(3) != null); +}