use crate::iter_set::{Iter, OwningIter};
#[cfg(feature = "raw-api")]
use crate::lock::RwLock;
use crate::setref::one::Ref;
use crate::ClashMap;
#[cfg(feature = "raw-api")]
use crate::HashMap;
use core::fmt;
use core::hash::{BuildHasher, Hash};
use core::iter::FromIterator;
#[cfg(feature = "raw-api")]
use crossbeam_utils::CachePadded;
use hashbrown::Equivalent;
use std::collections::hash_map::RandomState;
pub struct ClashSet<K, S = RandomState> {
pub(crate) inner: ClashMap<K, (), S>,
}
impl<K: fmt::Debug, S> fmt::Debug for ClashSet<K, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut set = f.debug_set();
self.inner.table.for_each(|(k, _)| {
set.entry(k);
});
set.finish()
}
}
impl<K: Clone, S: Clone> Clone for ClashSet<K, S> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.inner.clone_from(&source.inner)
}
}
impl<K, S> Default for ClashSet<K, S>
where
K: Eq + Hash,
S: Default + BuildHasher,
{
fn default() -> Self {
Self::with_hasher(Default::default())
}
}
impl<K: Eq + Hash> ClashSet<K, RandomState> {
pub fn new() -> Self {
Self::with_hasher(RandomState::default())
}
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_and_hasher(capacity, RandomState::default())
}
}
impl<'a, K: 'a + Eq + Hash, S: BuildHasher> ClashSet<K, S> {
pub fn with_hasher(hasher: S) -> Self {
Self::with_capacity_and_hasher(0, hasher)
}
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
Self {
inner: ClashMap::with_capacity_and_hasher(capacity, hasher),
}
}
pub fn hash_usize<T: Hash>(&self, item: &T) -> usize {
self.inner.hash_usize(item)
}
#[cfg(feature = "raw-api")]
pub fn shards(&self) -> &[CachePadded<RwLock<HashMap<K, ()>>>] {
self.inner.shards()
}
#[cfg(feature = "raw-api")]
pub fn determine_map<Q>(&self, key: &Q) -> usize
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.inner.determine_map(key)
}
#[cfg(feature = "raw-api")]
pub fn determine_shard(&self, hash: usize) -> usize {
self.inner.determine_shard(hash)
}
pub fn insert_mut(&mut self, key: K) -> bool {
self.inner.insert_mut(key, ()).is_none()
}
pub fn insert(&self, key: K) -> bool {
self.inner.insert(key, ()).is_none()
}
pub fn remove<Q>(&self, key: &Q) -> Option<K>
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.inner.remove(key).map(|(k, _)| k)
}
pub fn remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K) -> bool) -> Option<K>
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.inner.remove_if(key, |k, _| f(k)).map(|(k, _)| k)
}
pub fn get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K>>
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.inner.get(key).map(Ref::new)
}
pub fn shrink_to_fit(&self) {
self.inner.shrink_to_fit()
}
pub fn retain(&self, mut f: impl FnMut(&K) -> bool) {
self.inner.retain(|k, _| f(k))
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn clear(&self) {
self.inner.clear()
}
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
pub fn contains<Q>(&self, key: &Q) -> bool
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.inner.contains_key(key)
}
}
impl<K, S> ClashSet<K, S> {
pub fn iter(&self) -> Iter<'_, K> {
let iter = self.inner.iter();
Iter::new(iter)
}
}
impl<K: Eq + Hash, S: BuildHasher> IntoIterator for ClashSet<K, S> {
type Item = K;
type IntoIter = OwningIter<K>;
fn into_iter(self) -> Self::IntoIter {
OwningIter::new(self.inner.into_iter())
}
}
impl<K: Eq + Hash, S: BuildHasher> Extend<K> for ClashSet<K, S> {
fn extend<T: IntoIterator<Item = K>>(&mut self, iter: T) {
let iter = iter.into_iter().map(|k| (k, ()));
self.inner.extend(iter)
}
}
impl<K: Eq + Hash, S: BuildHasher + Default> FromIterator<K> for ClashSet<K, S> {
fn from_iter<I: IntoIterator<Item = K>>(iter: I) -> Self {
let mut set = ClashSet::default();
set.extend(iter);
set
}
}
#[cfg(feature = "typesize")]
impl<K, S> typesize::TypeSize for ClashSet<K, S>
where
K: typesize::TypeSize + Eq + Hash,
S: typesize::TypeSize + BuildHasher,
{
fn extra_size(&self) -> usize {
self.inner.extra_size()
}
typesize::if_typesize_details! {
fn get_collection_item_count(&self) -> Option<usize> {
Some(self.len())
}
}
}
#[cfg(test)]
mod tests {
use crate::ClashSet;
#[test]
fn test_basic() {
let set = ClashSet::new();
set.insert(0);
assert_eq!(set.get(&0).as_deref(), Some(&0));
}
#[test]
fn test_default() {
let set: ClashSet<u32> = ClashSet::default();
set.insert(0);
assert_eq!(set.get(&0).as_deref(), Some(&0));
}
#[test]
fn test_multiple_hashes() {
let set = ClashSet::<u32>::default();
for i in 0..100 {
assert!(set.insert(i));
}
for i in 0..100 {
assert!(!set.insert(i));
}
for i in 0..100 {
assert_eq!(Some(i), set.remove(&i));
}
for i in 0..100 {
assert_eq!(None, set.remove(&i));
}
}
}