Skip to content

Commit 2eb0f56

Browse files
committed
Tweak the structure slightly for some extra clarity
(No functional difference; just rearranged.)
1 parent 5c48fd7 commit 2eb0f56

File tree

1 file changed

+20
-9
lines changed

1 file changed

+20
-9
lines changed

crates/bevy_utils/src/lib.rs

+20-9
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ impl BuildHasher for EntityHash {
275275
/// try [`AHasher`] for a slower hash computation but fewer lookup conflicts.
276276
#[derive(Debug, Default)]
277277
pub struct EntityHasher {
278-
hash: u64,
278+
index: u32,
279279
}
280280

281281
impl Hasher for EntityHasher {
@@ -285,6 +285,23 @@ impl Hasher for EntityHasher {
285285

286286
#[inline]
287287
fn write_u64(&mut self, i: u64) {
288+
// We ignore the generation entirely. It's always functionally correct
289+
// to omit things when hashing, so long as it's consistent, just a perf
290+
// trade-off. This hasher is designed for "normal" cases, where nearly
291+
// everything in the table is a live entity, meaning there are few
292+
// generation conflicts. And thus it's overall faster to just ignore
293+
// the generation during hashing, leaving it to the `Entity::eq` to
294+
// confirm the generation matches -- just like `Entity::eq` checks that
295+
// the index is actually the right one, since there's always the chance
296+
// of a conflict in the index despite a good hash function.
297+
//
298+
// This truncation actually ends up with negative cost after optimization,
299+
// as the optimizer will just skip loading the generation at all.
300+
self.index = i as u32;
301+
}
302+
303+
#[inline]
304+
fn finish(&self) -> u64 {
288305
// SwissTable (and thus `hashbrown`) cares about two things from the hash:
289306
// - H1: low bits (masked by `2ⁿ-1`) to pick the slot in which to store the item
290307
// - H2: high 7 bits are used to SIMD optimize hash collision probing
@@ -302,16 +319,10 @@ impl Hasher for EntityHasher {
302319
// <https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences/>
303320
// It loses no information because it has a modular inverse.
304321
// (Specifically, `0x144c_bc89_u32 * 0x9e37_79b9_u32 == 1`.)
322+
//
305323
// The low 32 bits are just 1, to leave the entity id there unchanged.
306324
const UPPER_PHI: u64 = 0x9e37_79b9_0000_0001;
307-
// This bit-masking is free, as the optimizer can just not load the generation.
308-
let id = i & 0xFFFF_FFFF;
309-
self.hash = id.wrapping_mul(UPPER_PHI);
310-
}
311-
312-
#[inline]
313-
fn finish(&self) -> u64 {
314-
self.hash
325+
u64::from(self.index).wrapping_mul(UPPER_PHI)
315326
}
316327
}
317328

0 commit comments

Comments
 (0)