Use fxhash in TypeIdMap. (#1119)
Relying on TypeId being some hash internally isn't future-proof because there is no guarantee about internal layout or structure of TypeId. I benchmarked TypeId noop hasher vs fxhash and found that there is very little difference. Also fxhash is likely to be better supported because it is widely used in rustc itself. [Benchmarks of hashers](https://github.com/bevyengine/bevy/issues/1097) [Engine wide benchmarks](https://github.com/bevyengine/bevy/pull/1119#issuecomment-751361215)
This commit is contained in:
parent
0e0906d22e
commit
9bce8712b5
@ -20,6 +20,7 @@ trace = []
|
|||||||
bevy_tasks = { path = "../bevy_tasks", version = "0.4.0" }
|
bevy_tasks = { path = "../bevy_tasks", version = "0.4.0" }
|
||||||
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
|
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
|
||||||
bevy_ecs_macros = { path = "macros", version = "0.4.0" }
|
bevy_ecs_macros = { path = "macros", version = "0.4.0" }
|
||||||
|
fxhash = "0.2"
|
||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|||||||
@ -15,14 +15,12 @@
|
|||||||
// modified by Bevy contributors
|
// modified by Bevy contributors
|
||||||
|
|
||||||
use crate::{AtomicBorrow, Component, Entity};
|
use crate::{AtomicBorrow, Component, Entity};
|
||||||
use bevy_utils::AHasher;
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use std::{
|
use std::{
|
||||||
alloc::{alloc, dealloc, Layout},
|
alloc::{alloc, dealloc, Layout},
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
cell::UnsafeCell,
|
cell::UnsafeCell,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
hash::{BuildHasherDefault, Hasher},
|
|
||||||
mem,
|
mem,
|
||||||
ptr::{self, NonNull},
|
ptr::{self, NonNull},
|
||||||
};
|
};
|
||||||
@ -557,44 +555,8 @@ fn align(x: usize, alignment: usize) -> usize {
|
|||||||
|
|
||||||
/// A hasher optimized for hashing a single TypeId.
|
/// A hasher optimized for hashing a single TypeId.
|
||||||
///
|
///
|
||||||
/// TypeId is already thoroughly hashed, so there's no reason to hash it again.
|
/// We don't use RandomState from std or Random state from Ahash
|
||||||
/// Just leave the bits unchanged.
|
/// because fxhash is [proved to be faster](https://github.com/bevyengine/bevy/pull/1119#issuecomment-751361215)
|
||||||
#[derive(Default)]
|
/// and we don't need Hash Dos attack protection here
|
||||||
pub(crate) struct TypeIdHasher {
|
/// since TypeIds generated during compilation and there is no reason to user attack himself.
|
||||||
hash: u64,
|
pub(crate) type TypeIdMap<V> = HashMap<TypeId, V, fxhash::FxBuildHasher>;
|
||||||
}
|
|
||||||
|
|
||||||
impl Hasher for TypeIdHasher {
|
|
||||||
fn write_u64(&mut self, n: u64) {
|
|
||||||
// Only a single value can be hashed, so the old hash should be zero.
|
|
||||||
debug_assert_eq!(self.hash, 0);
|
|
||||||
self.hash = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tolerate TypeId being either u64 or u128.
|
|
||||||
fn write_u128(&mut self, n: u128) {
|
|
||||||
debug_assert_eq!(self.hash, 0);
|
|
||||||
self.hash = n as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, bytes: &[u8]) {
|
|
||||||
debug_assert_eq!(self.hash, 0);
|
|
||||||
|
|
||||||
// This will only be called if TypeId is neither u64 nor u128, which is not anticipated.
|
|
||||||
// In that case we'll just fall back to using a different hash implementation.
|
|
||||||
let mut hasher = AHasher::default();
|
|
||||||
hasher.write(bytes);
|
|
||||||
self.hash = hasher.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finish(&self) -> u64 {
|
|
||||||
self.hash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A HashMap with TypeId keys
|
|
||||||
///
|
|
||||||
/// Because TypeId is already a fully-hashed u64 (including data in the high seven bits,
|
|
||||||
/// which hashbrown needs), there is no need to hash it again. Instead, this uses the much
|
|
||||||
/// faster no-op hash.
|
|
||||||
pub(crate) type TypeIdMap<V> = HashMap<TypeId, V, BuildHasherDefault<TypeIdHasher>>;
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user