1 //! Build support for precomputed constant hash tables. 2 //! 3 //! This module can generate constant hash tables using open addressing and quadratic probing. 4 //! 5 //! The hash tables are arrays that are guaranteed to: 6 //! 7 //! - Have a power-of-two size. 8 //! - Contain at least one empty slot. 9 //! 10 //! This module provides build meta support for lookups in these tables, as well as the shared hash 11 //! function used for probing. 12 13 use std::iter; 14 15 /// A primitive hash function for matching opcodes. 16 pub fn simple_hash(s: &str) -> usize { 17 let mut h: u32 = 5381; 18 for c in s.chars() { 19 h = (h ^ c as u32).wrapping_add(h.rotate_right(6)); 20 } 21 h as usize 22 } 23 24 /// Compute an open addressed, quadratically probed hash table containing 25 /// `items`. The returned table is a list containing the elements of the 26 /// iterable `items` and `None` in unused slots. 27 pub fn generate_table<'cont, T, I: iter::Iterator<Item = &'cont T>, H: Fn(&T) -> usize>( 28 items: I, 29 num_items: usize, 30 hash_function: H, 31 ) -> Vec<Option<&'cont T>> { 32 let size = (1.20 * num_items as f64) as usize; 33 // TODO do we really need the multiply by two here? 34 let size = if size.is_power_of_two() { 35 size * 2 36 } else { 37 size.next_power_of_two() 38 }; 39 40 let mut table = vec![None; size]; 41 42 for i in items { 43 let mut h = hash_function(&i) % size; 44 let mut s = 0; 45 while table[h].is_some() { 46 s += 1; 47 h = (h + s) % size; 48 } 49 table[h] = Some(i); 50 } 51 52 table 53 } 54 55 #[cfg(test)] 56 mod tests { 57 use super::{generate_table, simple_hash}; 58 59 #[test] 60 fn basic() { 61 assert_eq!(simple_hash("Hello"), 0x2fa70c01); 62 assert_eq!(simple_hash("world"), 0x5b0c31d5); 63 } 64 65 #[test] 66 fn test_generate_table() { 67 let v = vec!["Hello".to_string(), "world".to_string()]; 68 let table = generate_table(v.iter(), v.len(), |s| simple_hash(&s)); 69 assert_eq!( 70 table, 71 vec![ 72 None, 73 Some(&"Hello".to_string()), 74 Some(&"world".to_string()), 75 None 76 ] 77 ); 78 } 79 } 80