pub fn table_capacity(len: usize) -> usize {
let mut capacity = 16;
while len * 4 > capacity * 3 {
capacity *= 2;
}
capacity
}
pub fn bucket(hash: i32, capacity: usize) -> usize {
let h = hash as u32;
((h ^ (h >> 16)) as usize) & (capacity - 1)
}
pub fn long_hash(value: u64) -> i32 {
(value ^ (value >> 32)) as i32
}
pub fn string_hash(s: &str) -> i32 {
s.bytes()
.fold(0i32, |h, b| h.wrapping_mul(31).wrapping_add(b as i32))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_table_capacity() {
assert_eq!(table_capacity(0), 16);
assert_eq!(table_capacity(12), 16);
assert_eq!(table_capacity(13), 32);
assert_eq!(table_capacity(100_000), 262_144);
}
#[test]
fn test_hashes_match_java() {
assert_eq!(string_hash(""), 0);
assert_eq!(string_hash("ACGT"), 2_003_087);
assert_eq!(
string_hash("GATCGGAAGAGCACACGTCTGAACTCCAGTCACATCACGATCTCGTATGC"),
-615_524_200
);
assert_eq!(long_hash(17), 17);
assert_eq!(long_hash(1 << 32), 1);
}
#[test]
fn test_bucket_spreads_high_bits() {
assert_eq!(bucket(17, 16), 1);
assert_eq!(bucket(1 << 16, 16), 1);
}
}