use core::{fmt, iter::FusedIterator, marker::PhantomData};
use crate::{
raw::{
Allocator, Bucket, Global, InsertSlot, RawDrain, RawExtractIf, RawIntoIter, RawIter,
RawTable,
},
TryReserveError,
};
pub struct HashTable<T, A = Global>
where
A: Allocator,
{
pub(crate) raw: RawTable<T, A>,
}
impl<T> HashTable<T, Global> {
pub const fn new() -> Self {
Self {
raw: RawTable::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
raw: RawTable::with_capacity(capacity),
}
}
}
impl<T, A> HashTable<T, A>
where
A: Allocator,
{
pub const fn new_in(alloc: A) -> Self {
Self {
raw: RawTable::new_in(alloc),
}
}
pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
Self {
raw: RawTable::with_capacity_in(capacity, alloc),
}
}
pub fn allocator(&self) -> &A {
self.raw.allocator()
}
pub fn find(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> {
self.raw.get(hash, eq)
}
pub fn find_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> {
self.raw.get_mut(hash, eq)
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn find_entry(
&mut self,
hash: u64,
eq: impl FnMut(&T) -> bool,
) -> Result<OccupiedEntry<'_, T, A>, AbsentEntry<'_, T, A>> {
match self.raw.find(hash, eq) {
Some(bucket) => Ok(OccupiedEntry {
hash,
bucket,
table: self,
}),
None => Err(AbsentEntry { table: self }),
}
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn entry(
&mut self,
hash: u64,
eq: impl FnMut(&T) -> bool,
hasher: impl Fn(&T) -> u64,
) -> Entry<'_, T, A> {
match self.raw.find_or_find_insert_slot(hash, eq, hasher) {
Ok(bucket) => Entry::Occupied(OccupiedEntry {
hash,
bucket,
table: self,
}),
Err(insert_slot) => Entry::Vacant(VacantEntry {
hash,
insert_slot,
table: self,
}),
}
}
pub fn insert_unique(
&mut self,
hash: u64,
value: T,
hasher: impl Fn(&T) -> u64,
) -> OccupiedEntry<'_, T, A> {
let bucket = self.raw.insert(hash, value, hasher);
OccupiedEntry {
hash,
bucket,
table: self,
}
}
pub fn clear(&mut self) {
self.raw.clear();
}
pub fn shrink_to_fit(&mut self, hasher: impl Fn(&T) -> u64) {
self.raw.shrink_to(self.len(), hasher)
}
pub fn shrink_to(&mut self, min_capacity: usize, hasher: impl Fn(&T) -> u64) {
self.raw.shrink_to(min_capacity, hasher);
}
pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) {
self.raw.reserve(additional, hasher)
}
pub fn try_reserve(
&mut self,
additional: usize,
hasher: impl Fn(&T) -> u64,
) -> Result<(), TryReserveError> {
self.raw.try_reserve(additional, hasher)
}
pub fn capacity(&self) -> usize {
self.raw.capacity()
}
pub fn len(&self) -> usize {
self.raw.len()
}
pub fn is_empty(&self) -> bool {
self.raw.is_empty()
}
pub fn iter(&self) -> Iter<'_, T> {
Iter {
inner: unsafe { self.raw.iter() },
marker: PhantomData,
}
}
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut {
inner: unsafe { self.raw.iter() },
marker: PhantomData,
}
}
pub fn retain(&mut self, mut f: impl FnMut(&mut T) -> bool) {
unsafe {
for item in self.raw.iter() {
if !f(item.as_mut()) {
self.raw.erase(item);
}
}
}
}
pub fn drain(&mut self) -> Drain<'_, T, A> {
Drain {
inner: self.raw.drain(),
}
}
pub fn extract_if<F>(&mut self, f: F) -> ExtractIf<'_, T, F, A>
where
F: FnMut(&mut T) -> bool,
{
ExtractIf {
f,
inner: RawExtractIf {
iter: unsafe { self.raw.iter() },
table: &mut self.raw,
},
}
}
pub fn get_many_mut<const N: usize>(
&mut self,
hashes: [u64; N],
eq: impl FnMut(usize, &T) -> bool,
) -> Option<[&'_ mut T; N]> {
self.raw.get_many_mut(hashes, eq)
}
pub unsafe fn get_many_unchecked_mut<const N: usize>(
&mut self,
hashes: [u64; N],
eq: impl FnMut(usize, &T) -> bool,
) -> Option<[&'_ mut T; N]> {
self.raw.get_many_unchecked_mut(hashes, eq)
}
}
impl<T, A> IntoIterator for HashTable<T, A>
where
A: Allocator,
{
type Item = T;
type IntoIter = IntoIter<T, A>;
fn into_iter(self) -> IntoIter<T, A> {
IntoIter {
inner: self.raw.into_iter(),
}
}
}
impl<'a, T, A> IntoIterator for &'a HashTable<T, A>
where
A: Allocator,
{
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
impl<'a, T, A> IntoIterator for &'a mut HashTable<T, A>
where
A: Allocator,
{
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
fn into_iter(self) -> IterMut<'a, T> {
self.iter_mut()
}
}
impl<T, A> Default for HashTable<T, A>
where
A: Allocator + Default,
{
fn default() -> Self {
Self {
raw: Default::default(),
}
}
}
impl<T, A> Clone for HashTable<T, A>
where
T: Clone,
A: Allocator + Clone,
{
fn clone(&self) -> Self {
Self {
raw: self.raw.clone(),
}
}
}
impl<T, A> fmt::Debug for HashTable<T, A>
where
T: fmt::Debug,
A: Allocator,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_set().entries(self.iter()).finish()
}
}
pub enum Entry<'a, T, A = Global>
where
A: Allocator,
{
Occupied(OccupiedEntry<'a, T, A>),
Vacant(VacantEntry<'a, T, A>),
}
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Entry<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
}
}
}
impl<'a, T, A> Entry<'a, T, A>
where
A: Allocator,
{
pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> {
match self {
Entry::Occupied(mut entry) => {
*entry.get_mut() = value;
entry
}
Entry::Vacant(entry) => entry.insert(value),
}
}
pub fn or_insert(self, default: T) -> OccupiedEntry<'a, T, A> {
match self {
Entry::Occupied(entry) => entry,
Entry::Vacant(entry) => entry.insert(default),
}
}
pub fn or_insert_with(self, default: impl FnOnce() -> T) -> OccupiedEntry<'a, T, A> {
match self {
Entry::Occupied(entry) => entry,
Entry::Vacant(entry) => entry.insert(default()),
}
}
pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self {
match self {
Entry::Occupied(mut entry) => {
f(entry.get_mut());
Entry::Occupied(entry)
}
Entry::Vacant(entry) => Entry::Vacant(entry),
}
}
}
pub struct OccupiedEntry<'a, T, A = Global>
where
A: Allocator,
{
hash: u64,
bucket: Bucket<T>,
table: &'a mut HashTable<T, A>,
}
unsafe impl<T, A> Send for OccupiedEntry<'_, T, A>
where
T: Send,
A: Send + Allocator,
{
}
unsafe impl<T, A> Sync for OccupiedEntry<'_, T, A>
where
T: Sync,
A: Sync + Allocator,
{
}
impl<T: fmt::Debug, A: Allocator> fmt::Debug for OccupiedEntry<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OccupiedEntry")
.field("value", self.get())
.finish()
}
}
impl<'a, T, A> OccupiedEntry<'a, T, A>
where
A: Allocator,
{
#[cfg_attr(feature = "inline-more", inline)]
pub fn remove(self) -> (T, VacantEntry<'a, T, A>) {
let (val, slot) = unsafe { self.table.raw.remove(self.bucket) };
(
val,
VacantEntry {
hash: self.hash,
insert_slot: slot,
table: self.table,
},
)
}
#[inline]
pub fn get(&self) -> &T {
unsafe { self.bucket.as_ref() }
}
#[inline]
pub fn get_mut(&mut self) -> &mut T {
unsafe { self.bucket.as_mut() }
}
pub fn into_mut(self) -> &'a mut T {
unsafe { self.bucket.as_mut() }
}
pub fn into_table(self) -> &'a mut HashTable<T, A> {
self.table
}
}
pub struct VacantEntry<'a, T, A = Global>
where
A: Allocator,
{
hash: u64,
insert_slot: InsertSlot,
table: &'a mut HashTable<T, A>,
}
impl<T: fmt::Debug, A: Allocator> fmt::Debug for VacantEntry<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("VacantEntry")
}
}
impl<'a, T, A> VacantEntry<'a, T, A>
where
A: Allocator,
{
#[inline]
pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> {
let bucket = unsafe {
self.table
.raw
.insert_in_slot(self.hash, self.insert_slot, value)
};
OccupiedEntry {
hash: self.hash,
bucket,
table: self.table,
}
}
pub fn into_table(self) -> &'a mut HashTable<T, A> {
self.table
}
}
pub struct AbsentEntry<'a, T, A = Global>
where
A: Allocator,
{
table: &'a mut HashTable<T, A>,
}
impl<T: fmt::Debug, A: Allocator> fmt::Debug for AbsentEntry<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("AbsentEntry")
}
}
impl<'a, T, A> AbsentEntry<'a, T, A>
where
A: Allocator,
{
pub fn into_table(self) -> &'a mut HashTable<T, A> {
self.table
}
}
pub struct Iter<'a, T> {
inner: RawIter<T>,
marker: PhantomData<&'a T>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
match self.inner.next() {
Some(bucket) => Some(unsafe { bucket.as_ref() }),
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
fn fold<B, F>(self, init: B, mut f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
self.inner
.fold(init, |acc, bucket| unsafe { f(acc, bucket.as_ref()) })
}
}
impl<T> ExactSizeIterator for Iter<'_, T> {
fn len(&self) -> usize {
self.inner.len()
}
}
impl<T> FusedIterator for Iter<'_, T> {}
pub struct IterMut<'a, T> {
inner: RawIter<T>,
marker: PhantomData<&'a mut T>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
match self.inner.next() {
Some(bucket) => Some(unsafe { bucket.as_mut() }),
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
fn fold<B, F>(self, init: B, mut f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
self.inner
.fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) })
}
}
impl<T> ExactSizeIterator for IterMut<'_, T> {
fn len(&self) -> usize {
self.inner.len()
}
}
impl<T> FusedIterator for IterMut<'_, T> {}
pub struct IntoIter<T, A = Global>
where
A: Allocator,
{
inner: RawIntoIter<T, A>,
}
impl<T, A> Iterator for IntoIter<T, A>
where
A: Allocator,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
fn fold<B, F>(self, init: B, f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
self.inner.fold(init, f)
}
}
impl<T, A> ExactSizeIterator for IntoIter<T, A>
where
A: Allocator,
{
fn len(&self) -> usize {
self.inner.len()
}
}
impl<T, A> FusedIterator for IntoIter<T, A> where A: Allocator {}
pub struct Drain<'a, T, A: Allocator = Global> {
inner: RawDrain<'a, T, A>,
}
impl<T, A: Allocator> Drain<'_, T, A> {
fn iter(&self) -> Iter<'_, T> {
Iter {
inner: self.inner.iter(),
marker: PhantomData,
}
}
}
impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.inner.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {
fn len(&self) -> usize {
self.inner.len()
}
}
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
#[must_use = "Iterators are lazy unless consumed"]
pub struct ExtractIf<'a, T, F, A: Allocator = Global>
where
F: FnMut(&mut T) -> bool,
{
f: F,
inner: RawExtractIf<'a, T, A>,
}
impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
where
F: FnMut(&mut T) -> bool,
{
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next(|val| (self.f)(val))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.inner.iter.size_hint().1)
}
}
impl<T, F, A: Allocator> FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool {}