use ahash::RandomState;
use core::hash::Hash;
use std::hash::BuildHasher;
use crate::Ldd;
use crate::LddRef;
use crate::Storage;
use super::ldd::LddIndex;
use super::ldd::SharedProtectionSet;
pub struct OperationCache {
protection_set: SharedProtectionSet,
caches1: Vec<Cache<LddIndex, usize>>,
caches2: Vec<Cache<(LddIndex, LddIndex), LddIndex>>,
caches3: Vec<Cache<(LddIndex, LddIndex, LddIndex), LddIndex>>,
}
impl OperationCache {
pub fn new(protection_set: SharedProtectionSet) -> OperationCache {
OperationCache {
protection_set,
caches1: vec![Cache::new()],
caches2: vec![Cache::new(); 3],
caches3: vec![Cache::new()],
}
}
pub fn clear(&mut self) {
for cache in self.caches1.iter_mut() {
cache.clear();
}
for cache in self.caches2.iter_mut() {
cache.clear();
}
for cache in self.caches3.iter_mut() {
cache.clear();
}
}
pub fn len(&self) -> usize {
let mut result: usize = 0;
for cache in self.caches1.iter() {
result += cache.len();
}
for cache in self.caches2.iter() {
result += cache.len();
}
for cache in self.caches3.iter() {
result += cache.len();
}
result
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn limit(&mut self, size: usize) {
for cache in self.caches1.iter_mut() {
cache.limit(size / 4);
}
for cache in self.caches2.iter_mut() {
cache.limit(size / 4);
}
for cache in self.caches3.iter_mut() {
cache.limit(size / 4);
}
}
fn get_cache1(&mut self, operator: &UnaryFunction) -> &mut Cache<LddIndex, usize> {
match operator {
UnaryFunction::Len => &mut self.caches1[0],
}
}
fn get_cache2(&mut self, operator: &BinaryOperator) -> &mut Cache<(LddIndex, LddIndex), LddIndex> {
match operator {
BinaryOperator::Union => &mut self.caches2[0],
BinaryOperator::Merge => &mut self.caches2[1],
BinaryOperator::Minus => &mut self.caches2[2],
}
}
fn get_cache3(&mut self, operator: &TernaryOperator) -> &mut Cache<(LddIndex, LddIndex, LddIndex), LddIndex> {
match operator {
TernaryOperator::RelationalProduct => &mut self.caches3[0],
}
}
fn create(&mut self, index: LddIndex) -> Ldd {
Ldd::new(&self.protection_set, index)
}
}
pub struct Cache<K, V, S = RandomState> {
table: Vec<(K, V)>,
hash_builder: S,
}
impl<K: Default + Clone, V: Clone + Default> Cache<K, V, RandomState> {
pub fn new() -> Cache<K, V, RandomState> {
Cache {
table: vec![Default::default(); 1024],
hash_builder: RandomState::default(),
}
}
}
impl<K: Default + Clone, V: Clone + Default> Default for Cache<K, V, RandomState> {
fn default() -> Self {
Self::new()
}
}
impl<K: Default + Clone, V: Clone + Default, S> Cache<K, V, S> {
pub fn clear(&mut self) {
let capacity = self.table.len();
self.table.clear();
self.table.resize(capacity, Default::default());
}
pub fn limit(&mut self, size: usize) {
let power_of_two = size.next_power_of_two();
self.table.clear();
self.table.resize(power_of_two, Default::default());
}
pub fn len(&self) -> usize {
self.table.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<K: Default + Eq + Hash, V, S: BuildHasher> Cache<K, V, S> {
pub fn get(&mut self, key: &K) -> Option<&V> {
debug_assert!(*key != K::default(), "The key may never be equal to its default value.");
let index = self.hash_builder.hash_one(key) % (self.table.len() as u64);
let entry = &self.table[index as usize];
if entry.0 == *key { Some(&entry.1) } else { None }
}
pub fn insert(&mut self, key: K, value: V) {
debug_assert!(key != K::default(), "The key may never be equal to its default value.");
let index = self.hash_builder.hash_one(&key) % (self.table.len() as u64);
self.table[index as usize] = (key, value);
}
}
impl<K: Clone, V: Clone, S: Clone> Clone for Cache<K, V, S> {
fn clone(&self) -> Self {
Cache {
table: self.table.clone(),
hash_builder: self.hash_builder.clone(),
}
}
}
pub enum UnaryFunction {
Len,
}
pub enum BinaryOperator {
Union,
Merge,
Minus,
}
pub enum TernaryOperator {
RelationalProduct,
}
pub fn cache_unary_function<F>(storage: &mut Storage, operator: UnaryFunction, a: &LddRef, f: F) -> usize
where
F: Fn(&mut Storage, &LddRef<'_>) -> usize,
{
let key = a.index();
if let Some(result) = storage.operation_cache().get_cache1(&operator).get(&key) {
*result
} else {
let result = f(storage, a);
storage.operation_cache().get_cache1(&operator).insert(key, result);
result
}
}
pub fn cache_binary_op<F>(storage: &mut Storage, operator: BinaryOperator, a: &LddRef, b: &LddRef, f: F) -> Ldd
where
F: Fn(&mut Storage, &LddRef<'_>, &LddRef<'_>) -> Ldd,
{
let key = (a.index(), b.index());
if let Some(result) = storage.operation_cache().get_cache2(&operator).get(&key) {
let result = *result; storage.operation_cache().create(result)
} else {
let result = f(storage, a, b);
storage
.operation_cache()
.get_cache2(&operator)
.insert(key, result.index());
result
}
}
pub fn cache_comm_binary_op<F>(storage: &mut Storage, operator: BinaryOperator, a: &LddRef, b: &LddRef, f: F) -> Ldd
where
F: Fn(&mut Storage, &LddRef<'_>, &LddRef<'_>) -> Ldd,
{
if a.index() < b.index() {
cache_binary_op(storage, operator, a, b, f)
} else {
cache_binary_op(storage, operator, b, a, f)
}
}
pub fn cache_terniary_op<F>(
storage: &mut Storage,
operator: TernaryOperator,
a: &LddRef,
b: &LddRef,
c: &LddRef,
f: F,
) -> Ldd
where
F: Fn(&mut Storage, &LddRef<'_>, &LddRef<'_>, &LddRef<'_>) -> Ldd,
{
let key = (a.index(), b.index(), c.index());
if let Some(result) = storage.operation_cache().get_cache3(&operator).get(&key) {
let result = *result; storage.operation_cache().create(result)
} else {
let result = f(storage, a, b, c);
storage
.operation_cache()
.get_cache3(&operator)
.insert(key, result.index());
result
}
}