diff --git a/src/atom.rs b/src/atom.rs index 31dafd2..a43f584 100644 --- a/src/atom.rs +++ b/src/atom.rs @@ -211,18 +211,14 @@ impl Atom { } pub fn try_static(string_to_add: &str) -> Option { - Self::try_static_internal(string_to_add).ok() - } - - fn try_static_internal(string_to_add: &str) -> Result { let static_set = Static::get(); let hash = phf_shared::hash(string_to_add, &static_set.key); let index = phf_shared::get_index(&hash, static_set.disps, static_set.atoms.len()); if static_set.atoms[index as usize] == string_to_add { - Ok(Self::pack_static(index)) + Some(Self::pack_static(index)) } else { - Err(hash) + None } } @@ -271,11 +267,9 @@ impl<'a, Static: StaticAtomSet> From> for Atom { phantom: PhantomData, } } else { - Self::try_static_internal(&string_to_add).unwrap_or_else(|hash| { - // Reconstitute 64-bit `Hash128::h1` - // https://docs.rs/phf_shared/0.14.0/src/phf_shared/lib.rs.html#45-54 - let hash = (hash.g as u64) << 32 | (hash.f1 as u64); - let ptr: std::ptr::NonNull = dynamic_set().insert(string_to_add, hash); + Self::try_static(&string_to_add).unwrap_or_else(|| { + // This string is not in the static set, add it if needed to the dynamic set. + let ptr: std::ptr::NonNull = dynamic_set().insert(string_to_add); let data = ptr.as_ptr().expose_provenance() as u64; debug_assert!(0 == data & TAG_MASK); Atom { diff --git a/src/dynamic_set.rs b/src/dynamic_set.rs index 19ffb72..fc89859 100644 --- a/src/dynamic_set.rs +++ b/src/dynamic_set.rs @@ -10,6 +10,7 @@ use parking_lot::Mutex; use std::borrow::Cow; use std::cell::UnsafeCell; +use std::hash::{BuildHasher as _, RandomState}; use std::ptr::NonNull; use std::sync::OnceLock; use std::sync::atomic::AtomicIsize; @@ -20,6 +21,7 @@ const BUCKET_MASK: u64 = (1 << 12) - 1; pub(crate) struct Set { buckets: Box<[Mutex>>]>, + hasher: RandomState, } pub(crate) struct Entry { @@ -46,12 +48,19 @@ pub(crate) fn dynamic_set() -> &'static Set { DYNAMIC_SET.get_or_init(|| { let buckets = (0..NB_BUCKETS).map(|_| Mutex::new(None)).collect(); - Set { buckets } + Set { + buckets, + hasher: RandomState::new(), + } }) } impl Set { - pub(crate) fn insert(&self, string: Cow, hash: u64) -> NonNull { + pub(crate) fn insert(&self, string: Cow) -> NonNull { + // Don’t reuse the static set hash here: + // https://github.com/servo/string-cache/issues/314 + let hash = self.hasher.hash_one::<&str>(&string); + let bucket_index = (hash & BUCKET_MASK) as usize; let mut linked_list = self.buckets[bucket_index].lock();