use alloc::{Alloc, InternedPtr};
use core::fmt;
use std::hash::{BuildHasher, Hash};
use std::ops::Index;
use clashmap::ClashCollection;
use hashbrown::HashTable;
use crate::Key;
mod alloc;
pub struct ParaCord<T, S = foldhash::fast::RandomState> {
slice_to_keys: ClashCollection<Collection<T>>,
keys_to_slice: boxcar::Vec<InternedPtr<T>>,
hasher: S,
}
impl<T: fmt::Debug, S> fmt::Debug for ParaCord<T, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
struct Collection<T> {
table: HashTable<*const InternedPtr<T>>,
alloc: Alloc<T>,
}
unsafe impl<T: Sync, S: Sync> Sync for ParaCord<T, S> {}
unsafe impl<T: Sync, S: Send> Send for ParaCord<T, S> {}
impl<T> Default for Collection<T> {
fn default() -> Self {
Self {
table: HashTable::default(),
alloc: Alloc::default(),
}
}
}
impl<T> Default for ParaCord<T> {
fn default() -> Self {
Self::with_hasher(foldhash::fast::RandomState::default())
}
}
impl<T, S: BuildHasher> ParaCord<T, S> {
pub fn with_hasher(hasher: S) -> Self {
Self {
keys_to_slice: boxcar::Vec::default(),
slice_to_keys: ClashCollection::default(),
hasher,
}
}
}
impl<T: Hash + Eq, S: BuildHasher> ParaCord<T, S> {
pub fn get(&self, s: &[T]) -> Option<Key> {
let hash = self.hasher.hash_one(s);
let shard = self.slice_to_keys.get_read_shard(hash);
let eq = |k: &*const InternedPtr<T>| unsafe { s == (**k).slice() };
let map = |k: &*const InternedPtr<T>| unsafe { (**k).key };
shard.table.find(hash, eq).map(map)
}
}
impl<T: Hash + Eq + Copy, S: BuildHasher> ParaCord<T, S> {
pub fn get_or_intern(&self, s: &[T]) -> Key {
let hash = self.hasher.hash_one(s);
let key = {
let eq = |k: &*const InternedPtr<T>| unsafe { s == (**k).slice() };
let map = |k: &*const InternedPtr<T>| unsafe { (**k).key };
let shard = self.slice_to_keys.get_read_shard(hash);
shard.table.find(hash, eq).map(map)
};
let Some(key) = key else {
return self.intern_slow(s, hash);
};
key
}
}
impl<T: Hash + Eq, S> ParaCord<T, S> {
pub fn try_resolve(&self, key: Key) -> Option<&[T]> {
let s = self.keys_to_slice.get(key.into_repr() as usize)?;
Some(s.slice())
}
pub fn resolve(&self, key: Key) -> &[T] {
self.keys_to_slice[key.into_repr() as usize].slice()
}
pub unsafe fn resolve_unchecked(&self, key: Key) -> &[T] {
unsafe { self.keys_to_slice.get_unchecked(key.into_repr() as usize) }.slice()
}
}
impl<T, S> ParaCord<T, S> {
pub fn len(&self) -> usize {
self.keys_to_slice.count()
}
pub fn is_empty(&self) -> bool {
self.keys_to_slice.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (Key, &[T])> {
self.into_iter()
}
pub fn clear(&mut self) {
self.keys_to_slice.clear();
self.slice_to_keys.shards_mut().iter_mut().for_each(|s| {
s.get_mut().table.clear();
drop(core::mem::take(&mut s.get_mut().alloc));
});
}
#[cfg(test)]
pub(crate) fn current_memory_usage(&mut self) -> usize {
let keys_size = self.keys_to_slice.count() * core::mem::size_of::<InternedPtr<T>>();
let shards_size = {
let acc = core::mem::size_of_val(self.slice_to_keys.shards());
self.slice_to_keys
.shards_mut()
.iter_mut()
.fold(acc, |acc, shard| {
let shard = shard.get_mut();
acc + shard.table.allocation_size() + shard.alloc.size()
})
};
size_of::<Self>() + keys_size + shards_size
}
}
impl<T: Hash + Eq + Copy, I: AsRef<[T]>, S: BuildHasher + Default> FromIterator<I>
for ParaCord<T, S>
{
fn from_iter<A: IntoIterator<Item = I>>(iter: A) -> Self {
let iter = iter.into_iter();
let len = iter.size_hint().0;
let mut this = Self {
keys_to_slice: boxcar::Vec::with_capacity(len),
slice_to_keys: ClashCollection::default(),
hasher: S::default(),
};
this.extend(iter);
this
}
}
impl<T: Hash + Eq + Copy, I: AsRef<[T]>, S: BuildHasher> Extend<I> for ParaCord<T, S> {
fn extend<A: IntoIterator<Item = I>>(&mut self, iter: A) {
for s in iter {
let s = s.as_ref();
let hash = self.hasher.hash_one(s);
self.intern_slow_mut(s, hash);
}
}
}
impl<T: Hash + Eq + Copy, S: BuildHasher> Index<Key> for ParaCord<T, S> {
type Output = [T];
fn index(&self, index: Key) -> &Self::Output {
self.resolve(index)
}
}
pub(crate) mod iter_private {
use super::InternedPtr;
use crate::Key;
pub struct Iter<'a, T> {
pub(super) inner: boxcar::Iter<'a, InternedPtr<T>>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = (Key, &'a [T]);
fn next(&mut self) -> Option<Self::Item> {
let (key, s) = self.inner.next()?;
Some(unsafe { (Key::new_unchecked(key as u32), s.slice()) })
}
}
}
impl<'a, T, S> IntoIterator for &'a ParaCord<T, S> {
type Item = (Key, &'a [T]);
type IntoIter = iter_private::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
iter_private::Iter {
inner: self.keys_to_slice.iter(),
}
}
}
#[cfg(test)]
mod tests {
use super::ParaCord;
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
fn inner_check_send_sync<T: 'static + Send + Sync>() {
is_send::<ParaCord<T>>();
is_sync::<ParaCord<T>>();
}
#[test]
fn check_send_sync() {
inner_check_send_sync::<()>();
}
}