use crate::hashmap;
use crate::hashmap::user;
use crate::hashmap::user::EntryT;
use crate::results::{InsertResult, InsertResultShared};
type LRUEntry<K, V, Umeta> =
user::Entry<K, V, ::std::marker::PhantomData<K>, Umeta>;
type HmapT<K, V, Umeta, HB> = hashmap::SimpleHmap<
LRUEntry<K, V, Umeta>,
K,
V,
::std::marker::PhantomData<K>,
Umeta,
HB,
>;
pub struct LRU<'a, K, V, Umeta, HB>
where
K: user::Hash,
V: user::Val,
Umeta: user::Meta<V>,
HB: ::std::hash::BuildHasher + Default,
{
_hmap: HmapT<K, V, Umeta, HB>,
_lru: LRUShared<
'a,
HmapT<K, V, Umeta, HB>,
LRUEntry<K, V, Umeta>,
K,
V,
::std::marker::PhantomData<K>,
Umeta,
HB,
>,
}
impl<
'a,
K: user::Hash,
V: user::Val,
Umeta: user::Meta<V>,
HB: ::std::hash::BuildHasher + Default,
> LRU<'a, K, V, Umeta, HB>
{
pub fn new(
entries: usize,
extra_hashmap_capacity: usize,
hash_builder: HB,
) -> LRU<'a, K, V, Umeta, HB> {
LRU {
_hmap: HmapT::<K, V, Umeta, HB>::with_capacity_and_hasher(
1 + entries + extra_hashmap_capacity,
hash_builder,
),
_lru: LRUShared::<
'_,
HmapT<K, V, Umeta, HB>,
LRUEntry<K, V, Umeta>,
K,
V,
::std::marker::PhantomData<K>,
Umeta,
HB,
>::new(entries, ::std::marker::PhantomData, None),
}
}
pub fn insert(&mut self, key: K, val: V) -> InsertResult<(K, V, Umeta)> {
self.insert_with_meta(key, val, Umeta::new())
}
pub fn insert_with_meta(
&mut self,
key: K,
val: V,
user_data: Umeta,
) -> InsertResult<(K, V, Umeta)> {
let e =
user::Entry::<K, V, ::std::marker::PhantomData<K>, Umeta>::new_entry(
None,
None,
key.clone(),
val,
::std::marker::PhantomData,
user_data,
);
let (mut maybe_clash, new_entry_idx, _new_entry) = self._hmap.insert(e);
let opt_ref_clash = maybe_clash.as_mut();
match self._lru.insert_shared(
&mut self._hmap,
opt_ref_clash,
new_entry_idx,
) {
InsertResultShared::OldEntry { evicted } => {
let c = match maybe_clash {
None => None,
Some(x) => Some(x.deconstruct()),
};
let e = match evicted {
None => None,
Some(x) => Some(x.deconstruct()),
};
InsertResult::OldEntry {
clash: c,
evicted: e,
}
}
InsertResultShared::OldTailPtr { evicted } => {
let c = match maybe_clash {
None => None,
Some(x) => Some(x.deconstruct()),
};
let removed = self._hmap.remove(unsafe { &*evicted.as_ptr() });
InsertResult::OldTail {
clash: c,
evicted: removed.deconstruct(),
}
}
InsertResultShared::Success => match maybe_clash {
None => InsertResult::Success,
Some(clash) => InsertResult::OldEntry {
clash: Some(clash.deconstruct()),
evicted: None,
},
},
}
}
pub fn clear(&mut self) {
self._hmap.clear();
self._lru.clear_shared()
}
pub fn remove(&mut self, key: &K) -> Option<(V, Umeta)> {
let (idx, entry) = match self._hmap.get_full(key) {
None => return None,
Some((idx, entry)) => (idx, entry),
};
self._lru.remove_shared(entry);
let (_, val, meta) = self._hmap.remove_idx(idx).deconstruct();
Some((val, meta))
}
pub fn contains_key(&self, key: &K) -> bool {
self._hmap.get_full(&key).is_some()
}
pub fn make_head(&mut self, key: &K) -> Option<(&V, &Umeta)> {
match self._hmap.get_full_mut(key) {
None => None,
Some((_, mut entry)) => {
self._lru.make_head(&mut entry);
Some((entry.get_val(), entry.get_user()))
}
}
}
pub fn get(&mut self, key: &K) -> Option<(&V, &Umeta)> {
match self._hmap.get_full_mut(key) {
None => None,
Some((_, mut entry)) => {
self._lru.on_get(&mut entry);
Some((entry.get_val(), entry.get_user()))
}
}
}
pub fn get_mut(&mut self, key: &K) -> Option<(&mut V, &mut Umeta)> {
match self._hmap.get_full_mut(key) {
None => None,
Some((_, mut entry)) => {
self._lru.on_get(&mut entry);
Some(entry.get_val_user_mut())
}
}
}
}
pub struct LRUShared<'a, Hmap, E, K, V, CidT, Umeta, HB>
where
Hmap: hashmap::HashMap<E, K, V, CidT, Umeta, HB>,
E: user::EntryT<K, V, CidT, Umeta>,
K: user::Hash,
V: user::Val,
CidT: user::Cid,
Umeta: user::Meta<V>,
HB: ::std::hash::BuildHasher + Default,
{
_capacity: usize,
_used: usize,
_head: Option<::std::ptr::NonNull<E>>,
_tail: Option<::std::ptr::NonNull<E>>,
_cache_id: CidT,
_hmap: ::std::marker::PhantomData<Hmap>,
_key: ::std::marker::PhantomData<K>,
_val: ::std::marker::PhantomData<V>,
_meta: ::std::marker::PhantomData<Umeta>,
_hashbuilder: ::std::marker::PhantomData<HB>,
_scan: crate::scan::Scan<'a, E, K, V, CidT, Umeta>,
}
impl<
'a,
Hmap: hashmap::HashMap<E, K, V, CidT, Umeta, HB>,
E: user::EntryT<K, V, CidT, Umeta>,
K: user::Hash,
V: user::Val,
CidT: user::Cid,
Umeta: user::Meta<V>,
HB: ::std::hash::BuildHasher + Default,
> LRUShared<'a, Hmap, E, K, V, CidT, Umeta, HB>
{
pub fn new(
entries: usize,
cache_id: CidT,
access_scan: Option<&'a dyn Fn(::std::ptr::NonNull<E>) -> ()>,
) -> Self {
LRUShared {
_capacity: entries,
_used: 0,
_head: None,
_tail: None,
_cache_id: cache_id,
_hmap: ::std::marker::PhantomData,
_key: ::std::marker::PhantomData,
_val: ::std::marker::PhantomData,
_meta: ::std::marker::PhantomData,
_hashbuilder: std::marker::PhantomData,
_scan: crate::scan::Scan::new(access_scan),
}
}
pub fn set_scanf(
&mut self,
access_scan: Option<&'a dyn Fn(::std::ptr::NonNull<E>) -> ()>,
) {
self._scan.set_scanf(access_scan)
}
pub fn insert_shared(
&mut self,
hmap: &mut Hmap,
maybe_old_entry: Option<&mut E>,
new_entry_idx: usize,
) -> InsertResultShared<E> {
let just_inserted = hmap.get_index_mut(new_entry_idx).unwrap();
self._used += 1;
self._scan.apply_raw(just_inserted.into());
*just_inserted.get_cache_id_mut() = self._cache_id;
match maybe_old_entry {
None => {
just_inserted.user_on_insert(None);
if self._used >= self._capacity {
unsafe {
self._head
.unwrap()
.as_mut()
.set_head_ptr(Some(just_inserted.into()));
}
self._head = Some(just_inserted.into());
let mut to_remove = self._tail.unwrap();
self._scan.check_and_next(to_remove);
self._scan.apply_next();
unsafe {
let mut to_rm_head =
to_remove.as_mut().get_head_ptr().unwrap();
to_rm_head.as_mut().set_tail_ptr(None);
self._tail = Some(to_rm_head);
return InsertResultShared::OldTailPtr {
evicted: to_remove,
};
}
}
match self._head {
None => {
self._head = Some(just_inserted.into());
self._tail = Some(just_inserted.into());
}
Some(mut old_head) => {
unsafe {
old_head
.as_mut()
.set_head_ptr(Some(just_inserted.into()))
};
self._head = Some(just_inserted.into());
self._scan.apply_next();
}
}
return InsertResultShared::Success;
}
Some(old_entry) => {
just_inserted.user_on_insert(Some(old_entry));
self._scan.check_and_next((old_entry).into());
self._scan.apply_next();
match old_entry.get_head_ptr() {
None => {
just_inserted.set_tail_ptr(old_entry.get_tail_ptr());
match old_entry.get_tail_ptr() {
None => {
self._tail = Some(just_inserted.into());
}
Some(mut old_entry_tail) => {
unsafe {
old_entry_tail.as_mut().set_head_ptr(Some(
just_inserted.into(),
));
}
}
}
self._head = Some(just_inserted.into());
return InsertResultShared::OldEntry { evicted: None };
}
Some(mut old_entry_head) => {
match old_entry.get_tail_ptr() {
None => {
unsafe {
old_entry_head.as_mut().set_tail_ptr(None);
self._head.unwrap().as_mut().set_head_ptr(
Some(just_inserted.into()),
);
}
self._head = Some(just_inserted.into());
self._tail = Some(old_entry_head);
return InsertResultShared::OldEntry {
evicted: None,
};
}
Some(mut old_entry_tail) => {
unsafe {
old_entry_tail
.as_mut()
.set_head_ptr(old_entry.get_head_ptr());
old_entry
.get_head_ptr()
.unwrap()
.as_mut()
.set_tail_ptr(old_entry.get_tail_ptr());
self._head.unwrap().as_mut().set_head_ptr(
Some(just_inserted.into()),
);
}
self._head = Some(just_inserted.into());
return InsertResultShared::OldEntry {
evicted: None,
};
}
}
}
}
}
}
}
pub fn clear_shared(&mut self) {
self._head = None;
self._tail = None;
self._scan.stop();
}
pub fn remove_shared(&mut self, entry: &E) {
self._scan.check_and_next(entry.into());
if None == entry.get_head_ptr() {
match entry.get_tail_ptr() {
None => {
self._head = None;
self._tail = None;
}
Some(mut entry_tail) => {
unsafe {
entry_tail.as_mut().set_head_ptr(None);
}
self._head = Some(entry_tail);
}
}
} else {
match entry.get_tail_ptr() {
None => {
unsafe {
entry
.get_head_ptr()
.unwrap()
.as_mut()
.set_tail_ptr(None);
}
self._tail = entry.get_head_ptr();
}
Some(mut entry_tail) => {
unsafe {
entry_tail.as_mut().set_head_ptr(entry.get_head_ptr());
entry
.get_head_ptr()
.unwrap()
.as_mut()
.set_tail_ptr(entry.get_tail_ptr());
}
}
}
}
}
pub fn make_head(&mut self, entry: &mut E) {
self._scan.check_and_next(entry.into());
match entry.get_head_ptr() {
None => {
}
Some(mut entry_head) => {
unsafe {
entry_head.as_mut().set_tail_ptr(entry.get_tail_ptr());
}
match entry.get_tail_ptr() {
None => {
unsafe {
self._head
.unwrap()
.as_mut()
.set_head_ptr(Some(entry.into()));
entry.set_tail_ptr(self._head);
}
self._head = Some(entry.into());
self._tail = Some(entry_head);
}
Some(mut entry_tail) => {
unsafe {
entry_tail.as_mut().set_head_ptr(Some(entry_head));
entry_head.as_mut().set_tail_ptr(Some(entry_tail));
self._head
.unwrap()
.as_mut()
.set_head_ptr(Some(entry.into()));
}
self._head = Some(entry.into());
}
}
}
}
}
pub fn get_cache_id(&self) -> CidT {
self._cache_id
}
pub fn on_get(&mut self, entry: &mut E) {
entry.user_on_get();
self._scan.apply_next();
}
pub fn start_scan(&mut self) {
match self._scan.is_running() {
false => match self._head {
Some(head) => self._scan.start_scan(head),
None => {}
},
true => {}
}
}
pub fn is_scan_running(&self) -> bool {
self._scan.is_running()
}
pub fn capacity(&self) -> usize {
self._capacity
}
pub fn len(&self) -> usize {
self._used
}
}