use crate::compat::*;
use hashbrown::hash_table as raw;
use hashbrown::HashTable as RawTable;
use crate::util::hash_one;
use super::{Element, Key, MaybeHash};
#[derive(Clone)]
pub(crate) struct Table<K, V, S> {
pub(crate) table: RawTable<(K, V)>,
hash_builder: S,
}
pub(crate) struct OccupiedEntry<'a, K: Element, V: Element> {
pub(crate) inner: raw::OccupiedEntry<'a, (K, V)>,
k_handle: K::Handle,
v_handle: V::Handle,
}
pub(crate) struct VacantEntry<'a, K: Element, V> {
inner: raw::VacantEntry<'a, (K, V)>,
pending_key: K::Owned,
pending_key_hash: K::CachedHash,
}
pub(crate) enum Entry<'a, K: Key, V: Element> {
Occupied(OccupiedEntry<'a, K, V>),
Vacant(VacantEntry<'a, K, V>),
}
impl<K, V, S> Table<K, V, S> {
pub(crate) fn new(capacity: usize, hash_builder: S) -> Self {
Self {
table: RawTable::with_capacity(capacity),
hash_builder,
}
}
pub(crate) fn hasher(&self) -> &S {
&self.hash_builder
}
pub(crate) fn capacity(&self) -> usize {
self.table.capacity()
}
pub(crate) fn len(&self) -> usize {
self.table.len()
}
pub(crate) fn load_factor(&self) -> f32 {
let n_buckets = self.table.num_buckets();
if n_buckets == 0 {
0.0 } else {
self.len() as f32 / n_buckets as f32
}
}
pub(crate) fn clear(&mut self) {
self.table.clear();
}
}
impl<K: Element, V: Element, S> Table<K, V, S> {
pub(crate) fn remove_expired_inner(&mut self) {
self.table
.retain(|(k, v)| !(k.is_expired() || v.is_expired()));
}
pub(crate) fn remove_expired(&mut self) {
self.remove_expired_inner();
}
}
impl<K: Key, V: Element, S: BuildHasher> Table<K, V, S> {
fn make_hasher(hash_builder: &S) -> impl Fn(&(K, V)) -> u64 + '_ {
move |(k, _)| k.hash(hash_builder)
}
#[inline]
pub(crate) fn try_reserve(&mut self, additional: usize) -> Result<(), crate::TryReserveError> {
if self.table.len().saturating_add(additional) <= self.table.capacity() {
return Ok(());
}
self.gc_and_try_grow(additional)
}
#[cold]
fn gc_and_try_grow(&mut self, additional: usize) -> Result<(), crate::TryReserveError> {
self.remove_expired_inner();
let new_len = self.len();
let expected_len = new_len
.checked_add(additional)
.ok_or(crate::TryReserveError::CapacityOverflow)?;
let desired_capacity = desired_capacity_for(expected_len);
if self.capacity() >= desired_capacity {
return Ok(());
}
let growth = desired_capacity - new_len;
self.table
.try_reserve(growth, Self::make_hasher(&self.hash_builder))
.map_err(crate::TryReserveError::from_hashbrown)
}
pub(crate) fn shrink_to_fit(&mut self) {
self.remove_expired_inner();
self.table
.shrink_to_fit(Self::make_hasher(&self.hash_builder));
}
pub(crate) fn shrink_to(&mut self, min_capacity: usize) {
if self.capacity() <= min_capacity {
return;
}
self.remove_expired_inner();
if self.capacity() > min_capacity {
self.table
.shrink_to(min_capacity, Self::make_hasher(&self.hash_builder));
}
}
pub(crate) fn entry(&mut self, key: K::Owned) -> Entry<'_, K, V> {
let hash = K::hash_owned(&key, &self.hash_builder);
self.try_reserve(1)
.expect("Unable to allocate space for entry!");
match self.table.entry(
hash,
|(k, _v)| k.eq_owned(&key),
Self::make_hasher(&self.hash_builder),
) {
raw::Entry::Occupied(mut occupied_entry) => {
let (k, v) = occupied_entry.get_mut();
if let Some(v_handle) = v.handle() {
let k_handle = K::handle_from_owned(&key);
k.reset_from_handle(&k_handle);
Entry::Occupied(OccupiedEntry {
inner: occupied_entry,
k_handle,
v_handle,
})
} else {
let ((_k, _v), vacant_entry) = occupied_entry.remove();
Entry::Vacant(VacantEntry {
inner: vacant_entry,
pending_key: key,
pending_key_hash: K::CachedHash::new(hash),
})
}
}
raw::Entry::Vacant(vacant_entry) => {
Entry::Vacant(VacantEntry {
inner: vacant_entry,
pending_key: key,
pending_key_hash: K::CachedHash::new(hash),
})
}
}
}
pub(crate) fn find_entry<Q>(&mut self, key: &Q) -> Option<OccupiedEntry<'_, K, V>>
where
Q: ?Sized + Hash + Eq,
K::Key: Borrow<Q>,
{
let hash = hash_one(&self.hash_builder, key);
match self.table.find_entry(hash, |(k, _)| k.eq_borrow(key)) {
Ok(occupied_entry) => {
let (k, v) = occupied_entry.get();
let (k_handle, v_handle) = (k.handle()?, v.handle()?);
Some(OccupiedEntry {
inner: occupied_entry,
k_handle,
v_handle,
})
}
Err(_absent_entry) => {
None
}
}
}
pub(crate) fn find<Q>(&self, key: &Q) -> Option<(K::Ref<'_>, V::Ref<'_>)>
where
Q: ?Sized + Hash + Eq,
K::Key: Borrow<Q>,
{
let hash = hash_one(&self.hash_builder, key);
let (k, v) = self.table.find(hash, |(k, _)| k.eq_borrow(key))?;
Some((k.as_ref()?, v.as_ref()?))
}
}
impl<K, V, S> Table<K, V, S> {
pub(crate) fn iter(&self) -> Iter<'_, K, V> {
Iter(self.table.iter())
}
pub(crate) fn into_iter(self) -> IntoIter<K, V> {
IntoIter(self.table.into_iter())
}
pub(crate) fn drain(&mut self) -> Drain<'_, K, V> {
Drain(self.table.drain())
}
}
impl<K: Key, T, S: BuildHasher> Table<K, super::Owned<T>, S> {
pub(crate) fn find_mut<Q>(&mut self, key: &Q) -> Option<(K::Ref<'_>, &mut T)>
where
Q: ?Sized + Hash + Eq,
K::Key: Borrow<Q>,
{
let hash = hash_one(&self.hash_builder, key);
let (k, v) = self.table.find_mut(hash, |(k, _)| k.eq_borrow(key))?;
Some((k.as_ref()?, &mut v.val))
}
pub(crate) fn get_disjoint_mut<Q, const N: usize>(
&mut self,
ks: [&Q; N],
) -> [Option<(K::Ref<'_>, &mut T)>; N]
where
Q: Hash + Eq + ?Sized,
K::Key: Borrow<Q>,
{
let hashes: [u64; N] = ks.map(|query| hash_one(&self.hash_builder, query));
self.table
.get_disjoint_mut(hashes, |idx, (k, _)| k.eq_borrow(ks[idx]))
.map(|ent| {
let (k, v) = ent?;
Some((k.as_ref()?, &mut v.val))
})
}
}
impl<K, T, S> Table<K, super::Owned<T>, S> {
pub(crate) fn iter_mut(&mut self) -> IterMut<'_, K, super::Owned<T>> {
IterMut(self.table.iter_mut())
}
}
impl<'a, K: Element, V: Element> OccupiedEntry<'a, K, V> {
pub(crate) fn get(&'a self) -> (&'a K::Owned, &'a V::Owned) {
let (k, v) = self.inner.get();
(
K::owned_ref_from_handle(k, &self.k_handle),
V::owned_ref_from_handle(v, &self.v_handle),
)
}
pub(crate) fn remove(self) -> (K::Owned, V::Owned) {
let ((k, v), _vacant) = self.inner.remove();
(
K::owned_from_handle(k, self.k_handle),
V::owned_from_handle(v, self.v_handle),
)
}
}
impl<'a, K: Element, V: Element<CachedHash = ()>> OccupiedEntry<'a, K, V> {
pub(crate) fn insert(&mut self, value: V::Owned) -> V::Owned {
let (_k, v) = self.inner.get_mut();
let (mut new_val, mut v_handle) = V::from_owned(value, ());
mem::swap(v, &mut new_val);
mem::swap(&mut self.v_handle, &mut v_handle);
V::owned_from_handle(new_val, v_handle)
}
}
impl<'a, K: Element, T> OccupiedEntry<'a, K, super::Owned<T>> {
pub(crate) fn into_mut(self) -> &'a mut T {
&mut self.inner.into_mut().1.val
}
}
impl<'a, K: Element, V: Element<CachedHash = ()>> VacantEntry<'a, K, V> {
pub(crate) fn insert(self, val: V::Owned) -> OccupiedEntry<'a, K, V> {
let (key, k_handle) = K::from_owned(self.pending_key, self.pending_key_hash);
let (val, v_handle) = V::from_owned(val, ());
let occupied = self.inner.insert((key, val));
OccupiedEntry {
inner: occupied,
k_handle,
v_handle,
}
}
}
impl<'a, K: Element, V: Element> VacantEntry<'a, K, V> {
pub(crate) fn into_key(self) -> K::Owned {
self.pending_key
}
pub(crate) fn key(&self) -> &K::Owned {
&self.pending_key
}
}
#[derive(Debug, Clone)]
pub(crate) struct Iter<'a, K, V>(raw::Iter<'a, (K, V)>);
impl<'a, K: Element, V: Element> Iterator for Iter<'a, K, V> {
type Item = (K::Ref<'a>, V::Ref<'a>);
fn next(&mut self) -> Option<Self::Item> {
for (k, v) in &mut self.0 {
if let (Some(k_ref), Some(v_ref)) = (k.as_ref(), v.as_ref()) {
return Some((k_ref, v_ref));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
#[derive(Debug)]
pub(crate) struct IterMut<'a, K, V>(raw::IterMut<'a, (K, V)>);
impl<'a, K: Element, T> Iterator for IterMut<'a, K, super::Owned<T>> {
type Item = (K::Ref<'a>, &'a mut T);
fn next(&mut self) -> Option<Self::Item> {
for (k, super::Owned { val }) in &mut self.0 {
if let Some(k_ref) = k.as_ref() {
return Some((k_ref, val));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
#[derive(Debug)]
pub(crate) struct IntoIter<K, V>(raw::IntoIter<(K, V)>);
impl<K: Element, V: Element> Iterator for IntoIter<K, V> {
type Item = (K::Owned, V::Owned);
fn next(&mut self) -> Option<Self::Item> {
for (k, v) in &mut self.0 {
if let (Some(k_owned), Some(v_owned)) = (k.into_owned(), v.into_owned()) {
return Some((k_owned, v_owned));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
#[derive(Debug)]
pub(crate) struct Drain<'a, K, V>(raw::Drain<'a, (K, V)>);
impl<'a, K: Element, V: Element> Iterator for Drain<'a, K, V> {
type Item = (K::Owned, V::Owned);
fn next(&mut self) -> Option<Self::Item> {
for (k, v) in &mut self.0 {
if let (Some(k_owned), Some(v_owned)) = (k.into_owned(), v.into_owned()) {
return Some((k_owned, v_owned));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.0.size_hint().1)
}
}
impl<K: Element, V: Element, S> Table<K, V, S> {
pub(crate) fn extract_if<'a, F>(&'a mut self, f: F) -> ExtractIf<'a, K, V>
where
F: FnMut(&mut (K, V)) -> bool + 'a,
{
let iter = Box::new(
self.table
.extract_if(f)
.filter_map(|(k, v)| Some((k.into_owned()?, v.into_owned()?))),
);
ExtractIf { iter }
}
}
pub(crate) struct ExtractIf<'a, K: Element, V: Element> {
iter: Box<dyn Iterator<Item = (K::Owned, V::Owned)> + 'a>,
}
impl<'a, K: Element, V: Element> Iterator for ExtractIf<'a, K, V> {
type Item = (K::Owned, V::Owned);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.iter.size_hint().1)
}
}
impl<'a, K: Element, V: Element> fmt::Debug for OccupiedEntry<'a, K, V>
where
K::Owned: fmt::Debug,
V::Owned: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (k, v) = self.get();
f.debug_struct("OccupiedEntry")
.field("key", k)
.field("val", v)
.finish()
}
}
impl<'a, K: Element, V: Element> fmt::Debug for VacantEntry<'a, K, V>
where
K::Owned: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let k = self.key();
f.debug_struct("VacantEntry").field("key", k).finish()
}
}
fn desired_capacity_for(len: usize) -> usize {
div_ceil(len, 3) * 4 + 1
}
fn div_ceil(a: usize, b: usize) -> usize {
a.saturating_add(b - 1) / b
}
#[cfg(test)]
mod test {
#![allow(clippy::unwrap_used)]
use super::*;
use crate::compat::rc::{Rc, Weak};
use crate::inner::{Owned, WeakK, WeakV};
use crate::util::hash_one;
type WkKeyMap = Table<WeakK<Weak<u8>>, Owned<u8>, RandomState>;
type WkWkMap = Table<WeakK<Weak<u8>>, WeakV<Weak<u8>>, RandomState>;
type WkValMap = Table<Owned<u8>, WeakV<Weak<u8>>, RandomState>;
impl<'a, K: Key, V: Element> super::Entry<'a, K, V> {
fn unwrap_occupied(self) -> OccupiedEntry<'a, K, V> {
match self {
Entry::Occupied(e) => e,
Entry::Vacant(_) => panic!("Entry was not occupied"),
}
}
fn unwrap_vacant(self) -> VacantEntry<'a, K, V> {
match self {
Entry::Occupied(_) => panic!("Entry was not vacant"),
Entry::Vacant(e) => e,
}
}
}
#[test]
fn construct() {
for cap in 0..64 {
let tab = WkKeyMap::new(cap, RandomState::default());
assert!(tab.capacity() >= cap);
}
}
#[test]
fn get_hasher() {
let rs = RandomState::default();
let tab = WkKeyMap::new(7, rs.clone());
assert_eq!(hash_one(&rs, &13_u8), hash_one(tab.hasher(), &13_u8));
}
#[test]
fn insert_len_clear() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let mut persist_keys = vec![];
for n in 0..200 {
let cap_orig = tab.capacity();
let should_grow = tab.len() == tab.capacity();
let k = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(n);
persist_keys.push(k);
assert_eq!(should_grow, tab.capacity() != cap_orig);
assert_eq!(tab.len(), persist_keys.len());
assert!(tab.capacity() >= tab.len());
}
let cap = tab.capacity();
tab.clear();
assert_eq!(tab.len(), 0);
assert_eq!(tab.capacity(), cap);
}
#[test]
fn insert_and_expire() {
let mut tab = WkKeyMap::new(7, RandomState::default());
let cap_initial = tab.capacity();
for n in 0..200 {
let k = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(n);
drop(k);
}
assert_eq!(tab.capacity(), cap_initial);
let mut persist_keys = vec![];
for n in 0..(cap_initial as u8 - 1) {
let k = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(n);
persist_keys.push(k);
}
for n in cap_initial as u8..200 {
let k = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(n);
}
assert!(tab.capacity() > cap_initial);
assert!(tab.capacity() < 150);
}
#[test]
fn shrink_to_fit() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let mut persist_keys = vec![];
for n in 0..200 {
let k = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(n);
persist_keys.push(k);
}
let cap = tab.capacity();
let buckets = tab.table.num_buckets();
assert_eq!(tab.len(), 200);
persist_keys.truncate(17);
assert_eq!(tab.len(), 200);
assert_eq!(tab.capacity(), cap);
tab.remove_expired_inner();
assert_eq!(tab.len(), 17);
assert!(tab.capacity() < cap);
assert_eq!(tab.table.num_buckets(), buckets);
tab.shrink_to_fit();
assert!(tab.capacity() >= 17);
assert!(tab.capacity() < cap);
assert_eq!(tab.len(), 17);
assert!(tab.table.num_buckets() < buckets);
}
#[test]
fn entry_and_find() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let u8_7 = Rc::new(7);
let u8_9 = Rc::new(9);
let u8_11 = Rc::new(11);
tab.entry(u8_7.clone()).unwrap_vacant().insert(7);
tab.entry(u8_9.clone()).unwrap_vacant().insert(9);
tab.entry(u8_11.clone()).unwrap_vacant().insert(11);
drop(u8_9);
assert_eq!(tab.find(&7).unwrap(), (u8_7.clone(), &7));
assert!(tab.find(&9).is_none());
let u8_7_other = Rc::new(7);
assert!(!Rc::ptr_eq(&u8_7, &u8_7_other));
let e = tab.entry(u8_7_other.clone()).unwrap_occupied();
assert_eq!(e.get().1, &7);
assert_eq!(e.get().0, &u8_7_other);
assert!(Rc::ptr_eq(&e.inner.get().0.handle().unwrap(), &u8_7_other));
*e.into_mut() = 77;
let e = tab.find_entry(&7).unwrap();
assert_eq!(e.get().1, &77);
assert_eq!(e.get().0, &u8_7_other);
assert_eq!(tab.find(&7).unwrap(), (u8_7, &77));
assert!(tab.find_entry(&9).is_none());
let u8_9 = Rc::new(9);
let e = tab.entry(u8_9.clone()).unwrap_vacant();
let e = e.insert(99);
assert_eq!(e.get().1, &99);
assert!(Rc::ptr_eq(&e.inner.get().0.handle().unwrap(), &u8_9));
let e = tab.find_entry(&9).unwrap();
assert_eq!(e.get().1, &99);
assert_eq!(tab.find(&9).unwrap(), (u8_9, &99));
let u8_13 = Rc::new(13);
assert!(tab.find_entry(&13).is_none());
let e = tab.entry(u8_13.clone()).unwrap_vacant();
assert_eq!(e.key().as_ref(), &13);
assert_eq!(e.into_key(), Rc::new(13));
assert!(tab.find(&13).is_none());
}
#[test]
fn entry_remove_replace() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let u8_7 = Rc::new(7);
let u8_9 = Rc::new(9);
let u8_11 = Rc::new(11);
tab.entry(u8_7.clone()).unwrap_vacant().insert(7);
tab.entry(u8_9.clone()).unwrap_vacant().insert(9);
tab.entry(u8_11.clone()).unwrap_vacant().insert(11);
drop(u8_9);
let mut e = tab.entry(u8_7.clone()).unwrap_occupied();
let old = e.insert(77);
assert_eq!(old, 7);
assert_eq!(e.get().1, &77);
let e = tab.entry(u8_11.clone()).unwrap_occupied();
let old = e.remove();
assert_eq!(&old.0, &u8_11);
assert_eq!(old.1, 11);
let v: Vec<_> = tab.into_iter().collect();
assert_eq!(v, vec![(u8_7, 77)]);
}
#[test]
fn find_mut() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let u8_7 = Rc::new(7);
let u8_9 = Rc::new(9);
let u8_11 = Rc::new(11);
tab.entry(u8_7.clone()).unwrap_vacant().insert(7);
tab.entry(u8_9.clone()).unwrap_vacant().insert(9);
tab.entry(u8_11.clone()).unwrap_vacant().insert(11);
drop(u8_9);
assert!(tab.find_mut(&9).is_none());
assert!(tab.find_mut(&99).is_none());
let (k, v) = tab.find_mut(&7).unwrap();
assert_eq!(k, u8_7);
assert_eq!(*v, 7);
*v = 17;
assert_eq!(tab.find(&7).unwrap().1, &17);
}
fn check_size_hint_ok(actual: usize, hint: (usize, Option<usize>)) {
assert!(actual >= hint.0);
if let Some(high) = hint.1 {
assert!(actual <= high);
}
}
#[test]
fn disjoint_mut() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let mut persist_keys = vec![];
for n in 0..=15 {
let k = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(0);
persist_keys.push(k);
}
let [three, seven, ten, fifty_five] = tab.get_disjoint_mut([&3, &7, &10, &55]);
*three.unwrap().1 = 3;
*seven.unwrap().1 = 7;
*ten.unwrap().1 = 10;
assert!(fifty_five.is_none());
assert_eq!(tab.find(&3).unwrap().1, &3);
assert_eq!(tab.find(&7).unwrap().1, &7);
assert_eq!(tab.find(&10).unwrap().1, &10);
assert_eq!(tab.find(&12).unwrap().1, &0);
assert_eq!(persist_keys.pop(), Some(Rc::new(15)));
let [x, y] = tab.get_disjoint_mut([&1, &15]);
assert!(x.is_some());
assert!(y.is_none());
}
#[test]
#[should_panic]
fn disjoint_mut_panic() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let mut persist_keys = vec![];
for n in 0..=15 {
let k = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(0);
persist_keys.push(k);
}
let _only_one_present = tab.get_disjoint_mut([&5, &5, &5, &5]);
}
#[test]
fn iters_simple() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let mut persist_keys = vec![];
for n in 0..=15 {
let k = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(n);
if n & 1 == 1 {
persist_keys.push(k);
}
}
let len = persist_keys.len();
let itermut = tab.iter_mut();
check_size_hint_ok(len, itermut.size_hint());
let mut count = 0;
for (k, v) in itermut {
count += 1;
assert!(persist_keys.contains(&k));
*v *= *v;
}
assert_eq!(count, persist_keys.len());
for k in persist_keys.iter() {
assert_eq!(*tab.find(k).unwrap().1, k.as_ref() * k.as_ref());
}
let iter = tab.iter();
check_size_hint_ok(len, iter.size_hint());
let mut count = 0;
for (k, v) in iter {
count += 1;
assert_eq!(*v, k.as_ref() * k.as_ref());
}
assert_eq!(count, persist_keys.len());
let mut count = 0;
let intoiter = tab.into_iter();
check_size_hint_ok(len, intoiter.size_hint());
for (k, v) in intoiter {
count += 1;
assert_eq!(v, k.as_ref() * k.as_ref());
}
assert_eq!(count, persist_keys.len());
}
#[test]
fn drain_and_drop() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let mut persist_keys = vec![];
for n in 0..100 {
let k = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(n * 2);
persist_keys.push(k);
}
let buckets = tab.table.num_buckets();
assert_eq!(tab.len(), 100);
let drain = tab.drain();
check_size_hint_ok(100, drain.size_hint());
for (k, v) in drain.take(7) {
assert_eq!(*k.as_ref() * 2, v);
}
assert_eq!(tab.len(), 0);
assert_eq!(tab.table.num_buckets(), buckets);
}
#[test]
fn drain_completely() {
let mut persist_keys: Vec<_> = (0..=20).map(Rc::new).collect();
let mut tab = WkKeyMap::new(0, RandomState::default());
for n in &persist_keys {
tab.entry(n.clone()).unwrap_vacant().insert(**n);
}
persist_keys.truncate(10);
let mut drained: Vec<_> = tab.drain().map(|(k, _)| k).collect();
assert_eq!(drained.len(), 10);
drained.sort();
assert_eq!(drained, persist_keys);
}
#[test]
fn debug() {
let mut tab = WkKeyMap::new(0, RandomState::default());
let seventeen = Rc::new(17);
let vacant = tab.entry(seventeen.clone()).unwrap_vacant();
assert_eq!(format!("{:?}", vacant), "VacantEntry { key: 17 }");
let occupied = vacant.insert(23);
assert_eq!(
format!("{:?}", occupied),
"OccupiedEntry { key: 17, val: 23 }"
);
}
#[test]
fn weakweak_basics() {
let mut tab = WkWkMap::new(0, RandomState::default());
let mut persist_keys = vec![];
let mut persist_vals = vec![];
for n in 0..200 {
let k = Rc::new(n);
let v = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(v.clone());
persist_keys.push(k);
persist_vals.push(v);
}
assert_eq!(tab.len(), 200);
persist_vals.reverse();
persist_vals.truncate(190);
persist_keys.truncate(190);
assert_eq!(tab.len(), 200);
assert_eq!(tab.iter().count(), 180);
tab.remove_expired();
assert_eq!(tab.len(), 180);
assert_eq!(tab.iter().count(), 180);
assert!(tab.find(&6).is_none());
assert!(tab.find(&195).is_none());
let p150 = tab.find(&150).unwrap();
assert_eq!(p150.0.as_ref(), &150);
assert_eq!(p150.1.as_ref(), &150);
}
#[test]
fn weakweak_entry_cases() {
let mut tab = WkWkMap::new(0, RandomState::default());
let mut persist_keys = vec![];
let mut persist_vals = vec![];
for n in 0..200 {
let k = Rc::new(n);
let v = Rc::new(n);
tab.entry(k.clone()).unwrap_vacant().insert(v.clone());
persist_keys.push(k);
persist_vals.push(v);
}
persist_vals.truncate(150);
let k = Rc::new(220);
let k2 = tab.entry(k.clone()).unwrap_vacant().into_key();
assert!(Rc::ptr_eq(&k, &k2));
let k_orig = persist_keys[100].clone();
let k_new = Rc::new(100);
assert_eq!(&k_new, &k_orig);
assert!(!Rc::ptr_eq(&k, &k_orig));
let e = tab.entry(k_new.clone()).unwrap_occupied();
assert!(Rc::ptr_eq(e.get().0, &k_new));
assert!(Rc::ptr_eq(e.get().1, &persist_vals[100]));
let k = Rc::new(190);
let e = tab.entry(k.clone()).unwrap_vacant();
assert!(Rc::ptr_eq(e.key(), &k));
}
#[test]
fn weakvalmap_basics() {
let mut tab = WkValMap::new(0, RandomState::default());
let mut persist_vals = vec![];
for n in 0..100 {
let v = Rc::new(n);
tab.entry(n).unwrap_vacant().insert(v.clone());
persist_vals.push(v);
}
assert_eq!(tab.find(&22).unwrap(), (&22, Rc::new(22)));
assert_eq!(tab.entry(50).unwrap_occupied().remove(), (50, Rc::new(50)));
persist_vals.truncate(50);
assert_eq!(tab.iter().count(), 50);
tab.remove_expired();
assert_eq!(tab.len(), 50);
}
#[test]
fn div_ceil_test() {
assert_eq!(div_ceil(0, 99), 0);
assert_eq!(div_ceil(100, 99), 2);
assert_eq!(div_ceil(6, 3), 2);
assert_eq!(div_ceil(7, 3), 3);
}
#[test]
fn desired_capacity_test() {
assert_eq!(desired_capacity_for(0), 1);
assert_eq!(desired_capacity_for(1), 5);
assert_eq!(desired_capacity_for(3), 5);
assert_eq!(desired_capacity_for(4), 9);
assert_eq!(desired_capacity_for(10), 17);
for len in 0..200 {
let cap = desired_capacity_for(len);
assert!(cap > len);
assert!((len as f64) < (cap as f64) * 0.75);
}
}
#[test]
fn extract_if() {
let numbers: Vec<Rc<u8>> = (0..50).map(Rc::new).collect();
let mut tab: WkKeyMap = WkKeyMap::new(0, RandomState::default());
for n in numbers.iter() {
tab.entry(n.clone()).unwrap_vacant().insert(**n);
}
let div3: Vec<(Rc<u8>, u8)> = tab
.extract_if(|(k, v)| {
if k.as_ref().unwrap().as_ref() % 3 == 0 {
true
} else {
v.val *= 2;
false
}
})
.collect();
assert_eq!(div3.len() + tab.iter().count(), numbers.len());
assert!(div3.iter().all(|(_k, v)| v % 3 == 0));
assert!(tab.iter().all(|(k, v)| *k % 3 != 0 && *v == *k * 2));
}
#[test]
fn shrink_to() {
let numbers: Vec<Rc<u8>> = (0..50).map(Rc::new).collect();
let mut tab: WkKeyMap = WkKeyMap::new(1000, RandomState::default());
for n in numbers.iter() {
tab.entry(n.clone()).unwrap_vacant().insert(**n);
}
let cap_orig = tab.capacity();
assert!(cap_orig >= 1000);
for n in 0..200 {
let mut t2 = tab.clone();
t2.shrink_to(n);
assert!(t2.capacity() >= n);
assert_eq!(t2.iter().count(), 50);
assert!(t2.capacity() < cap_orig);
}
for n in (cap_orig - 10)..(cap_orig + 10) {
let mut t2 = tab.clone();
t2.shrink_to(n);
assert_eq!(t2.iter().count(), 50);
}
tab.shrink_to(9999);
assert_eq!(tab.capacity(), cap_orig);
}
#[test]
fn try_reserve_error_conversion() {
let e = hashbrown::TryReserveError::CapacityOverflow;
let e = crate::TryReserveError::from_hashbrown(e);
assert!(matches!(e, crate::TryReserveError::CapacityOverflow));
assert_eq!(
e.to_string(),
"Allocation failed: arithmetic overflow in capacity calculation"
);
let e = hashbrown::TryReserveError::AllocError {
layout: Layout::from_size_align(16, 16).expect("Bad layout"),
};
let e = crate::TryReserveError::from_hashbrown(e);
assert!(matches!(e, crate::TryReserveError::AllocError { .. }));
assert_eq!(
e.to_string(),
"Allocation failed: memory allocator returned an error"
);
}
}