authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-11-11 00:01:40+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-11 19:32:58-07:00
logb6350a2b3f5c92ff4f0db152684f9c55bedb0bf6
tree0fbc970e9cf7437404295fba1060215eb43ea88c
parent8c62733927b0b0785b6ed951a2a239102c6ca95b

std: fix HashMap.putAssumeCapacity


1 files changed, 35 insertions(+), 34 deletions(-)

lib/std/hash_map.zig+35-34
...@@ -468,41 +468,12 @@ pub fn HashMapUnmanaged(...@@ -468,41 +468,12 @@ pub fn HashMapUnmanaged(
468 self.putAssumeCapacityNoClobber(key, value);468 self.putAssumeCapacityNoClobber(key, value);
469 }469 }
470470
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 pub fn putAssumeCapacity(self: *Self, key: K, value: V) void {474 pub fn putAssumeCapacity(self: *Self, key: K, value: V) void {
472 const hash = hashFn(key);475 const gop = self.getOrPutAssumeCapacity(key);
473 const mask = self.capacity() - 1;476 gop.entry.value = value;
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;
506 }477 }
507478
508 /// Insert an entry in the map. Assumes it is not already present,479 /// Insert an entry in the map. Assumes it is not already present,
...@@ -1148,6 +1119,36 @@ test "std.hash_map put" {...@@ -1148,6 +1119,36 @@ test "std.hash_map put" {
1148 }1119 }
1149}1120}
11501121
1122test "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
1151test "std.hash_map getOrPut" {1152test "std.hash_map getOrPut" {
1152 var map = AutoHashMap(u32, u32).init(std.testing.allocator);1153 var map = AutoHashMap(u32, u32).init(std.testing.allocator);
1153 defer map.deinit();1154 defer map.deinit();