diff options
Diffstat (limited to 'vendor/phf_shared/src/lib.rs')
-rw-r--r-- | vendor/phf_shared/src/lib.rs | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/vendor/phf_shared/src/lib.rs b/vendor/phf_shared/src/lib.rs new file mode 100644 index 000000000..79b119a32 --- /dev/null +++ b/vendor/phf_shared/src/lib.rs @@ -0,0 +1,421 @@ +#![doc(html_root_url = "https://docs.rs/phf_shared/0.9")] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "std")] +extern crate std as core; + +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::num::Wrapping; +use siphasher::sip128::{Hash128, Hasher128, SipHasher13}; + +#[non_exhaustive] +pub struct Hashes { + pub g: u32, + pub f1: u32, + pub f2: u32, +} + +/// A central typedef for hash keys +/// +/// Makes experimentation easier by only needing to be updated here. +pub type HashKey = u64; + +#[inline] +pub fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 { + (Wrapping(d2) + Wrapping(f1) * Wrapping(d1) + Wrapping(f2)).0 +} + +/// `key` is from `phf_generator::HashState`. +#[inline] +pub fn hash<T: ?Sized + PhfHash>(x: &T, key: &HashKey) -> Hashes { + let mut hasher = SipHasher13::new_with_keys(0, *key); + x.phf_hash(&mut hasher); + + let Hash128 { + h1: lower, + h2: upper, + } = hasher.finish128(); + + Hashes { + g: (lower >> 32) as u32, + f1: lower as u32, + f2: upper as u32, + } +} + +/// Return an index into `phf_generator::HashState::map`. +/// +/// * `hash` is from `hash()` in this crate. +/// * `disps` is from `phf_generator::HashState::disps`. +/// * `len` is the length of `phf_generator::HashState::map`. +#[inline] +pub fn get_index(hashes: &Hashes, disps: &[(u32, u32)], len: usize) -> u32 { + let (d1, d2) = disps[(hashes.g % (disps.len() as u32)) as usize]; + displace(hashes.f1, hashes.f2, d1, d2) % (len as u32) +} + +/// A trait implemented by types which can be used in PHF data structures. +/// +/// This differs from the standard library's `Hash` trait in that `PhfHash`'s +/// results must be architecture independent so that hashes will be consistent +/// between the host and target when cross compiling. +pub trait PhfHash { + /// Feeds the value into the state given, updating the hasher as necessary. + fn phf_hash<H: Hasher>(&self, state: &mut H); + + /// Feeds a slice of this type into the state provided. + fn phf_hash_slice<H: Hasher>(data: &[Self], state: &mut H) + where + Self: Sized, + { + for piece in data { + piece.phf_hash(state); + } + } +} + +/// Trait for printing types with `const` constructors, used by `phf_codegen` and `phf_macros`. +pub trait FmtConst { + /// Print a `const` expression representing this value. + fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; +} + +/// Identical to `std::borrow::Borrow` except omitting blanket impls to facilitate other +/// borrowing patterns. +/// +/// The same semantic requirements apply: +/// +/// > In particular `Eq`, `Ord` and `Hash` must be equivalent for borrowed and owned values: +/// `x.borrow() == y.borrow()` should give the same result as `x == y`. +/// +/// (This crate's API only requires `Eq` and `PhfHash`, however.) +/// +/// ### Motivation +/// The conventional signature for lookup methods on collections looks something like this: +/// +/// ```rust,ignore +/// impl<K, V> Map<K, V> where K: PhfHash + Eq { +/// fn get<T: ?Sized>(&self, key: &T) -> Option<&V> where T: PhfHash + Eq, K: Borrow<T> { +/// ... +/// } +/// } +/// ``` +/// +/// This allows the key type used for lookup to be different than the key stored in the map so for +/// example you can use `&str` to look up a value in a `Map<String, _>`. However, this runs into +/// a problem in the case where `T` and `K` are both a `Foo<_>` type constructor but +/// the contained type is different (even being the same type with different lifetimes). +/// +/// The main issue for this crate's API is that, with this method signature, you cannot perform a +/// lookup on a `Map<UniCase<&'static str>, _>` with a `UniCase<&'a str>` where `'a` is not +/// `'static`; there is no impl of `Borrow` that resolves to +/// `impl Borrow<UniCase<'a>> for UniCase<&'static str>` and one cannot be added either because of +/// all the blanket impls. +/// +/// Instead, this trait is implemented conservatively, without blanket impls, so that impls like +/// this may be added. This is feasible since the set of types that implement `PhfHash` is +/// intentionally small. +/// +/// This likely won't be fixable with specialization alone but will require full support for lattice +/// impls since we technically want to add overlapping blanket impls. +pub trait PhfBorrow<B: ?Sized> { + /// Convert a reference to `self` to a reference to the borrowed type. + fn borrow(&self) -> &B; +} + +/// Create an impl of `FmtConst` delegating to `fmt::Debug` for types that can deal with it. +/// +/// Ideally with specialization this could be just one default impl and then specialized where +/// it doesn't apply. +macro_rules! delegate_debug ( + ($ty:ty) => { + impl FmtConst for $ty { + fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } + } + } +); + +delegate_debug!(str); +delegate_debug!(char); +delegate_debug!(u8); +delegate_debug!(i8); +delegate_debug!(u16); +delegate_debug!(i16); +delegate_debug!(u32); +delegate_debug!(i32); +delegate_debug!(u64); +delegate_debug!(i64); +delegate_debug!(u128); +delegate_debug!(i128); +delegate_debug!(bool); + +/// `impl PhfBorrow<T> for T` +macro_rules! impl_reflexive( + ($($t:ty),*) => ( + $(impl PhfBorrow<$t> for $t { + fn borrow(&self) -> &$t { + self + } + })* + ) +); + +impl_reflexive!( + str, + char, + u8, + i8, + u16, + i16, + u32, + i32, + u64, + i64, + u128, + i128, + bool, + [u8] +); + +#[cfg(feature = "std")] +impl PhfBorrow<str> for String { + fn borrow(&self) -> &str { + self + } +} + +#[cfg(feature = "std")] +impl PhfBorrow<[u8]> for Vec<u8> { + fn borrow(&self) -> &[u8] { + self + } +} + +#[cfg(feature = "std")] +delegate_debug!(String); + +#[cfg(feature = "std")] +impl PhfHash for String { + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + (**self).phf_hash(state) + } +} + +#[cfg(feature = "std")] +impl PhfHash for Vec<u8> { + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + (**self).phf_hash(state) + } +} + +impl<'a, T: 'a + PhfHash + ?Sized> PhfHash for &'a T { + fn phf_hash<H: Hasher>(&self, state: &mut H) { + (*self).phf_hash(state) + } +} + +impl<'a, T: 'a + FmtConst + ?Sized> FmtConst for &'a T { + fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (*self).fmt_const(f) + } +} + +impl<'a> PhfBorrow<str> for &'a str { + fn borrow(&self) -> &str { + self + } +} + +impl<'a> PhfBorrow<[u8]> for &'a [u8] { + fn borrow(&self) -> &[u8] { + self + } +} + +impl PhfHash for str { + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + self.as_bytes().phf_hash(state) + } +} + +impl PhfHash for [u8] { + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + state.write(self); + } +} + +impl FmtConst for [u8] { + #[inline] + fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // slices need a leading reference + write!(f, "&{:?}", self) + } +} + +#[cfg(feature = "unicase")] +impl<S> PhfHash for unicase::UniCase<S> +where + unicase::UniCase<S>: Hash, +{ + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + self.hash(state) + } +} + +#[cfg(feature = "unicase")] +impl<S> FmtConst for unicase::UniCase<S> +where + S: AsRef<str>, +{ + fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.is_ascii() { + f.write_str("UniCase::ascii(")?; + } else { + f.write_str("UniCase::unicode(")?; + } + + self.as_ref().fmt_const(f)?; + f.write_str(")") + } +} + +#[cfg(feature = "unicase")] +impl<'b, 'a: 'b, S: ?Sized + 'a> PhfBorrow<unicase::UniCase<&'b S>> for unicase::UniCase<&'a S> { + fn borrow(&self) -> &unicase::UniCase<&'b S> { + self + } +} + +#[cfg(feature = "uncased")] +impl PhfHash for uncased::UncasedStr { + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + self.hash(state) + } +} + +#[cfg(feature = "uncased")] +impl FmtConst for uncased::UncasedStr { + fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // transmute is not stable in const fns (rust-lang/rust#53605), so + // `UncasedStr::new` can't be a const fn itself, but we can inline the + // call to transmute here in the meantime. + f.write_str("unsafe { ::std::mem::transmute::<&'static str, &'static UncasedStr>(")?; + self.as_str().fmt_const(f)?; + f.write_str(") }") + } +} + +#[cfg(feature = "uncased")] +impl PhfBorrow<uncased::UncasedStr> for &uncased::UncasedStr { + fn borrow(&self) -> &uncased::UncasedStr { + self + } +} + +macro_rules! sip_impl ( + (le $t:ty) => ( + impl PhfHash for $t { + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + self.to_le().hash(state); + } + } + ); + ($t:ty) => ( + impl PhfHash for $t { + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + self.hash(state); + } + } + ) +); + +sip_impl!(u8); +sip_impl!(i8); +sip_impl!(le u16); +sip_impl!(le i16); +sip_impl!(le u32); +sip_impl!(le i32); +sip_impl!(le u64); +sip_impl!(le i64); +sip_impl!(le u128); +sip_impl!(le i128); +sip_impl!(bool); + +impl PhfHash for char { + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + (*self as u32).phf_hash(state) + } +} + +// minimize duplicated code since formatting drags in quite a bit +fn fmt_array(array: &[u8], f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", array) +} + +macro_rules! array_impl ( + ($t:ty, $n:expr) => ( + impl PhfHash for [$t; $n] { + #[inline] + fn phf_hash<H: Hasher>(&self, state: &mut H) { + state.write(self); + } + } + + impl FmtConst for [$t; $n] { + fn fmt_const(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt_array(self, f) + } + } + + impl PhfBorrow<[$t]> for [$t; $n] { + fn borrow(&self) -> &[$t] { + self + } + } + ) +); + +array_impl!(u8, 1); +array_impl!(u8, 2); +array_impl!(u8, 3); +array_impl!(u8, 4); +array_impl!(u8, 5); +array_impl!(u8, 6); +array_impl!(u8, 7); +array_impl!(u8, 8); +array_impl!(u8, 9); +array_impl!(u8, 10); +array_impl!(u8, 11); +array_impl!(u8, 12); +array_impl!(u8, 13); +array_impl!(u8, 14); +array_impl!(u8, 15); +array_impl!(u8, 16); +array_impl!(u8, 17); +array_impl!(u8, 18); +array_impl!(u8, 19); +array_impl!(u8, 20); +array_impl!(u8, 21); +array_impl!(u8, 22); +array_impl!(u8, 23); +array_impl!(u8, 24); +array_impl!(u8, 25); +array_impl!(u8, 26); +array_impl!(u8, 27); +array_impl!(u8, 28); +array_impl!(u8, 29); +array_impl!(u8, 30); +array_impl!(u8, 31); +array_impl!(u8, 32); |