| ... | @@ -629,6 +629,13 @@ pub fn HashMap( | ... | @@ -629,6 +629,13 @@ pub fn HashMap( |
| 629 | return self.unmanaged.removeAdapted(key, ctx); | 629 | return self.unmanaged.removeAdapted(key, ctx); |
| 630 | } | 630 | } |
| 631 | | 631 | |
| | 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 | |
| 632 | /// Creates a copy of this map, using the same allocator | 639 | /// Creates a copy of this map, using the same allocator |
| 633 | pub fn clone(self: Self) !Self { | 640 | pub fn clone(self: Self) !Self { |
| 634 | var other = try self.unmanaged.cloneContext(self.allocator, self.ctx); | 641 | var other = try self.unmanaged.cloneContext(self.allocator, self.ctx); |
| ... | @@ -1377,6 +1384,14 @@ pub fn HashMapUnmanaged( | ... | @@ -1377,6 +1384,14 @@ pub fn HashMapUnmanaged( |
| 1377 | return self.getIndex(key, ctx) != null; | 1384 | return self.getIndex(key, ctx) != null; |
| 1378 | } | 1385 | } |
| 1379 | | 1386 | |
| | 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 | |
| 1380 | /// If there is an `Entry` with a matching key, it is deleted from | 1395 | /// If there is an `Entry` with a matching key, it is deleted from |
| 1381 | /// the hash map, and this function returns true. Otherwise this | 1396 | /// the hash map, and this function returns true. Otherwise this |
| 1382 | /// function returns false. | 1397 | /// function returns false. |
| ... | @@ -1390,17 +1405,29 @@ pub fn HashMapUnmanaged( | ... | @@ -1390,17 +1405,29 @@ pub fn HashMapUnmanaged( |
| 1390 | } | 1405 | } |
| 1391 | pub fn removeAdapted(self: *Self, key: anytype, ctx: anytype) bool { | 1406 | pub fn removeAdapted(self: *Self, key: anytype, ctx: anytype) bool { |
| 1392 | if (self.getIndex(key, ctx)) |idx| { | 1407 | if (self.getIndex(key, ctx)) |idx| { |
| 1393 | self.metadata.?[idx].remove(); | 1408 | self.removeByIndex(idx); |
| 1394 | self.keys()[idx] = undefined; | | |
| 1395 | self.values()[idx] = undefined; | | |
| 1396 | self.size -= 1; | | |
| 1397 | self.available += 1; | | |
| 1398 | return true; | 1409 | return true; |
| 1399 | } | 1410 | } |
| 1400 | | 1411 | |
| 1401 | return false; | 1412 | return false; |
| 1402 | } | 1413 | } |
| 1403 | | 1414 | |
| | 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 | |
| 1404 | fn initMetadatas(self: *Self) void { | 1431 | fn initMetadatas(self: *Self) void { |
| 1405 | @memset(@ptrCast([*]u8, self.metadata.?), 0, @sizeOf(Metadata) * self.capacity()); | 1432 | @memset(@ptrCast([*]u8, self.metadata.?), 0, @sizeOf(Metadata) * self.capacity()); |
| 1406 | } | 1433 | } |
| ... | @@ -2082,3 +2109,47 @@ test "std.hash_map ensureUnusedCapacity" { | ... | @@ -2082,3 +2109,47 @@ test "std.hash_map ensureUnusedCapacity" { |
| 2082 | // should not change the capacity. | 2109 | // should not change the capacity. |
| 2083 | try testing.expectEqual(capacity, map.capacity()); | 2110 | try testing.expectEqual(capacity, map.capacity()); |
| 2084 | } | 2111 | } |
| | 2112 | |
| | 2113 | test "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 | |
| | 2139 | test "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 | } |