use crate::*;
pub struct Reader<'a> {
pub data: &'a [u8],
}
pub struct Writer<'a> {
pub data: &'a mut [u8],
}
pub struct Pos {
slot: usize,
entry: u8,
}
impl Pos {
pub fn start() -> Self {
Self { slot: 0, entry: 0 }
}
}
const SLOTS: usize = 103;
const USED: usize = 0;
const FREE: usize = USED + 1;
const DALL: usize = FREE + 1;
const SLOT: usize = DALL + 2;
const DATA: usize = SLOT + SLOTS;
const ESIZE: usize = 3;
impl<'a> Reader<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data }
}
pub fn get<K: DKey>(&self, key: &K, hash: u64, ps: &mut PageSet) -> Option<(usize, usize)> {
if self.data.is_empty() {
return None;
}
let slot = (hash % SLOTS as u64) as usize;
let mut entry = self.data[SLOT + slot];
while entry != 0 {
let voff = self.get_voff(entry);
let len = self.data[voff] as usize;
let v = &self.data[voff + 1..voff + 1 + len];
if key.ok(v, ps) {
return Some((voff + 1, len));
}
entry = self.next(entry);
}
None
}
pub fn iter_next(&self, pos: &mut Pos) -> Option<(usize, usize)> {
if self.data.is_empty() {
return None;
}
while pos.entry == 0 {
if pos.slot == SLOTS {
return None;
}
pos.entry = self.data[SLOT + pos.slot];
pos.slot += 1;
}
let voff = self.get_voff(pos.entry);
pos.entry = self.next(pos.entry);
let len = self.data[voff] as usize;
Some((voff + 1, len))
}
pub fn compact(&self, size: usize) -> Vec<u8> {
let mut result = vec![0; size];
let mut w = Writer::new(&mut result);
let mut pos = Pos::start();
while let Some((off, len)) = self.iter_next(&mut pos) {
let ud = &self.data[off..off + len];
w.insert_at(pos.slot - 1, ud);
}
result
}
fn eoff(&self, entry: u8) -> usize {
assert!(entry > 0);
self.data.len() - (entry as usize) * ESIZE
}
fn next(&self, entry: u8) -> u8 {
self.data[self.eoff(entry)]
}
fn get_voff(&self, entry: u8) -> usize {
let off = self.eoff(entry) + 1;
DATA + self.data[off] as usize + (self.data[off + 1] as usize) * 256
}
}
impl<'a> Writer<'a> {
pub fn new(data: &'a mut [u8]) -> Self {
Self { data }
}
pub fn insert(&mut self, user_data: &[u8], hash: u64) {
debug_assert!(self.space(user_data.len()) == 0);
let slot = (hash % SLOTS as u64) as usize;
self.insert_at(slot, user_data);
}
pub fn space(&self, rsize: usize) -> usize {
let used = DATA + self.get2(DALL) + (self.data[USED] as usize) * 3;
let reqd = used + 1 + rsize + (if self.data[FREE] == 0 { ESIZE } else { 0 });
if reqd > self.data.len() {
reqd - self.data.len()
} else {
0
}
}
fn insert_at(&mut self, slot: usize, user_data: &[u8]) {
let n = user_data.len();
let new_entry = self.alloc_entry();
let voff = self.alloc_data(1 + n);
self.data[voff] = n as u8;
self.data[voff + 1..voff + 1 + n].copy_from_slice(user_data);
self.set_voff(new_entry, voff);
let old_entry = self.data[SLOT + slot];
self.set_next(new_entry, old_entry);
self.data[SLOT + slot] = new_entry;
}
pub fn remove<K: DKey>(&mut self, key: &K, hash: u64, ps: &mut PageSet) -> bool {
let slot = (hash % SLOTS as u64) as usize;
let mut entry = self.data[SLOT + slot];
let mut prev = None;
while entry != 0 {
let voff = self.get_voff(entry);
let len = self.data[voff] as usize;
let v = &self.data[voff + 1..voff + 1 + len];
let next = self.next(entry);
if key.ok(v, ps) {
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 true;
}
prev = Some(entry);
entry = next;
}
false
}
fn alloc_entry(&mut self) -> u8 {
let result = self.data[FREE];
if result != 0 {
self.data[FREE] = self.next(result);
return result;
}
let result = self.data[USED];
self.data[USED] += 1;
result + 1
}
fn eoff(&self, entry: u8) -> usize {
assert!(entry > 0);
self.data.len() - (entry as usize) * ESIZE
}
fn next(&self, entry: u8) -> u8 {
self.data[self.eoff(entry)]
}
fn set_next(&mut self, entry: u8, val: u8) {
self.data[self.eoff(entry)] = val;
}
fn get_voff(&self, entry: u8) -> usize {
let off = self.eoff(entry) + 1;
self.get2(off)
}
fn set_voff(&mut self, entry: u8, voff: usize) {
let voff = voff - DATA;
let off = self.eoff(entry) + 1;
self.set2(off, voff);
}
fn alloc_data(&mut self, size: usize) -> usize {
let result = self.get2(DALL);
self.set2(DALL, result + size);
DATA + result
}
fn get2(&self, off: usize) -> usize {
self.data[off] as usize + (self.data[off + 1] as usize) * 256
}
fn set2(&mut self, off: usize, to: usize) {
self.data[off] = (to % 256) as u8;
self.data[off + 1] = ((to / 256) % 256) as u8;
}
}