use crate::Key;
pub struct Reader<'a> {
pub data: &'a [u8],
}
pub struct Writer<'a> {
pub data: &'a mut [u8],
}
const ENTS: usize = 127;
const SLOTS: usize = 253;
const REFA: usize = 0;
const SLOT: usize = REFA + ENTS * 16;
const NEXT: usize = SLOT + SLOTS;
const USED: usize = NEXT + ENTS;
const FREE: usize = USED + 1;
pub const SIZE: usize = FREE + 1;
impl<'a> Reader<'a> {
pub fn get<K: Key>(&self, key: &K, hash: u64) -> Option<u64> {
let slot = (hash % SLOTS as u64) as usize;
let mut entry = self.data[SLOT + slot];
while entry != 0 {
let (r, h) = self.get_ref(entry);
if h == hash && key.equal(r) {
return Some(r);
}
entry = self.get_next(entry);
}
None
}
fn get_next(&self, ix: u8) -> u8 {
self.data[NEXT + (ix - 1) as usize]
}
fn get_ref(&self, entry: u8) -> (u64, u64) {
let off = REFA + (entry as usize - 1) * 16;
let loc = &self.data[off..off + 8];
let r = u64::from_le_bytes(loc.try_into().unwrap());
let loc = &self.data[off + 8..off + 16];
let h = u64::from_le_bytes(loc.try_into().unwrap());
(r, h)
}
pub fn iter(self) -> Iter<'a> {
Iter {
slot: 0,
entry: 0,
r: self,
}
}
}
pub struct Iter<'a> {
slot: usize,
entry: u8,
r: Reader<'a>,
}
impl<'a> Iterator for Iter<'a> {
type Item = (u64, u64);
fn next(&mut self) -> Option<Self::Item> {
let mut entry = self.entry;
while entry == 0 {
if self.slot == SLOTS {
return None;
}
entry = self.r.data[SLOT + self.slot];
self.slot += 1;
}
let (r, h) = self.r.get_ref(entry);
self.entry = self.r.get_next(entry);
Some((r, h))
}
}
impl<'a> Writer<'a> {
pub fn insert(&mut self, id: u64, hash: u64) {
let slot = (hash % SLOTS as u64) as usize;
let new_entry = self.alloc_entry();
self.set_ref(new_entry, id, hash);
let old_entry = self.data[SLOT + slot];
self.set_next(new_entry, old_entry);
self.data[SLOT + slot] = new_entry;
}
pub fn full(&self) -> bool {
self.data[FREE] == 0 && self.data[USED] as usize == ENTS
}
pub fn remove<K: Key>(&mut self, key: &K, hash: u64) -> Option<u64> {
let slot = (hash % SLOTS as u64) as usize;
let mut entry = self.data[SLOT + slot];
let mut prev = None;
while entry != 0 {
let (r, h) = self.get_ref(entry);
let next = self.get_next(entry);
if h == hash && key.equal(r) {
if let Some(prev) = prev {
self.set_next(prev, next);
} else {
self.data[SLOT + slot] = next;
}
self.set_next(entry, self.data[FREE]);
self.data[FREE] = entry;
return Some(r);
}
prev = Some(entry);
entry = next;
}
None
}
fn alloc_entry(&mut self) -> u8 {
let result = self.data[FREE];
if result != 0 {
self.data[FREE] = self.get_next(result);
return result;
}
let result = self.data[USED];
self.data[USED] += 1;
result + 1
}
fn get_next(&self, ix: u8) -> u8 {
self.data[NEXT + (ix - 1) as usize]
}
fn set_next(&mut self, ix: u8, val: u8) {
self.data[NEXT + (ix - 1) as usize] = val;
}
fn get_ref(&self, entry: u8) -> (u64, u64) {
let off = REFA + (entry as usize - 1) * 16;
let loc = &self.data[off..off + 8];
let r = u64::from_le_bytes(loc.try_into().unwrap());
let loc = &self.data[off + 8..off + 16];
let h = u64::from_le_bytes(loc.try_into().unwrap());
(r, h)
}
fn set_ref(&mut self, entry: u8, id: u64, hash: u64) {
let off = REFA + (entry as usize - 1) * 16;
let loc = &mut self.data[off..off + 8];
loc.copy_from_slice(&id.to_le_bytes());
let loc = &mut self.data[off + 8..off + 16];
loc.copy_from_slice(&hash.to_le_bytes());
}
}
#[cfg(test)]
struct TestKey {
value: u64,
}
#[cfg(test)]
impl Key for TestKey {
fn hash(&self) -> u64 {
(self.value * 101) % 53
}
fn equal(&self, r: u64) -> bool {
self.value == r
}
}
#[test]
fn test_hmp() {
let mut data = vec![0; SIZE];
let lim = ENTS as u64;
for tv in 1..lim {
let mut p = Writer { data: &mut data };
let key = TestKey { value: tv };
p.insert(key.value, key.hash());
}
for tv in 1..lim {
let p = Reader { data: &data };
let key = TestKey { value: tv };
let x = p.get(&key, key.hash());
assert!(x == Some(tv));
}
{
let p = Reader { data: &data };
for _e in p.iter() {
}
}
for tv in 1..lim {
let mut p = Writer { data: &mut data };
let key = TestKey { value: tv };
let x = p.remove(&key, key.hash());
assert!(x == Some(tv));
}
}