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 34 // Probing code's stop condition relies on the table having one vacant entry at least. 35 let size = if size.is_power_of_two() { 36 size * 2 37 } else { 38 size.next_power_of_two() 39 }; 40 41 let mut table = vec![None; size]; 42 43 for i in items { 44 let mut h = hash_function(&i) % size; 45 let mut s = 0; 46 while table[h].is_some() { 47 s += 1; 48 h = (h + s) % size; 49 } 50 table[h] = Some(i); 51 } 52 53 table 54 } 55 56 #[cfg(test)] 57 mod tests { 58 use super::{generate_table, simple_hash}; 59 60 #[test] 61 fn basic() { 62 assert_eq!(simple_hash("Hello"), 0x2fa70c01); 63 assert_eq!(simple_hash("world"), 0x5b0c31d5); 64 } 65 66 #[test] 67 fn test_generate_table() { 68 let v = vec!["Hello".to_string(), "world".to_string()]; 69 let table = generate_table(v.iter(), v.len(), |s| simple_hash(&s)); 70 assert_eq!( 71 table, 72 vec![ 73 None, 74 Some(&"Hello".to_string()), 75 Some(&"world".to_string()), 76 None 77 ] 78 ); 79 } 80 } 81