use core::borrow::Borrow;
use core::hash::Hash;
use core::marker::PhantomData;
use quickdiv::DivisorU64;
use crate::shared::*;
#[derive(Debug)]
pub struct RawPhfMap<K, V: 'static> {
codomain_len: DivisorU64,
buckets: DivisorU64,
seed: u64,
pilots_table: &'static [u16],
values: &'static [V],
free: &'static [u32],
key_marker: PhantomData<K>,
}
impl<K, V> RawPhfMap<K, V> {
#[doc(hidden)]
pub const fn new(
seed: u64,
pilots_table: &'static [u16],
values: &'static [V],
free: &'static [u32],
) -> RawPhfMap<K, V> {
let codomain_len = DivisorU64::new((values.len() + free.len()) as u64);
let buckets = DivisorU64::new(pilots_table.len() as u64);
RawPhfMap {
codomain_len,
buckets,
seed,
pilots_table,
values,
free,
key_marker: PhantomData,
}
}
pub fn get<Q>(&self, key: &Q) -> &V
where
K: Borrow<Q>,
Q: Hash + ?Sized,
{
let key_hash = hash_key(key.borrow(), self.seed);
let bucket = get_bucket(key_hash, self.buckets);
let pilot_hash = hash_pilot_value(self.pilots_table[bucket]);
let idx = get_index(key_hash, pilot_hash, self.codomain_len);
if idx < self.len() {
&self.values[idx]
} else {
&self.values[self.free[idx - self.len()] as usize]
}
}
pub const fn len(&self) -> usize {
self.values.len()
}
pub const fn is_empty(&self) -> bool {
self.values.is_empty()
}
pub fn iter(&self) -> Iter<'_, V> {
Iter {
iter: self.values.iter(),
}
}
}
#[derive(Clone)]
pub struct Iter<'a, V: 'a> {
iter: core::slice::Iter<'a, V>,
}
impl<'a, V> Iterator for Iter<'a, V> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[cfg(test)]
mod tests {
use crate::examples::EMPTY_RAW_MAP;
use super::*;
#[test]
#[should_panic]
fn test_get_from_empty() {
EMPTY_RAW_MAP.get("Lenar");
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<RawPhfMap<u64, u64>>();
}
}