diff --git a/Cargo.lock b/Cargo.lock index 897b37d7..a89c6417 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "human_name" -version = "0.6.5" +version = "0.7.0" dependencies = [ "itertools 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 9cc6739e..e01ae695 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "human_name" -version = "0.6.5" +version = "0.7.0" authors = ["David Judd "] description = "A library for parsing and comparing human names" license = "Apache-2.0" diff --git a/src/comparison.rs b/src/comparison.rs index 42823445..1f2bc5c3 100644 --- a/src/comparison.rs +++ b/src/comparison.rs @@ -65,7 +65,7 @@ impl Name { #[cfg_attr(rustfmt, rustfmt_skip)] pub fn consistent_with(&self, other: &Name) -> bool { // Fast path - if self.memoized_surname_hash() != other.memoized_surname_hash() { + if self.hash != other.hash { return false; } diff --git a/src/external.rs b/src/external.rs index 1693de78..aef8de68 100644 --- a/src/external.rs +++ b/src/external.rs @@ -54,7 +54,7 @@ pub extern "C" fn human_name_consistent_with(a: &Name, b: &Name) -> bool { #[no_mangle] pub extern "C" fn human_name_hash(name: &Name) -> u64 { - name.memoized_surname_hash() + name.hash } #[no_mangle] diff --git a/src/lib.rs b/src/lib.rs index 4b1b1ce0..5e5a1c20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,6 @@ pub mod external; mod eq_hash; use std::borrow::Cow; -use std::cell::Cell; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; use std::slice::Iter; @@ -66,7 +65,7 @@ pub struct Name { generation_from_suffix: Option, initials: String, word_indices_in_initials: Vec<(usize, usize)>, - hash: Cell>, + pub hash: u64, } impl Name { @@ -186,13 +185,16 @@ impl Name { names.shrink_to_fit(); word_indices_in_initials.shrink_to_fit(); + let mut s = DefaultHasher::new(); + Name::hash_surnames(&names[surname_index_in_names..], &mut s); + Some(Name { words: names, surname_index: surname_index_in_names, generation_from_suffix: generation_from_suffix, initials: initials, word_indices_in_initials: word_indices_in_initials, - hash: Cell::new(None), + hash: s.finish(), }) } @@ -410,7 +412,11 @@ impl Name { /// We can't use the first initial because we might ignore it if someone goes /// by a middle name or nickname, or due to transliteration. pub fn surname_hash(&self, state: &mut H) { - let surname_chars = self.surnames() + Name::hash_surnames(self.surnames(), state) + } + + fn hash_surnames(surnames: &[String], state: &mut H) { + let surname_chars = surnames .iter() .flat_map(|w| w.chars()) .flat_map(transliterate) @@ -420,22 +426,6 @@ impl Name { c.hash(state); } } - - /// Memoizes the result of `surname_hash` when used with `DefaultHasher` - pub fn memoized_surname_hash(&self) -> u64 { - { - let cached = self.hash.get(); - if cached.is_some() { - return cached.unwrap(); - } - - let mut s = DefaultHasher::new(); - self.surname_hash(&mut s); - self.hash.set(Some(s.finish())); - } - - self.memoized_surname_hash() - } } struct GivenNamesOrInitials<'a> { diff --git a/tests/lib.rs b/tests/lib.rs index d7857078..e130dbbb 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -129,7 +129,7 @@ fn equality() { "{} should be equal to {} but was not!", b, a); - assert!(parsed_a.unwrap().memoized_surname_hash() == parsed_b.unwrap().memoized_surname_hash(), + assert!(parsed_a.unwrap().hash == parsed_b.unwrap().hash, "{} should have the same hash as {} but did not!", a, b);