authorgravatar for 94326797+riverbl@users.noreply.github.comriverbl <94326797+riverbl@users.noreply.github.com> 2021-11-15 12:54:14+00:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-01-24 20:29:05+02:00
loga0732117d07f9dc9b8afb457d935ca84411ec233
tree87686b97e90207d48d3485d10bfef813700a5739
parent15ef251a153de7f4985c1a87bf7706dde0e27306

HashMap: add removeByPtr


1 files changed, 76 insertions(+), 5 deletions(-)

lib/std/hash_map.zig+76-5
......@@ -629,6 +629,13 @@ pub fn HashMap(
629629 return self.unmanaged.removeAdapted(key, ctx);
630630 }
631631
632 /// Delete the entry with key pointed to by keyPtr from the hash map.
633 /// keyPtr is assumed to be a valid pointer to a key that is present
634 /// in the hash map.
635 pub fn removeByPtr(self: *Self, keyPtr: *K) void {
636 self.unmanaged.removeByPtr(keyPtr);
637 }
638
632639 /// Creates a copy of this map, using the same allocator
633640 pub fn clone(self: Self) !Self {
634641 var other = try self.unmanaged.cloneContext(self.allocator, self.ctx);
......@@ -1377,6 +1384,14 @@ pub fn HashMapUnmanaged(
13771384 return self.getIndex(key, ctx) != null;
13781385 }
13791386
1387 fn removeByIndex(self: *Self, idx: usize) void {
1388 self.metadata.?[idx].remove();
1389 self.keys()[idx] = undefined;
1390 self.values()[idx] = undefined;
1391 self.size -= 1;
1392 self.available += 1;
1393 }
1394
13801395 /// If there is an `Entry` with a matching key, it is deleted from
13811396 /// the hash map, and this function returns true. Otherwise this
13821397 /// function returns false.
......@@ -1390,17 +1405,29 @@ pub fn HashMapUnmanaged(
13901405 }
13911406 pub fn removeAdapted(self: *Self, key: anytype, ctx: anytype) bool {
13921407 if (self.getIndex(key, ctx)) |idx| {
1393 self.metadata.?[idx].remove();
1394 self.keys()[idx] = undefined;
1395 self.values()[idx] = undefined;
1396 self.size -= 1;
1397 self.available += 1;
1408 self.removeByIndex(idx);
13981409 return true;
13991410 }
14001411
14011412 return false;
14021413 }
14031414
1415 /// Delete the entry with key pointed to by keyPtr from the hash map.
1416 /// keyPtr is assumed to be a valid pointer to a key that is present
1417 /// in the hash map.
1418 pub fn removeByPtr(self: *Self, keyPtr: *K) void {
1419 // TODO: replace with pointer subtraction once supported by zig
1420 // if @sizeOf(K) == 0 then there is at most one item in the hash
1421 // map, which is assumed to exist as keyPtr must be valid. This
1422 // item must be at index 0.
1423 const idx = if (@sizeOf(K) > 0)
1424 (@ptrToInt(keyPtr) - @ptrToInt(self.keys())) / @sizeOf(K)
1425 else
1426 0;
1427
1428 self.removeByIndex(idx);
1429 }
1430
14041431 fn initMetadatas(self: *Self) void {
14051432 @memset(@ptrCast([*]u8, self.metadata.?), 0, @sizeOf(Metadata) * self.capacity());
14061433 }
......@@ -2082,3 +2109,47 @@ test "std.hash_map ensureUnusedCapacity" {
20822109 // should not change the capacity.
20832110 try testing.expectEqual(capacity, map.capacity());
20842111}
2112
2113test "std.hash_map removeByPtr" {
2114 var map = AutoHashMap(i32, u64).init(testing.allocator);
2115 defer map.deinit();
2116
2117 var i: i32 = undefined;
2118
2119 i = 0;
2120 while (i < 10) : (i += 1) {
2121 try map.put(i, 0);
2122 }
2123
2124 try testing.expect(map.count() == 10);
2125
2126 i = 0;
2127 while (i < 10) : (i += 1) {
2128 const keyPtr = map.getKeyPtr(i);
2129 try testing.expect(keyPtr != null);
2130
2131 if (keyPtr) |ptr| {
2132 map.removeByPtr(ptr);
2133 }
2134 }
2135
2136 try testing.expect(map.count() == 0);
2137}
2138
2139test "std.hash_map removeByPtr 0 sized key" {
2140 var map = AutoHashMap(u0, u64).init(testing.allocator);
2141 defer map.deinit();
2142
2143 try map.put(0, 0);
2144
2145 try testing.expect(map.count() == 1);
2146
2147 const keyPtr = map.getKeyPtr(0);
2148 try testing.expect(keyPtr != null);
2149
2150 if (keyPtr) |ptr| {
2151 map.removeByPtr(ptr);
2152 }
2153
2154 try testing.expect(map.count() == 0);
2155}