use crate::utils::assert_fast;
use std::alloc;
use std::alloc::Layout;
use std::cmp;
use std::mem;
const AGING_DIVISOR: u32 = 16;
pub struct HTable {
pub table: Box<[[HTableEntry; 64]; 64]>,
pub max: u32,
}
pub struct HTableEntry {
pub data: u32,
}
impl HTable {
pub fn add(&mut self, from: usize, to: usize, depth: u8) {
assert_fast!(from < 64);
assert_fast!(to < 64);
let entry = &mut self.table[from][to];
let value = (depth as u32).pow(2);
let updated_value = entry.data + value;
self.max = cmp::max(self.max, updated_value);
entry.data = updated_value;
}
pub fn punish(&mut self, from: usize, to: usize, depth: u8) {
assert_fast!(from < 64);
assert_fast!(to < 64);
let entry = &mut self.table[from][to];
let value = depth as u32;
let updated_value = match value <= entry.data {
true => entry.data - value,
false => 0,
};
entry.data = updated_value;
}
pub fn get(&self, from: usize, to: usize, max: u8) -> u8 {
assert_fast!(from < 64);
assert_fast!(to < 64);
assert_fast!(max > 0);
assert_fast!(self.max > 0);
(self.table[from][to].data * (max as u32)).div_ceil(self.max) as u8
}
pub fn age_values(&mut self) {
for row in self.table.iter_mut() {
for entry in row {
entry.data = entry.data.div_ceil(AGING_DIVISOR);
}
}
self.max = self.age_value(self.max);
}
fn age_value(&self, value: u32) -> u32 {
value.div_ceil(AGING_DIVISOR)
}
}
impl Default for HTable {
fn default() -> Self {
const SIZE: usize = mem::size_of::<HTableEntry>();
unsafe {
let ptr = alloc::alloc_zeroed(Layout::from_size_align(64 * 64 * SIZE, SIZE).unwrap());
Self { table: Box::from_raw(ptr as *mut [[HTableEntry; 64]; 64]), max: 1 }
}
}
}