use core::hash::{Hash, Hasher};
use super::djb2hash::Djb2Hasher;
pub trait ProbableSlot<K> {
fn contains_key(&self, key: &K) -> bool
where
K: Eq;
fn is_empty(&self) -> bool;
fn is_tombstone(&self) -> bool;
}
pub fn hash_key<K: Hash, const N: usize>(key: &K) -> usize {
if N == 0 {
return 0;
}
let mut hasher = Djb2Hasher::default();
key.hash(&mut hasher);
(hasher.finish() as usize) % N
}
pub fn find_key_with_hash<K, S, const N: usize>(slots: &[S; N], key: &K) -> (bool, usize)
where
K: Eq + Hash,
S: ProbableSlot<K>,
{
let start_hash = hash_key::<K, N>(key);
let mut index = start_hash;
let mut first_tombstone = None;
for _i in 0..N {
let slot = &slots[index];
if slot.contains_key(key) {
return (true, index); } else if slot.is_empty() {
return (false, first_tombstone.unwrap_or(index));
} else if slot.is_tombstone() {
if first_tombstone.is_none() {
first_tombstone = Some(index);
}
}
index = (index + 1) % N; if index == start_hash {
return (false, first_tombstone.unwrap_or(start_hash));
}
}
(false, first_tombstone.unwrap_or(start_hash)) }