use twox_hash::{RandomXxHashBuilder64, XxHash64};
use core::hash::{BuildHasher, Hash, Hasher};
use core::borrow::Borrow;
const MAX_LOAD_FACTOR: usize = 100_000;
const DEFAULT_BUCKETS_SIZE: usize = 4096 / std::mem::size_of::<usize>();
const DEFAULT_SLOT_SIZE: usize = 8;
#[derive(Clone, Hash, PartialEq)]
pub struct ArrayHashBuilder<H> {
hasher: H,
buckets_size: usize,
max_load_factor: usize,
slot_size: usize
}
impl Default for ArrayHashBuilder<XxHash64> {
fn default() -> ArrayHashBuilder<XxHash64> {
ArrayHashBuilder {
hasher: RandomXxHashBuilder64::default().build_hasher(),
buckets_size: DEFAULT_BUCKETS_SIZE,
max_load_factor: MAX_LOAD_FACTOR,
slot_size: DEFAULT_SLOT_SIZE
}
}
}
impl<'a, H, K, V> From<&'a ArrayHash<H, K, V>> for ArrayHashBuilder<H> where H: Clone + Hasher, K: Hash + PartialEq {
fn from(ah: &'a ArrayHash<H, K, V>) -> ArrayHashBuilder<H> {
let buckets = ah.buckets.as_ref().unwrap();
debug_assert!(buckets.len() > 0);
ArrayHashBuilder {
buckets_size: buckets.len(),
hasher: ah.hasher.clone(),
max_load_factor: ah.max_load_factor,
slot_size: buckets[0].len()
}
}
}
impl<H> ArrayHashBuilder<H> where H: core::hash::Hasher {
#[inline]
pub fn with_hasher(hasher: H) -> ArrayHashBuilder<H> {
ArrayHashBuilder {
hasher: hasher,
buckets_size: DEFAULT_BUCKETS_SIZE,
max_load_factor: MAX_LOAD_FACTOR,
slot_size: DEFAULT_SLOT_SIZE
}
}
#[inline]
pub fn hasher<H2>(self, hasher: H2) -> ArrayHashBuilder<H2> {
ArrayHashBuilder {
hasher,
buckets_size: self.buckets_size,
max_load_factor: self.max_load_factor,
slot_size: self.slot_size
}
}
pub fn buckets_size(mut self, size: usize) -> Self {
debug_assert!(size > 0);
self.buckets_size = size;
self
}
pub fn max_load_factor(mut self, factor: usize) -> Self {
debug_assert!(factor > 0);
self.max_load_factor = factor;
self
}
pub fn slot_size(mut self, size: usize) -> Self {
self.slot_size = size;
self
}
pub fn build<K, V>(self) -> ArrayHash<H, K, V> where H: core::hash::Hasher + Clone, K: core::hash::Hash + core::cmp::PartialEq {
ArrayHash {
buckets: Some((0..self.buckets_size).map(|_| Vec::with_capacity(self.slot_size)).collect()),
hasher: self.hasher,
capacity: self.buckets_size,
max_load_factor: self.max_load_factor,
size: 0
}
}
}
#[derive(Clone, Debug)]
pub struct ArrayHash<H, K, V> where H: core::hash::Hasher + Clone, K: core::hash::Hash + PartialEq {
buckets: Option<Box<[Vec<(K, V)>]>>,
hasher: H,
capacity: usize,
max_load_factor: usize,
size: usize
}
impl<H, K1, V1, K2, V2> PartialEq<ArrayHash<H, K1, V1>> for ArrayHash<H, K2, V2>
where H: Clone + Hasher + PartialEq,
K1: Hash + PartialEq + PartialEq<K2>,
V1: PartialEq<V2>,
K2: Hash + PartialEq
{
fn eq(&self, rhs: &ArrayHash<H, K1, V1>) -> bool {
self.is_hasher_eq(rhs) &&
self.capacity == rhs.capacity &&
self.size == rhs.size &&
rhs.buckets.as_deref().unwrap().iter().zip(self.buckets.as_deref().unwrap().iter()).all(|(rhs, lhs)| {
rhs.len() == lhs.len() && rhs.iter().zip(lhs.iter()).all(|((k1, v1), (k2, v2))| {k1 == k2 && v1 == v2})
})
}
}
impl<H, K, V> Hash for ArrayHash<H, K, V> where H: Hasher + Clone, K: Hash + PartialEq, V: Hash {
fn hash<H2: Hasher>(&self, hasher: &mut H2) {
self.buckets.hash(hasher);
}
}
impl<H, K, V> ArrayHash<H, K, V> where H: core::hash::Hasher + Clone, K: core::hash::Hash + PartialEq {
#[inline]
pub fn to_builder(&self) -> ArrayHashBuilder<H> {
ArrayHashBuilder::from(self)
}
#[inline]
pub fn is_hasher_eq<K2, V2>(&self, rhs: &ArrayHash<H, K2, V2>) -> bool
where H: PartialEq,
K2: Hash + PartialEq
{
self.hasher == rhs.hasher
}
pub fn put(&mut self, key: K, value: V) -> Option<(K, V)> {
let mut index = self.make_key(&key);
let result;
if let Some(i) = self.buckets.as_mut().unwrap()[index].iter().position(|(k, _)| *k == key) {
result = Some(self.buckets.as_mut().unwrap()[index].swap_remove(i));
} else {
self.size += 1;
if self.maybe_expand() {
index = self.make_key(&key);
}
result = None
}
self.buckets.as_mut().unwrap()[index].push((key, value));
result
}
pub fn try_put(&mut self, key: K, value: V) -> Result<&V, (K, V, &V)> {
let mut index = self.make_key(&key);
if let Some(i) = self.buckets.as_ref().unwrap()[index].iter().position(|(k, _)| *k == key) {
Err((key, value, &self.buckets.as_ref().unwrap()[index][i].1))
} else {
self.size += 1;
if self.maybe_expand() {
index = self.make_key(&key);
}
let bucket = &mut self.buckets.as_mut().unwrap()[index];
bucket.push((key, value));
Ok(&bucket[bucket.len() - 1].1)
}
}
pub fn get<T>(&self, key: &T) -> Option<&V> where T: core::hash::Hash + PartialEq<K> {
let index = self.make_key(&key);
let slot = &self.buckets.as_ref().unwrap()[index];
return slot.iter().find(|(k, _)| {key == k}).map(|(_, v)| v)
}
pub fn smart_get<T, Q>(&self, key: Q) -> Option<&V> where Q: core::ops::Deref<Target=T>, K: core::ops::Deref<Target=T>, T: core::hash::Hash + core::cmp::PartialEq {
let index = self.make_key(&*key);
let slot = &self.buckets.as_ref().unwrap()[index];
slot.iter().find(|(k, _)| **k == *key).map(|(_, v)| v)
}
pub fn coerce_get<T>(&self, key: &T) -> Option<&V> where T: core::hash::Hash + PartialEq + ?Sized, K: Borrow<T> {
let index = self.make_key(key);
let slot = &self.buckets.as_ref().unwrap()[index];
return slot.iter().find(|(k, _)| {key == k.borrow()}).map(|(_, v)| v)
}
pub fn remove<T>(&mut self, key: &T) -> Option<(K, V)> where T: core::hash::Hash + PartialEq<K> {
let slot_idx = self.make_key(key);
let slot = self.buckets.as_mut().unwrap();
let entry_idx = slot[slot_idx].iter().position(|(k, _)| {key == k});
if let Some(i) = entry_idx {
self.size -= 1;
Some(slot[slot_idx].swap_remove(i))
} else {
None
}
}
pub fn smart_remove<Q, T>(&mut self, key: Q) -> Option<(K, V)> where Q: core::ops::Deref<Target=T>, K: core::ops::Deref<Target=T>, T: core::hash::Hash + core::cmp::PartialEq {
let slot_idx = self.make_key(&*key);
let slot = self.buckets.as_mut().unwrap();
let entry_idx = slot[slot_idx].iter().position(|(k, _)| {*key == **k});
if let Some(i) = entry_idx {
self.size -= 1;
Some(slot[slot_idx].swap_remove(i))
} else {
None
}
}
pub fn coerce_remove<T>(&mut self, key: &T) -> Option<(K, V)> where T: core::hash::Hash + PartialEq + ?Sized, K: Borrow<T> {
let slot_idx = self.make_key(key);
let slot = self.buckets.as_mut().unwrap();
let entry_idx = slot[slot_idx].iter().position(|(k, _)| {key == k.borrow()});
if let Some(i) = entry_idx {
self.size -= 1;
Some(slot[slot_idx].swap_remove(i))
} else {
None
}
}
#[inline]
pub fn len(&self) -> usize {
self.size
}
pub fn contains_iter<'a, I>(&self, other: I) -> bool where I: IntoIterator<Item=&'a (K, V)>, K: 'a, V: 'a + PartialEq {
for (key, value) in other.into_iter() {
if let Some(v) = self.get(key) {
if v != value {
return false
}
} else {
return false
}
}
true
}
pub fn iter(&self) -> ArrayHashIterator<'_, K, V> {
let slots = self.buckets.as_ref().unwrap();
let mut buckets = slots.iter();
let first_iter = buckets.next().unwrap().iter();
ArrayHashIterator {
buckets: buckets,
current_iterator: first_iter,
size: self.size
}
}
pub fn iter_mut(&mut self) -> ArrayHashIterMut<'_, K, V> {
if self.size > 0 {
let buckets: Box<[core::slice::IterMut<(K, V)>]> = self.buckets.as_mut().unwrap().iter_mut().filter_map(|slot| {
if slot.len() > 0 {Some(slot.iter_mut())} else {None}
}).collect();
let remain_slots = buckets.len() - 1;
ArrayHashIterMut {
buckets,
remain_slots, slot_cursor: 0,
size: self.size
}
} else {
ArrayHashIterMut {
buckets: vec![[].iter_mut()].into_boxed_slice(),
remain_slots: 0,
slot_cursor: 0,
size: self.size
}
}
}
pub fn drain(&mut self) -> DrainIter<K, V> {
let mut bucket_iter = self.buckets.as_mut().unwrap().iter_mut();
let current_slot = bucket_iter.next();
self.size = 0;
DrainIter {
bucket_iter,
current_slot,
size: self.size
}
}
pub fn drain_with<F>(&mut self, pred: F) -> DrainWithIter<F, K, V> where F: Fn(&(K, V)) -> bool {
let mut bucket_iter = self.buckets.as_mut().unwrap().iter_mut();
let current_slot = bucket_iter.next();
let size = self.size;
DrainWithIter {
bucket_iter,
cur_size: &mut self.size,
current_slot,
predicate: pred,
size
}
}
pub fn split_by<F>(&mut self, pred: F) -> ArrayHash<H, K, V> where F: Fn(&(K, V)) -> bool {
let mut other = self.to_builder().build();
let buckets = self.buckets.as_mut().unwrap();
for i in 0..buckets.len() {
let mut j = 0;
loop {
if j >= buckets[i].len() {
break;
}
if pred(&buckets[i][j]) {
other.buckets.as_mut().unwrap()[i].push(buckets[i].swap_remove(j));
other.size += 1;
self.size -= 1;
} else {
j += 1;
}
}
}
other
}
#[inline(always)]
fn make_key<T>(&self, key: &T) -> usize where T: core::hash::Hash + ?Sized {
let mut local_hasher = self.hasher.clone();
key.hash(&mut local_hasher);
local_hasher.finish() as usize % self.capacity
}
#[inline(always)]
fn maybe_expand(&mut self) -> bool {
if self.size < self.max_load_factor {
return false
}
let old_buckets = self.buckets.take().unwrap().into_vec();
let new_capacity = self.capacity * 2;
self.capacity = new_capacity;
self.max_load_factor *= 2;
let mut buckets: Vec<Vec<(K, V)>> = (0..new_capacity).map(|_| Vec::with_capacity(old_buckets[0].len())).collect();
old_buckets.into_iter().for_each(|slot| {
for (key, value) in slot {
let index = self.make_key(&key);
buckets[index % new_capacity].push((key, value));
}
});
self.buckets = Some(buckets.into_boxed_slice());
true
}
}
#[derive(Debug)]
pub struct ArrayHashIterator<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {
buckets: core::slice::Iter<'a, Vec<(K, V)>>,
current_iterator: core::slice::Iter<'a, (K, V)>,
size: usize
}
impl<'a, K, V> Iterator for ArrayHashIterator<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {
type Item=&'a (K, V);
fn next(&mut self) -> Option<Self::Item> {
let mut result = self.current_iterator.next();
while result.is_none() {
if let Some(slot) = self.buckets.next() {
self.current_iterator = slot.iter();
result = self.current_iterator.next();
} else {
break
}
}
result
}
}
impl<'a, K, V> core::iter::FusedIterator for ArrayHashIterator<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {}
impl<'a, K, V> core::iter::ExactSizeIterator for ArrayHashIterator<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {
#[inline]
fn len(&self) -> usize {
self.size
}
}
#[derive(Debug)]
pub struct ArrayHashIterMut<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {
buckets: Box<[core::slice::IterMut<'a, (K, V)>]>,
remain_slots: usize,
slot_cursor: usize,
size: usize
}
impl<'a, K, V> Iterator for ArrayHashIterMut<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {
type Item=&'a mut (K, V);
fn next(&mut self) -> Option<Self::Item> {
let mut result = self.buckets[self.slot_cursor].next();
while result.is_none() {
if self.slot_cursor < self.remain_slots {
self.slot_cursor += 1;
result = self.buckets[self.slot_cursor].next();
} else {
break;
}
}
result
}
}
impl<'a, K, V> core::iter::FusedIterator for ArrayHashIterMut<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {}
impl<'a, K, V> core::iter::ExactSizeIterator for ArrayHashIterMut<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {
#[inline]
fn len(&self) -> usize {
self.size
}
}
#[derive(Debug)]
pub struct ArrayHashIntoIter<K, V> where K: core::hash::Hash + core::cmp::PartialEq {
buckets: std::vec::IntoIter<Vec<(K, V)>>,
current_iterator: std::vec::IntoIter<(K, V)>,
size: usize
}
impl<K, V> Iterator for ArrayHashIntoIter<K, V> where K: core::hash::Hash + core::cmp::PartialEq {
type Item=(K, V);
fn next(&mut self) -> Option<Self::Item> {
let mut result = self.current_iterator.next();
while result.is_none() {
if let Some(slot) = self.buckets.next() {
if slot.len() > 0 { self.current_iterator = slot.into_iter();
result = self.current_iterator.next();
}
} else {
break
}
}
result
}
}
impl<K, V> core::iter::FusedIterator for ArrayHashIntoIter<K, V> where K: core::hash::Hash + core::cmp::PartialEq {}
impl<K, V> core::iter::ExactSizeIterator for ArrayHashIntoIter<K, V> where K: core::hash::Hash + core::cmp::PartialEq {
#[inline]
fn len(&self) -> usize {
self.size
}
}
impl<H, K, V> IntoIterator for ArrayHash<H, K, V> where H: core::hash::Hasher + Clone, K: core::hash::Hash + core::cmp::PartialEq {
type Item=(K, V);
type IntoIter=ArrayHashIntoIter<K, V>;
fn into_iter(self) -> Self::IntoIter {
if self.size >= 1 {
let mut buckets = self.buckets.unwrap().into_vec().into_iter();
let current_iterator = buckets.next().unwrap().into_iter();
ArrayHashIntoIter {
buckets,
current_iterator,
size: self.size
}
} else {
let mut emptied_bucket = vec![vec![]].into_iter();
let emptied_iterator = emptied_bucket.next().unwrap().into_iter();
ArrayHashIntoIter {
buckets: emptied_bucket,
current_iterator: emptied_iterator,
size: 0
}
}
}
}
impl<'a, H, K, V> IntoIterator for &'a ArrayHash<H, K, V> where H: core::hash::Hasher + Clone, K: core::hash::Hash + core::cmp::PartialEq {
type Item=&'a(K, V);
type IntoIter=ArrayHashIterator<'a, K, V>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, H, K, V> IntoIterator for &'a mut ArrayHash<H, K, V> where H: core::hash::Hasher + Clone, K: core::hash::Hash + core::cmp::PartialEq {
type Item=&'a mut (K, V);
type IntoIter=ArrayHashIterMut<'a, K, V>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[derive(Debug)]
pub struct DrainIter<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {
bucket_iter: core::slice::IterMut<'a, Vec<(K, V)>>,
current_slot: Option<&'a mut Vec<(K, V)>>,
size: usize,
}
impl<'a, K, V> Iterator for DrainIter<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {
type Item=(K, V);
fn next(&mut self) -> Option<Self::Item> {
let mut result = self.current_slot.as_mut().unwrap().pop();
while result.is_none() {
self.current_slot = self.bucket_iter.next();
if self.current_slot.is_some() {
result = self.current_slot.as_mut().unwrap().pop();
} else {
break;
}
}
result
}
}
impl<'a, K, V> core::iter::FusedIterator for DrainIter<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {}
impl<'a, K, V> core::iter::ExactSizeIterator for DrainIter<'a, K, V> where K: core::hash::Hash + core::cmp::PartialEq {
#[inline]
fn len(&self) -> usize {
self.size
}
}
#[derive(Debug)]
pub struct DrainWithIter<'a, F, K, V> where F: for<'r> Fn(&'r (K, V)) -> bool, K: core::hash::Hash + core::cmp::PartialEq {
bucket_iter: core::slice::IterMut<'a, Vec<(K, V)>>,
cur_size: &'a mut usize,
current_slot: Option<&'a mut Vec<(K, V)>>,
predicate: F,
size: usize
}
impl<'a, F, K, V> Iterator for DrainWithIter<'a, F, K, V> where F: for<'r> Fn(&'r (K, V)) -> bool, K: core::hash::Hash + core::cmp::PartialEq {
type Item=(K, V);
fn next(&mut self) -> Option<Self::Item> {
while let Some(ref mut v) = self.current_slot {
for i in 0..v.len() {
if (self.predicate)(&v[i]) {
*self.cur_size -= 1;
return Some(v.swap_remove(i))
}
}
loop {
self.current_slot = self.bucket_iter.next();
if self.current_slot.is_some() {
if self.current_slot.as_ref().unwrap().len() == 0 {
continue;
} else {
break;
}
} else {
return None
}
}
}
None
}
}
impl<'a, F, K, V> core::iter::FusedIterator for DrainWithIter<'a, F, K, V> where F: for<'r> Fn(&'r (K, V)) -> bool, K: core::hash::Hash + core::cmp::PartialEq {}
impl<'a, F, K, V> core::iter::ExactSizeIterator for DrainWithIter<'a, F, K, V> where F: for<'r> Fn(&'r (K, V)) -> bool, K: core::hash::Hash + core::cmp::PartialEq {
#[inline]
fn len(&self) -> usize {
self.size
}
}
#[cfg(test)]
mod tests;