| ... | ... | @@ -468,41 +468,12 @@ pub fn HashMapUnmanaged( |
| 468 | 468 | self.putAssumeCapacityNoClobber(key, value); |
| 469 | 469 | } |
| 470 | 470 | |
| 471 | /// Asserts there is enough capacity to store the new key-value pair. |
| 472 | /// Clobbers any existing data. To detect if a put would clobber |
| 473 | /// existing data, see `getOrPutAssumeCapacity`. |
| 471 | 474 | pub fn putAssumeCapacity(self: *Self, key: K, value: V) void { |
| 472 | | const hash = hashFn(key); |
| 473 | | const mask = self.capacity() - 1; |
| 474 | | const fingerprint = Metadata.takeFingerprint(hash); |
| 475 | | var idx = @truncate(usize, hash & mask); |
| 476 | | |
| 477 | | var first_tombstone_idx: usize = self.capacity(); // invalid index |
| 478 | | var metadata = self.metadata.? + idx; |
| 479 | | while (metadata[0].isUsed() or metadata[0].isTombstone()) { |
| 480 | | if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { |
| 481 | | const entry = &self.entries()[idx]; |
| 482 | | if (eqlFn(entry.key, key)) { |
| 483 | | return; |
| 484 | | } |
| 485 | | } else if (first_tombstone_idx == self.capacity() and metadata[0].isTombstone()) { |
| 486 | | first_tombstone_idx = idx; |
| 487 | | } |
| 488 | | |
| 489 | | idx = (idx + 1) & mask; |
| 490 | | metadata = self.metadata.? + idx; |
| 491 | | } |
| 492 | | |
| 493 | | if (first_tombstone_idx < self.capacity()) { |
| 494 | | // Cheap try to lower probing lengths after deletions. Recycle a tombstone. |
| 495 | | idx = first_tombstone_idx; |
| 496 | | metadata = self.metadata.? + idx; |
| 497 | | } else { |
| 498 | | // We're using a slot previously free. |
| 499 | | self.available -= 1; |
| 500 | | } |
| 501 | | |
| 502 | | metadata[0].fill(fingerprint); |
| 503 | | const entry = &self.entries()[idx]; |
| 504 | | entry.* = .{ .key = key, .value = undefined }; |
| 505 | | self.size += 1; |
| 475 | const gop = self.getOrPutAssumeCapacity(key); |
| 476 | gop.entry.value = value; |
| 506 | 477 | } |
| 507 | 478 | |
| 508 | 479 | /// Insert an entry in the map. Assumes it is not already present, |
| ... | ... | @@ -1148,6 +1119,36 @@ test "std.hash_map put" { |
| 1148 | 1119 | } |
| 1149 | 1120 | } |
| 1150 | 1121 | |
| 1122 | test "std.hash_map putAssumeCapacity" { |
| 1123 | var map = AutoHashMap(u32, u32).init(std.testing.allocator); |
| 1124 | defer map.deinit(); |
| 1125 | |
| 1126 | try map.ensureCapacity(20); |
| 1127 | var i: u32 = 0; |
| 1128 | while (i < 20) : (i += 1) { |
| 1129 | map.putAssumeCapacityNoClobber(i, i); |
| 1130 | } |
| 1131 | |
| 1132 | i = 0; |
| 1133 | var sum = i; |
| 1134 | while (i < 20) : (i += 1) { |
| 1135 | sum += map.get(i).?; |
| 1136 | } |
| 1137 | expectEqual(sum, 190); |
| 1138 | |
| 1139 | i = 0; |
| 1140 | while (i < 20) : (i += 1) { |
| 1141 | map.putAssumeCapacity(i, 1); |
| 1142 | } |
| 1143 | |
| 1144 | i = 0; |
| 1145 | sum = i; |
| 1146 | while (i < 20) : (i += 1) { |
| 1147 | sum += map.get(i).?; |
| 1148 | } |
| 1149 | expectEqual(sum, 20); |
| 1150 | } |
| 1151 | |
| 1151 | 1152 | test "std.hash_map getOrPut" { |
| 1152 | 1153 | var map = AutoHashMap(u32, u32).init(std.testing.allocator); |
| 1153 | 1154 | defer map.deinit(); |