| ... | @@ -1335,16 +1335,33 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -1335,16 +1335,33 @@ pub fn ArrayHashMapUnmanaged( |
| 1335 | hash.* = h; | 1335 | hash.* = h; |
| 1336 | } | 1336 | } |
| 1337 | } | 1337 | } |
| 1338 | // Rebuild the index. | 1338 | try rebuildIndex(self, gpa, ctx); |
| 1339 | if (self.entries.capacity > linear_scan_max) { | 1339 | } |
| 1340 | // We're going to rebuild the index header and replace the existing one (if any). The | 1340 | |
| 1341 | // indexes should sized such that they will be at most 60% full. | 1341 | /// Modify an entry's key without reordering any entries. |
| 1342 | const bit_index = try IndexHeader.findBitIndex(self.entries.capacity); | 1342 | pub fn setKey(self: *Self, gpa: Allocator, index: usize, new_key: K) Oom!void { |
| 1343 | const new_header = try IndexHeader.alloc(gpa, bit_index); | 1343 | if (@sizeOf(ByIndexContext) != 0) |
| 1344 | if (self.index_header) |header| header.free(gpa); | 1344 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call setKeyContext instead."); |
| 1345 | self.insertAllEntriesIntoNewHeader(if (store_hash) {} else ctx, new_header); | 1345 | return setKeyContext(self, gpa, index, new_key, undefined); |
| 1346 | self.index_header = new_header; | 1346 | } |
| 1347 | } | 1347 | |
| | 1348 | pub fn setKeyContext(self: *Self, gpa: Allocator, index: usize, new_key: K, ctx: Context) Oom!void { |
| | 1349 | const key_ptr = &self.entries.items(.key)[index]; |
| | 1350 | key_ptr.* = new_key; |
| | 1351 | if (store_hash) self.entries.items(.hash)[index].* = checkedHash(ctx, key_ptr.*); |
| | 1352 | try rebuildIndex(self, gpa, undefined); |
| | 1353 | } |
| | 1354 | |
| | 1355 | fn rebuildIndex(self: *Self, gpa: Allocator, ctx: Context) Oom!void { |
| | 1356 | if (self.entries.capacity <= linear_scan_max) return; |
| | 1357 | |
| | 1358 | // We're going to rebuild the index header and replace the existing one (if any). The |
| | 1359 | // indexes should sized such that they will be at most 60% full. |
| | 1360 | const bit_index = try IndexHeader.findBitIndex(self.entries.capacity); |
| | 1361 | const new_header = try IndexHeader.alloc(gpa, bit_index); |
| | 1362 | if (self.index_header) |header| header.free(gpa); |
| | 1363 | self.insertAllEntriesIntoNewHeader(if (store_hash) {} else ctx, new_header); |
| | 1364 | self.index_header = new_header; |
| 1348 | } | 1365 | } |
| 1349 | | 1366 | |
| 1350 | /// Sorts the entries and then rebuilds the index. | 1367 | /// Sorts the entries and then rebuilds the index. |
| ... | @@ -2530,6 +2547,22 @@ test "0 sized key and 0 sized value" { | ... | @@ -2530,6 +2547,22 @@ test "0 sized key and 0 sized value" { |
| 2530 | try testing.expectEqual(map.get(0), null); | 2547 | try testing.expectEqual(map.get(0), null); |
| 2531 | } | 2548 | } |
| 2532 | | 2549 | |
| | 2550 | test "setKey" { |
| | 2551 | const gpa = std.testing.allocator; |
| | 2552 | |
| | 2553 | var map: AutoArrayHashMapUnmanaged(i32, i32) = .empty; |
| | 2554 | defer map.deinit(gpa); |
| | 2555 | |
| | 2556 | try map.put(gpa, 12, 34); |
| | 2557 | try map.put(gpa, 56, 78); |
| | 2558 | |
| | 2559 | try map.setKey(gpa, 0, 42); |
| | 2560 | try testing.expectEqual(2, map.count()); |
| | 2561 | try testing.expectEqual(false, map.contains(12)); |
| | 2562 | try testing.expectEqual(34, map.get(42)); |
| | 2563 | try testing.expectEqual(78, map.get(56)); |
| | 2564 | } |
| | 2565 | |
| 2533 | pub fn getHashPtrAddrFn(comptime K: type, comptime Context: type) (fn (Context, K) u32) { | 2566 | pub fn getHashPtrAddrFn(comptime K: type, comptime Context: type) (fn (Context, K) u32) { |
| 2534 | return struct { | 2567 | return struct { |
| 2535 | fn hash(ctx: Context, key: K) u32 { | 2568 | fn hash(ctx: Context, key: K) u32 { |