use std::hash::Hash;
use super::super::{identity::RowHandle, FastMap, HandleMap};
#[derive(Clone, Debug)]
pub struct HashIndex<K> {
by_key: FastMap<K, Vec<RowHandle>>,
key_of: HandleMap<K>,
retired: Vec<Vec<RowHandle>>,
}
impl<K> HashIndex<K>
where
K: Eq + Hash + Clone,
{
pub fn new() -> HashIndex<K> {
HashIndex {
by_key: FastMap::default(),
key_of: HandleMap::new(),
retired: Vec::new(),
}
}
fn take_bucket(&mut self, key: &K) -> Vec<RowHandle> {
match self.by_key.remove(key) {
Some(bucket) => bucket,
None => self.retired.pop().unwrap_or_default(),
}
}
fn put_bucket(&mut self, key: K, mut bucket: Vec<RowHandle>) {
if bucket.is_empty() {
bucket.clear();
self.retired.push(bucket);
} else {
self.by_key.insert(key, bucket);
}
}
pub fn insert(&mut self, handle: RowHandle, key: K) {
if let Some(old) = self.key_of.insert(handle, key.clone()) {
if old != key {
let mut bucket = self.take_bucket(&old);
if let Some(pos) = bucket.iter().position(|h| *h == handle) {
bucket.swap_remove(pos);
}
self.put_bucket(old, bucket);
} else if self.by_key.get(&key).is_some_and(|b| b.contains(&handle)) {
return;
}
}
let mut bucket = self.take_bucket(&key);
bucket.push(handle);
self.put_bucket(key, bucket);
}
pub(crate) fn insert_transient(&mut self, handle: RowHandle, key: K) {
let mut bucket = self.take_bucket(&key);
bucket.push(handle);
self.put_bucket(key, bucket);
}
pub fn remove(&mut self, handle: RowHandle) {
let Some(key) = self.key_of.remove(handle) else {
return;
};
let mut bucket = self.take_bucket(&key);
if let Some(pos) = bucket.iter().position(|h| *h == handle) {
bucket.swap_remove(pos);
}
self.put_bucket(key, bucket);
}
pub fn clear(&mut self) {
self.by_key.clear();
self.key_of.clear();
self.retired.clear();
}
#[inline]
pub fn lookup(&self, key: &K) -> &[RowHandle] {
self.by_key.get(key).map(Vec::as_slice).unwrap_or(&[])
}
}