#![expect(clippy::inline_always)]
use std::{
fmt,
hash::{BuildHasher, Hash},
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
use rustc_hash::FxBuildHasher;
use crate::bump::Bump;
pub use hashbrown::{
Equivalent, TryReserveError,
hash_map::{
Drain, Entry, EntryRef, ExtractIf, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys,
OccupiedError, Values, ValuesMut,
},
};
use crate::Allocator;
type InnerHashMap<'alloc, K, V, S> = hashbrown::HashMap<K, V, S, &'alloc Bump>;
pub struct HashMap<'alloc, K, V, S = FxBuildHasher>(
pub(crate) ManuallyDrop<InnerHashMap<'alloc, K, V, S>>,
);
impl<K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for HashMap<'_, K, V, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.0.iter()).finish()
}
}
unsafe impl<K: Sync, V: Sync, S: Sync> Sync for HashMap<'_, K, V, S> {}
impl<'alloc, K, V, S> HashMap<'alloc, K, V, S> {
const ASSERT_K_AND_V_ARE_NOT_DROP: () = {
assert!(
!std::mem::needs_drop::<K>(),
"Cannot create a HashMap<K, V> where K is a Drop type"
);
assert!(
!std::mem::needs_drop::<V>(),
"Cannot create a HashMap<K, V> where V is a Drop type"
);
};
#[inline(always)]
pub fn with_hasher_in(hasher: S, allocator: &'alloc Allocator) -> Self {
const { Self::ASSERT_K_AND_V_ARE_NOT_DROP };
let inner = InnerHashMap::with_hasher_in(hasher, allocator.bump());
Self(ManuallyDrop::new(inner))
}
#[inline(always)]
pub fn with_capacity_and_hasher_in(
capacity: usize,
hasher: S,
allocator: &'alloc Allocator,
) -> Self {
const { Self::ASSERT_K_AND_V_ARE_NOT_DROP };
let inner = InnerHashMap::with_capacity_and_hasher_in(capacity, hasher, allocator.bump());
Self(ManuallyDrop::new(inner))
}
#[inline(always)]
pub fn into_keys(self) -> IntoKeys<K, V, &'alloc Bump> {
let inner = ManuallyDrop::into_inner(self.0);
inner.into_keys()
}
#[inline(always)]
pub fn into_values(self) -> IntoValues<K, V, &'alloc Bump> {
let inner = ManuallyDrop::into_inner(self.0);
inner.into_values()
}
#[expect(clippy::unused_self)]
pub fn allocator(&self) -> &'alloc Bump {
const { panic!("This method cannot be called") };
unreachable!();
}
}
impl<'alloc, K, V, S: Default> HashMap<'alloc, K, V, S> {
#[inline(always)]
pub fn new_in(allocator: &'alloc Allocator) -> Self {
Self::with_hasher_in(S::default(), allocator)
}
#[inline(always)]
pub fn with_capacity_in(capacity: usize, allocator: &'alloc Allocator) -> Self {
Self::with_capacity_and_hasher_in(capacity, S::default(), allocator)
}
#[inline]
pub fn from_iter_in<I: IntoIterator<Item = (K, V)>>(
iter: I,
allocator: &'alloc Allocator,
) -> Self
where
K: Eq + Hash,
S: BuildHasher,
{
const { Self::ASSERT_K_AND_V_ARE_NOT_DROP };
let iter = iter.into_iter();
let capacity = iter.size_hint().0;
let map =
InnerHashMap::with_capacity_and_hasher_in(capacity, S::default(), allocator.bump());
let mut map = ManuallyDrop::new(map);
iter.for_each(|(k, v)| {
map.insert(k, v);
});
Self(map)
}
}
impl<'alloc, K, V, S> Deref for HashMap<'alloc, K, V, S> {
type Target = InnerHashMap<'alloc, K, V, S>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'alloc, K, V, S> DerefMut for HashMap<'alloc, K, V, S> {
#[inline]
fn deref_mut(&mut self) -> &mut InnerHashMap<'alloc, K, V, S> {
&mut self.0
}
}
impl<'alloc, K, V, S> IntoIterator for HashMap<'alloc, K, V, S> {
type IntoIter = IntoIter<K, V, &'alloc Bump>;
type Item = (K, V);
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
let inner = ManuallyDrop::into_inner(self.0);
inner.into_iter()
}
}
impl<'alloc, 'i, K, V, S> IntoIterator for &'i HashMap<'alloc, K, V, S> {
type IntoIter = <&'i InnerHashMap<'alloc, K, V, S> as IntoIterator>::IntoIter;
type Item = (&'i K, &'i V);
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'alloc, 'i, K, V, S> IntoIterator for &'i mut HashMap<'alloc, K, V, S> {
type IntoIter = <&'i mut InnerHashMap<'alloc, K, V, S> as IntoIterator>::IntoIter;
type Item = (&'i K, &'i mut V);
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<K, V, S> PartialEq for HashMap<'_, K, V, S>
where
K: Eq + Hash,
V: PartialEq,
S: BuildHasher,
{
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<K, V, S> Eq for HashMap<'_, K, V, S>
where
K: Eq + Hash,
V: Eq,
S: BuildHasher,
{
}