authorgravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2021-05-12 19:39:36+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-14 15:15:55-04:00
log2d4d4baa42590803cff8581add325ea3f102ac2a
tree9f14b2d55c76a71fa7b9ec0c565cfe64ed3be103
parent8b4e91e18ce425902bef726ec3731d266867a6f7

std.hash_map: use 7 bits of metadata instead of 6

we only effectively need 1 control bit to represent 2 special states for the metadata (free and tombstone) this should reduce the number of actual element equality tests, but since it's very low already, the impact is negligible

1 files changed, 13 insertions(+), 12 deletions(-)

lib/std/hash_map.zig+13-12
......@@ -304,29 +304,32 @@ pub fn HashMapUnmanaged(
304304 /// Metadata for a slot. It can be in three states: empty, used or
305305 /// tombstone. Tombstones indicate that an entry was previously used,
306306 /// they are a simple way to handle removal.
307 /// To this state, we add 6 bits from the slot's key hash. These are
307 /// To this state, we add 7 bits from the slot's key hash. These are
308308 /// used as a fast way to disambiguate between entries without
309309 /// having to use the equality function. If two fingerprints are
310310 /// different, we know that we don't have to compare the keys at all.
311 /// The 6 bits are the highest ones from a 64 bit hash. This way, not
311 /// The 7 bits are the highest ones from a 64 bit hash. This way, not
312312 /// only we use the `log2(capacity)` lowest bits from the hash to determine
313 /// a slot index, but we use 6 more bits to quickly resolve collisions
314 /// when multiple elements with different hashes end up wanting to be in / the same slot.
313 /// a slot index, but we use 7 more bits to quickly resolve collisions
314 /// when multiple elements with different hashes end up wanting to be in the same slot.
315315 /// Not using the equality function means we don't have to read into
316 /// the entries array, avoiding a likely cache miss.
316 /// the entries array, likely avoiding a cache miss and a potentially
317 /// costly function call.
317318 const Metadata = packed struct {
318 const FingerPrint = u6;
319 const FingerPrint = u7;
319320
321 const free: FingerPrint = 0;
322 const tombstone: FingerPrint = 1;
323
324 fingerprint: FingerPrint = free,
320325 used: u1 = 0,
321 tombstone: u1 = 0,
322 fingerprint: FingerPrint = 0,
323326
324327 pub fn isUsed(self: Metadata) bool {
325328 return self.used == 1;
326329 }
327330
328331 pub fn isTombstone(self: Metadata) bool {
329 return self.tombstone == 1;
332 return !self.isUsed() and self.fingerprint == tombstone;
330333 }
331334
332335 pub fn takeFingerprint(hash: Hash) FingerPrint {
......@@ -337,14 +340,12 @@ pub fn HashMapUnmanaged(
337340
338341 pub fn fill(self: *Metadata, fp: FingerPrint) void {
339342 self.used = 1;
340 self.tombstone = 0;
341343 self.fingerprint = fp;
342344 }
343345
344346 pub fn remove(self: *Metadata) void {
345347 self.used = 0;
346 self.tombstone = 1;
347 self.fingerprint = 0;
348 self.fingerprint = tombstone;
348349 }
349350 };
350351