std: fix HashMap.putAssumeCapacity

This commit is contained in:
Vexu 2020-11-11 00:01:40 +02:00
parent 06a3a69e6f
commit f70160f89c
No known key found for this signature in database
GPG key ID: 59AEB8936E16A6AC

View file

@ -468,41 +468,12 @@ pub fn HashMapUnmanaged(
self.putAssumeCapacityNoClobber(key, value);
}
/// Asserts there is enough capacity to store the new key-value pair.
/// Clobbers any existing data. To detect if a put would clobber
/// existing data, see `getOrPutAssumeCapacity`.
pub fn putAssumeCapacity(self: *Self, key: K, value: V) void {
const hash = hashFn(key);
const mask = self.capacity() - 1;
const fingerprint = Metadata.takeFingerprint(hash);
var idx = @truncate(usize, hash & mask);
var first_tombstone_idx: usize = self.capacity(); // invalid index
var metadata = self.metadata.? + idx;
while (metadata[0].isUsed() or metadata[0].isTombstone()) {
if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) {
const entry = &self.entries()[idx];
if (eqlFn(entry.key, key)) {
return;
}
} else if (first_tombstone_idx == self.capacity() and metadata[0].isTombstone()) {
first_tombstone_idx = idx;
}
idx = (idx + 1) & mask;
metadata = self.metadata.? + idx;
}
if (first_tombstone_idx < self.capacity()) {
// Cheap try to lower probing lengths after deletions. Recycle a tombstone.
idx = first_tombstone_idx;
metadata = self.metadata.? + idx;
} else {
// We're using a slot previously free.
self.available -= 1;
}
metadata[0].fill(fingerprint);
const entry = &self.entries()[idx];
entry.* = .{ .key = key, .value = undefined };
self.size += 1;
const gop = self.getOrPutAssumeCapacity(key);
gop.entry.value = value;
}
/// Insert an entry in the map. Assumes it is not already present,
@ -1148,6 +1119,36 @@ test "std.hash_map put" {
}
}
test "std.hash_map putAssumeCapacity" {
var map = AutoHashMap(u32, u32).init(std.testing.allocator);
defer map.deinit();
try map.ensureCapacity(20);
var i: u32 = 0;
while (i < 20) : (i += 1) {
map.putAssumeCapacityNoClobber(i, i);
}
i = 0;
var sum = i;
while (i < 20) : (i += 1) {
sum += map.get(i).?;
}
expectEqual(sum, 190);
i = 0;
while (i < 20) : (i += 1) {
map.putAssumeCapacity(i, 1);
}
i = 0;
sum = i;
while (i < 20) : (i += 1) {
sum += map.get(i).?;
}
expectEqual(sum, 20);
}
test "std.hash_map getOrPut" {
var map = AutoHashMap(u32, u32).init(std.testing.allocator);
defer map.deinit();