| ... | @@ -304,29 +304,32 @@ pub fn HashMapUnmanaged( | ... | @@ -304,29 +304,32 @@ pub fn HashMapUnmanaged( |
| 304 | /// Metadata for a slot. It can be in three states: empty, used or | 304 | /// Metadata for a slot. It can be in three states: empty, used or |
| 305 | /// tombstone. Tombstones indicate that an entry was previously used, | 305 | /// tombstone. Tombstones indicate that an entry was previously used, |
| 306 | /// they are a simple way to handle removal. | 306 | /// 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 |
| 308 | /// used as a fast way to disambiguate between entries without | 308 | /// used as a fast way to disambiguate between entries without |
| 309 | /// having to use the equality function. If two fingerprints are | 309 | /// having to use the equality function. If two fingerprints are |
| 310 | /// different, we know that we don't have to compare the keys at all. | 310 | /// 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 |
| 312 | /// only we use the `log2(capacity)` lowest bits from the hash to determine | 312 | /// 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 | 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. | 314 | /// when multiple elements with different hashes end up wanting to be in the same slot. |
| 315 | /// Not using the equality function means we don't have to read into | 315 | /// 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. |
| 317 | const Metadata = packed struct { | 318 | const Metadata = packed struct { |
| 318 | const FingerPrint = u6; | 319 | const FingerPrint = u7; |
| 319 | | 320 | |
| | 321 | const free: FingerPrint = 0; |
| | 322 | const tombstone: FingerPrint = 1; |
| | 323 | |
| | 324 | fingerprint: FingerPrint = free, |
| 320 | used: u1 = 0, | 325 | used: u1 = 0, |
| 321 | tombstone: u1 = 0, | | |
| 322 | fingerprint: FingerPrint = 0, | | |
| 323 | | 326 | |
| 324 | pub fn isUsed(self: Metadata) bool { | 327 | pub fn isUsed(self: Metadata) bool { |
| 325 | return self.used == 1; | 328 | return self.used == 1; |
| 326 | } | 329 | } |
| 327 | | 330 | |
| 328 | pub fn isTombstone(self: Metadata) bool { | 331 | pub fn isTombstone(self: Metadata) bool { |
| 329 | return self.tombstone == 1; | 332 | return !self.isUsed() and self.fingerprint == tombstone; |
| 330 | } | 333 | } |
| 331 | | 334 | |
| 332 | pub fn takeFingerprint(hash: Hash) FingerPrint { | 335 | pub fn takeFingerprint(hash: Hash) FingerPrint { |
| ... | @@ -337,14 +340,12 @@ pub fn HashMapUnmanaged( | ... | @@ -337,14 +340,12 @@ pub fn HashMapUnmanaged( |
| 337 | | 340 | |
| 338 | pub fn fill(self: *Metadata, fp: FingerPrint) void { | 341 | pub fn fill(self: *Metadata, fp: FingerPrint) void { |
| 339 | self.used = 1; | 342 | self.used = 1; |
| 340 | self.tombstone = 0; | | |
| 341 | self.fingerprint = fp; | 343 | self.fingerprint = fp; |
| 342 | } | 344 | } |
| 343 | | 345 | |
| 344 | pub fn remove(self: *Metadata) void { | 346 | pub fn remove(self: *Metadata) void { |
| 345 | self.used = 0; | 347 | self.used = 0; |
| 346 | self.tombstone = 1; | 348 | self.fingerprint = tombstone; |
| 347 | self.fingerprint = 0; | | |
| 348 | } | 349 | } |
| 349 | }; | 350 | }; |
| 350 | | 351 | |