#![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::hash_set::{
Difference, Drain, Entry, ExtractIf, Intersection, IntoIter, Iter, SymmetricDifference, Union,
};
use crate::{Allocator, HashMap};
type InnerHashSet<'alloc, T, S> = hashbrown::HashSet<T, S, &'alloc Bump>;
pub struct HashSet<'alloc, T, S = FxBuildHasher>(ManuallyDrop<InnerHashSet<'alloc, T, S>>);
impl<T: fmt::Debug, S> fmt::Debug for HashSet<'_, T, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_set().entries(self.0.iter()).finish()
}
}
unsafe impl<T: Sync, S: Sync> Sync for HashSet<'_, T, S> {}
impl<'alloc, T, S> HashSet<'alloc, T, S> {
const ASSERT_T_IS_NOT_DROP: () = {
assert!(!std::mem::needs_drop::<T>(), "Cannot create a HashSet<T> where T is a Drop type");
};
#[inline(always)]
pub fn with_hasher_in(hasher: S, allocator: &'alloc Allocator) -> Self {
const { Self::ASSERT_T_IS_NOT_DROP };
let inner = InnerHashSet::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_T_IS_NOT_DROP };
let inner = InnerHashSet::with_capacity_and_hasher_in(capacity, hasher, allocator.bump());
Self(ManuallyDrop::new(inner))
}
#[expect(clippy::unused_self)]
pub fn allocator(&self) -> &'alloc Bump {
const { panic!("This method cannot be called") };
unreachable!();
}
}
impl<'alloc, T> HashSet<'alloc, T> {
#[inline(always)]
pub fn new_in(allocator: &'alloc Allocator) -> Self {
Self::with_hasher_in(FxBuildHasher, allocator)
}
#[inline(always)]
pub fn with_capacity_in(capacity: usize, allocator: &'alloc Allocator) -> Self {
Self::with_capacity_and_hasher_in(capacity, FxBuildHasher, allocator)
}
#[inline]
pub fn from_iter_in<I: IntoIterator<Item = T>>(iter: I, allocator: &'alloc Allocator) -> Self
where
T: Eq + Hash,
{
const { Self::ASSERT_T_IS_NOT_DROP };
let iter = iter.into_iter();
let capacity = iter.size_hint().0;
let set =
InnerHashSet::with_capacity_and_hasher_in(capacity, FxBuildHasher, allocator.bump());
let mut set = ManuallyDrop::new(set);
iter.for_each(|v| {
set.insert(v);
});
Self(set)
}
}
impl<'alloc, T, S> Deref for HashSet<'alloc, T, S> {
type Target = InnerHashSet<'alloc, T, S>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'alloc, T, S> DerefMut for HashSet<'alloc, T, S> {
#[inline]
fn deref_mut(&mut self) -> &mut InnerHashSet<'alloc, T, S> {
&mut self.0
}
}
impl<'alloc, T, S> IntoIterator for HashSet<'alloc, T, S> {
type IntoIter = IntoIter<T, &'alloc Bump>;
type Item = T;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
let inner = ManuallyDrop::into_inner(self.0);
inner.into_iter()
}
}
impl<'alloc, 'i, T, S> IntoIterator for &'i HashSet<'alloc, T, S> {
type IntoIter = <&'i InnerHashSet<'alloc, T, S> as IntoIterator>::IntoIter;
type Item = &'i T;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<T, S> PartialEq for HashSet<'_, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<T, S> Eq for HashSet<'_, T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
}
impl<'alloc, T, S> From<HashMap<'alloc, T, (), S>> for HashSet<'alloc, T, S> {
#[inline(always)]
fn from(map: HashMap<'alloc, T, (), S>) -> Self {
let inner_map = ManuallyDrop::into_inner(map.0);
let inner_set = hashbrown::HashSet::from(inner_map);
Self(ManuallyDrop::new(inner_set))
}
}