diff --git a/phf/src/map.rs b/phf/src/map.rs index 8f1d6c61..d74c9f72 100644 --- a/phf/src/map.rs +++ b/phf/src/map.rs @@ -2,6 +2,7 @@ use debug_builders::DebugMap; use std::borrow::Borrow; use std::ops::Index; +use std::hash::{Hasher, SipHasher}; use std::slice; use std::fmt; use std::iter::IntoIterator; @@ -70,7 +71,10 @@ impl Map { /// Like `get`, but returns both the key and the value. pub fn get_entry(&self, key: &T) -> Option<(&K, &V)> where T: Eq + PhfHash, K: Borrow { - let (g, f1, f2) = key.phf_hash(self.key); + let mut hasher = SipHasher::new_with_keys(0, self.key); + key.phf_hash(&mut hasher); + let (g, f1, f2) = phf_shared::split(hasher.finish()); + let (d1, d2) = self.disps[(g % (self.disps.len() as u32)) as usize]; let entry = &self.entries[(phf_shared::displace(f1, f2, d1, d2) % (self.entries.len() as u32)) as usize]; diff --git a/phf/src/ordered_map.rs b/phf/src/ordered_map.rs index f8e66c3b..e9044dec 100644 --- a/phf/src/ordered_map.rs +++ b/phf/src/ordered_map.rs @@ -1,6 +1,7 @@ //! An order-preserving immutable map constructed at compile time. use debug_builders::DebugMap; use std::borrow::Borrow; +use std::hash::{Hasher, SipHasher}; use std::iter::IntoIterator; use std::ops::Index; use std::fmt; @@ -94,7 +95,10 @@ impl OrderedMap { fn get_internal(&self, key: &T) -> Option<(usize, (&K, &V))> where T: Eq + PhfHash, K: Borrow { - let (g, f1, f2) = key.phf_hash(self.key); + let mut hasher = SipHasher::new_with_keys(0, self.key); + key.phf_hash(&mut hasher); + let (g, f1, f2) = phf_shared::split(hasher.finish()); + let (d1, d2) = self.disps[(g % (self.disps.len() as u32)) as usize]; let idx = self.idxs[(phf_shared::displace(f1, f2, d1, d2) % (self.idxs.len() as u32)) as usize]; let entry = &self.entries[idx]; diff --git a/phf_generator/src/lib.rs b/phf_generator/src/lib.rs index d39a2f67..c5b73383 100644 --- a/phf_generator/src/lib.rs +++ b/phf_generator/src/lib.rs @@ -4,6 +4,7 @@ extern crate rand; use phf_shared::PhfHash; use rand::{SeedableRng, XorShiftRng, Rng}; +use std::hash::{Hasher, SipHasher}; const DEFAULT_LAMBDA: usize = 5; @@ -37,9 +38,12 @@ fn try_generate_hash(entries: &[H], rng: &mut XorShiftRng) -> Option } let key = rng.gen(); + let hasher = SipHasher::new_with_keys(0, key); let hashes: Vec<_> = entries.iter().map(|entry| { - let (g, f1, f2) = entry.phf_hash(key); + let mut hasher = hasher.clone(); + entry.phf_hash(&mut hasher); + let (g, f1, f2) = phf_shared::split(hasher.finish()); Hashes { g: g, f1: f1, diff --git a/phf_macros/src/util.rs b/phf_macros/src/util.rs index 431e6e55..9b05d238 100644 --- a/phf_macros/src/util.rs +++ b/phf_macros/src/util.rs @@ -47,20 +47,20 @@ impl Hash for Key { } impl PhfHash for Key { - fn phf_hash(&self, key: u64) -> (u32, u32, u32) { + fn phf_hash(&self, state: &mut H) { match *self { - Key::Str(ref s) => s.phf_hash(key), - Key::Binary(ref b) => b.phf_hash(key), - Key::Char(c) => c.phf_hash(key), - Key::U8(b) => b.phf_hash(key), - Key::I8(b) => b.phf_hash(key), - Key::U16(b) => b.phf_hash(key), - Key::I16(b) => b.phf_hash(key), - Key::U32(b) => b.phf_hash(key), - Key::I32(b) => b.phf_hash(key), - Key::U64(b) => b.phf_hash(key), - Key::I64(b) => b.phf_hash(key), - Key::Bool(b) => b.phf_hash(key), + Key::Str(ref s) => s.phf_hash(state), + Key::Binary(ref b) => b.phf_hash(state), + Key::Char(c) => c.phf_hash(state), + Key::U8(b) => b.phf_hash(state), + Key::I8(b) => b.phf_hash(state), + Key::U16(b) => b.phf_hash(state), + Key::I16(b) => b.phf_hash(state), + Key::U32(b) => b.phf_hash(state), + Key::I32(b) => b.phf_hash(state), + Key::U64(b) => b.phf_hash(state), + Key::I64(b) => b.phf_hash(state), + Key::Bool(b) => b.phf_hash(state), } } } @@ -72,8 +72,8 @@ pub struct Entry { } impl PhfHash for Entry { - fn phf_hash(&self, key: u64) -> (u32, u32, u32) { - self.key_contents.phf_hash(key) + fn phf_hash(&self, state: &mut H) { + self.key_contents.phf_hash(state) } } diff --git a/phf_shared/src/lib.rs b/phf_shared/src/lib.rs index 0e959f75..1a5a028a 100644 --- a/phf_shared/src/lib.rs +++ b/phf_shared/src/lib.rs @@ -1,6 +1,6 @@ #![doc(html_root_url="http://sfackler.github.io/rust-phf/doc")] -use std::hash::{Hasher, Hash, SipHasher}; +use std::hash::{Hasher, Hash}; #[inline] pub fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 { @@ -8,7 +8,7 @@ pub fn displace(f1: u32, f2: u32, d1: u32, d2: u32) -> u32 { } #[inline] -fn split(hash: u64) -> (u32, u32, u32) { +pub fn split(hash: u64) -> (u32, u32, u32) { const BITS: u32 = 21; const MASK: u64 = (1 << BITS) - 1; @@ -17,39 +17,48 @@ fn split(hash: u64) -> (u32, u32, u32) { ((hash >> (2 * BITS)) & MASK) as u32) } -/// A trait implemented by types which can be used in PHF data structures +/// 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 { - /// Hashes the value of `self`, factoring in a seed - fn phf_hash(&self, seed: u64) -> (u32, u32, u32); + /// Feeds the value into the state given, updating the hasher as necessary. + fn phf_hash(&self, state: &mut H); + + /// Feeds a slice of this type into the state provided. + fn phf_hash_slice(data: &[Self], state: &mut H) where Self: Sized { + for piece in data { + piece.phf_hash(state); + } + } } impl<'a> PhfHash for &'a str { #[inline] - fn phf_hash(&self, seed: u64) -> (u32, u32, u32) { - self.as_bytes().phf_hash(seed) + fn phf_hash(&self, state: &mut H) { + self.as_bytes().phf_hash(state) } } impl<'a> PhfHash for &'a [u8] { #[inline] - fn phf_hash(&self, seed: u64) -> (u32, u32, u32) { - (*self).phf_hash(seed) + fn phf_hash(&self, state: &mut H) { + (*self).phf_hash(state) } } impl PhfHash for str { #[inline] - fn phf_hash(&self, seed: u64) -> (u32, u32, u32) { - self.as_bytes().phf_hash(seed) + fn phf_hash(&self, state: &mut H) { + self.as_bytes().phf_hash(state) } } impl PhfHash for [u8] { #[inline] - fn phf_hash(&self, seed: u64) -> (u32, u32, u32) { - let mut state = SipHasher::new_with_keys(seed, 0); - Hasher::write(&mut state, self); - split(state.finish()) + fn phf_hash(&self, state: &mut H) { + state.write(self); } } @@ -58,20 +67,16 @@ macro_rules! sip_impl( (le $t:ty) => ( impl PhfHash for $t { #[inline] - fn phf_hash(&self, seed: u64) -> (u32, u32, u32) { - let mut hasher = SipHasher::new_with_keys(seed, 0); - self.to_le().hash(&mut hasher); - split(hasher.finish()) + fn phf_hash(&self, state: &mut H) { + self.to_le().hash(state); } } ); ($t:ty) => ( impl PhfHash for $t { #[inline] - fn phf_hash(&self, seed: u64) -> (u32, u32, u32) { - let mut hasher = SipHasher::new_with_keys(seed, 0); - self.hash(&mut hasher); - split(hasher.finish()) + fn phf_hash(&self, state: &mut H) { + self.hash(state); } } ) @@ -89,8 +94,8 @@ sip_impl!(bool); impl PhfHash for char { #[inline] - fn phf_hash(&self, seed: u64) -> (u32, u32, u32) { - (*self as u32).phf_hash(seed) + fn phf_hash(&self, state: &mut H) { + (*self as u32).phf_hash(state) } } @@ -98,10 +103,8 @@ macro_rules! array_impl( ($t:ty, $n:expr) => ( impl PhfHash for [$t; $n] { #[inline] - fn phf_hash(&self, seed: u64) -> (u32, u32, u32) { - let mut hasher = SipHasher::new_with_keys(seed, 0); - Hasher::write(&mut hasher, self); - split(hasher.finish()) + fn phf_hash(&self, state: &mut H) { + state.write(self); } } )