use std::hash::{BuildHasher, Hasher};
pub type SeededHashMap<K, V> = std::collections::HashMap<K, V, SeededState>;
pub type SeededHashSet<K> = std::collections::HashSet<K, SeededState>;
#[derive(Clone, Debug, Default)]
pub struct SeededState(foldhash::fast::RandomState);
impl BuildHasher for SeededState {
type Hasher = SeededHasher;
#[inline]
fn build_hasher(&self) -> SeededHasher {
SeededHasher(self.0.build_hasher())
}
}
pub struct SeededHasher(foldhash::fast::FoldHasher<'static>);
impl Hasher for SeededHasher {
#[inline]
fn write(&mut self, bytes: &[u8]) {
if let Some((lo, rest)) = bytes.split_first_chunk::<16>() {
if let Ok(hi) = <[u8; 16]>::try_from(rest) {
self.0.write_u128(u128::from_ne_bytes(*lo));
self.0.write_u128(u128::from_ne_bytes(hi));
return;
}
if let Ok(hi) = <[u8; 4]>::try_from(rest) {
self.0.write_u128(u128::from_ne_bytes(*lo));
self.0.write_u32(u32::from_ne_bytes(hi));
return;
}
}
self.0.write(bytes);
}
#[inline]
fn write_u8(&mut self, i: u8) {
self.0.write_u8(i);
}
#[inline]
fn write_u16(&mut self, i: u16) {
self.0.write_u16(i);
}
#[inline]
fn write_u32(&mut self, i: u32) {
self.0.write_u32(i);
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.0.write_u64(i);
}
#[inline]
fn write_u128(&mut self, i: u128) {
self.0.write_u128(i);
}
#[inline]
fn write_usize(&mut self, i: usize) {
self.0.write_usize(i);
}
#[inline]
fn finish(&self) -> u64 {
self.0.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Address, H256, U256};
use std::hash::Hash;
const KEYS: u64 = 4096;
const MAX_BUCKET_LOAD: usize = 16;
const ZEROING_WORD: u64 = 0x13198a2e03707344;
fn fullest_bucket<K: Hash>(keys: impl Iterator<Item = K>) -> usize {
let state = SeededState::default();
let mut loads = vec![0usize; KEYS as usize];
for key in keys {
let bucket = state.hash_one(key) % KEYS;
if let Some(load) = loads.get_mut(bucket as usize) {
*load += 1;
}
}
loads.into_iter().max().unwrap_or_default()
}
fn address_with(at: usize, word: u64) -> Address {
let mut bytes = [0u8; 20];
for (byte, value) in bytes.iter_mut().skip(4).zip(ZEROING_WORD.to_le_bytes()) {
*byte = value;
}
for (byte, value) in bytes.iter_mut().skip(at).zip(word.to_le_bytes()) {
*byte = value;
}
Address::from(bytes)
}
#[test]
fn spreads_h256_keys_that_differ_in_either_half() {
let low = (0..KEYS).map(|i| H256::from(U256([i, 0, ZEROING_WORD, 0]).to_little_endian()));
assert!(fullest_bucket(low) <= MAX_BUCKET_LOAD);
let high = (0..KEYS).map(|i| H256::from(U256([0, 0, ZEROING_WORD, i]).to_little_endian()));
assert!(fullest_bucket(high) <= MAX_BUCKET_LOAD);
}
#[test]
fn spreads_u256_keys_that_differ_in_either_half() {
let low = (0..KEYS).map(|i| U256([i, 0, ZEROING_WORD, 0]));
assert!(fullest_bucket(low) <= MAX_BUCKET_LOAD);
let high = (0..KEYS).map(|i| U256([0, 0, ZEROING_WORD, i]));
assert!(fullest_bucket(high) <= MAX_BUCKET_LOAD);
}
#[test]
fn spreads_addresses_that_differ_in_either_part() {
assert!(fullest_bucket((0..KEYS).map(|i| address_with(12, i))) <= MAX_BUCKET_LOAD);
assert!(fullest_bucket((0..KEYS).map(|i| address_with(16, i))) <= MAX_BUCKET_LOAD);
}
#[test]
fn spreads_byte_strings_on_both_paths() {
let short = (0..KEYS).map(|i| U256([i, 0, ZEROING_WORD, 0]).to_little_endian().to_vec());
assert!(fullest_bucket(short) <= MAX_BUCKET_LOAD);
let long = (0..KEYS).map(|i| {
let mut bytes = vec![0u8; 40];
for (byte, value) in bytes.iter_mut().skip(32).zip(i.to_le_bytes()) {
*byte = value;
}
bytes
});
assert!(fullest_bucket(long) <= MAX_BUCKET_LOAD);
}
#[test]
fn two_maps_hash_the_same_key_apart() {
let key = H256::repeat_byte(0x5a);
assert_ne!(
SeededState::default().hash_one(key),
SeededState::default().hash_one(key)
);
}
#[test]
fn equal_keys_hash_equal_on_both_paths() {
let state = SeededState::default();
let key = H256::from_low_u64_be(7);
assert_eq!(state.hash_one(key), state.hash_one(key));
let bytes = vec![1u8; 40];
assert_eq!(state.hash_one(&bytes), state.hash_one(&bytes));
}
}