| use crate::iter_set::{Iter, OwningIter}; |
| #[cfg(feature = "raw-api")] |
| use crate::lock::RwLock; |
| use crate::setref::one::Ref; |
| use crate::DashMap; |
| #[cfg(feature = "raw-api")] |
| use crate::HashMap; |
| use cfg_if::cfg_if; |
| use core::borrow::Borrow; |
| use core::fmt; |
| use core::hash::{BuildHasher, Hash}; |
| use core::iter::FromIterator; |
| use std::collections::hash_map::RandomState; |
| |
| /// DashSet is a thin wrapper around [`DashMap`] using `()` as the value type. It uses |
| /// methods and types which are more convenient to work with on a set. |
| /// |
| /// [`DashMap`]: struct.DashMap.html |
| pub struct DashSet<K, S = RandomState> { |
| pub(crate) inner: DashMap<K, (), S>, |
| } |
| |
| impl<K: Eq + Hash + fmt::Debug, S: BuildHasher + Clone> fmt::Debug for DashSet<K, S> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| fmt::Debug::fmt(&self.inner, f) |
| } |
| } |
| |
| impl<K: Eq + Hash + Clone, S: Clone> Clone for DashSet<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 DashSet<K, S> |
| where |
| K: Eq + Hash, |
| S: Default + BuildHasher + Clone, |
| { |
| fn default() -> Self { |
| Self::with_hasher(Default::default()) |
| } |
| } |
| |
| impl<'a, K: 'a + Eq + Hash> DashSet<K, RandomState> { |
| /// Creates a new DashSet with a capacity of 0. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let games = DashSet::new(); |
| /// games.insert("Veloren"); |
| /// ``` |
| pub fn new() -> Self { |
| Self::with_hasher(RandomState::default()) |
| } |
| |
| /// Creates a new DashMap with a specified starting capacity. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let numbers = DashSet::with_capacity(2); |
| /// numbers.insert(2); |
| /// numbers.insert(8); |
| /// ``` |
| pub fn with_capacity(capacity: usize) -> Self { |
| Self::with_capacity_and_hasher(capacity, RandomState::default()) |
| } |
| } |
| |
| impl<'a, K: 'a + Eq + Hash, S: BuildHasher + Clone> DashSet<K, S> { |
| /// Creates a new DashMap with a capacity of 0 and the provided hasher. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// use std::collections::hash_map::RandomState; |
| /// |
| /// let s = RandomState::new(); |
| /// let games = DashSet::with_hasher(s); |
| /// games.insert("Veloren"); |
| /// ``` |
| pub fn with_hasher(hasher: S) -> Self { |
| Self::with_capacity_and_hasher(0, hasher) |
| } |
| |
| /// Creates a new DashMap with a specified starting capacity and hasher. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// use std::collections::hash_map::RandomState; |
| /// |
| /// let s = RandomState::new(); |
| /// let numbers = DashSet::with_capacity_and_hasher(2, s); |
| /// numbers.insert(2); |
| /// numbers.insert(8); |
| /// ``` |
| pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { |
| Self { |
| inner: DashMap::with_capacity_and_hasher(capacity, hasher), |
| } |
| } |
| |
| /// Hash a given item to produce a usize. |
| /// Uses the provided or default HashBuilder. |
| pub fn hash_usize<T: Hash>(&self, item: &T) -> usize { |
| self.inner.hash_usize(item) |
| } |
| |
| cfg_if! { |
| if #[cfg(feature = "raw-api")] { |
| /// Allows you to peek at the inner shards that store your data. |
| /// You should probably not use this unless you know what you are doing. |
| /// |
| /// Requires the `raw-api` feature to be enabled. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let set = DashSet::<()>::new(); |
| /// println!("Amount of shards: {}", set.shards().len()); |
| /// ``` |
| pub fn shards(&self) -> &[RwLock<HashMap<K, (), S>>] { |
| self.inner.shards() |
| } |
| } |
| } |
| |
| cfg_if! { |
| if #[cfg(feature = "raw-api")] { |
| /// Finds which shard a certain key is stored in. |
| /// You should probably not use this unless you know what you are doing. |
| /// Note that shard selection is dependent on the default or provided HashBuilder. |
| /// |
| /// Requires the `raw-api` feature to be enabled. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let set = DashSet::new(); |
| /// set.insert("coca-cola"); |
| /// println!("coca-cola is stored in shard: {}", set.determine_map("coca-cola")); |
| /// ``` |
| pub fn determine_map<Q>(&self, key: &Q) -> usize |
| where |
| K: Borrow<Q>, |
| Q: Hash + Eq + ?Sized, |
| { |
| self.inner.determine_map(key) |
| } |
| } |
| } |
| |
| cfg_if! { |
| if #[cfg(feature = "raw-api")] { |
| /// Finds which shard a certain hash is stored in. |
| /// |
| /// Requires the `raw-api` feature to be enabled. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let set: DashSet<i32> = DashSet::new(); |
| /// let key = "key"; |
| /// let hash = set.hash_usize(&key); |
| /// println!("hash is stored in shard: {}", set.determine_shard(hash)); |
| /// ``` |
| pub fn determine_shard(&self, hash: usize) -> usize { |
| self.inner.determine_shard(hash) |
| } |
| } |
| } |
| |
| /// Inserts a key into the set. Returns true if the key was not already in the set. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let set = DashSet::new(); |
| /// set.insert("I am the key!"); |
| /// ``` |
| pub fn insert(&self, key: K) -> bool { |
| self.inner.insert(key, ()).is_none() |
| } |
| |
| /// Removes an entry from the map, returning the key if it existed in the map. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let soccer_team = DashSet::new(); |
| /// soccer_team.insert("Jack"); |
| /// assert_eq!(soccer_team.remove("Jack").unwrap(), "Jack"); |
| /// ``` |
| pub fn remove<Q>(&self, key: &Q) -> Option<K> |
| where |
| K: Borrow<Q>, |
| Q: Hash + Eq + ?Sized, |
| { |
| self.inner.remove(key).map(|(k, _)| k) |
| } |
| |
| /// Removes an entry from the set, returning the key |
| /// if the entry existed and the provided conditional function returned true. |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let soccer_team = DashSet::new(); |
| /// soccer_team.insert("Sam"); |
| /// soccer_team.remove_if("Sam", |player| player.starts_with("Ja")); |
| /// assert!(soccer_team.contains("Sam")); |
| /// ``` |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let soccer_team = DashSet::new(); |
| /// soccer_team.insert("Sam"); |
| /// soccer_team.remove_if("Jacob", |player| player.starts_with("Ja")); |
| /// assert!(!soccer_team.contains("Jacob")); |
| /// ``` |
| pub fn remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K) -> bool) -> Option<K> |
| where |
| K: Borrow<Q>, |
| Q: Hash + Eq + ?Sized, |
| { |
| // TODO: Don't create another closure around f |
| self.inner.remove_if(key, |k, _| f(k)).map(|(k, _)| k) |
| } |
| |
| /// Creates an iterator over a DashMap yielding immutable references. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let words = DashSet::new(); |
| /// words.insert("hello"); |
| /// assert_eq!(words.iter().count(), 1); |
| /// ``` |
| pub fn iter(&'a self) -> Iter<'a, K, S, DashMap<K, (), S>> { |
| let iter = self.inner.iter(); |
| |
| Iter::new(iter) |
| } |
| |
| /// Get a reference to an entry in the set |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let youtubers = DashSet::new(); |
| /// youtubers.insert("Bosnian Bill"); |
| /// assert_eq!(*youtubers.get("Bosnian Bill").unwrap(), "Bosnian Bill"); |
| /// ``` |
| pub fn get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K, S>> |
| where |
| K: Borrow<Q>, |
| Q: Hash + Eq + ?Sized, |
| { |
| self.inner.get(key).map(Ref::new) |
| } |
| |
| /// Remove excess capacity to reduce memory usage. |
| pub fn shrink_to_fit(&self) { |
| self.inner.shrink_to_fit() |
| } |
| |
| /// Retain elements that whose predicates return true |
| /// and discard elements whose predicates return false. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let people = DashSet::new(); |
| /// people.insert("Albin"); |
| /// people.insert("Jones"); |
| /// people.insert("Charlie"); |
| /// people.retain(|name| name.contains('i')); |
| /// assert_eq!(people.len(), 2); |
| /// ``` |
| pub fn retain(&self, mut f: impl FnMut(&K) -> bool) { |
| self.inner.retain(|k, _| f(k)) |
| } |
| |
| /// Fetches the total number of keys stored in the set. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let people = DashSet::new(); |
| /// people.insert("Albin"); |
| /// people.insert("Jones"); |
| /// people.insert("Charlie"); |
| /// assert_eq!(people.len(), 3); |
| /// ``` |
| pub fn len(&self) -> usize { |
| self.inner.len() |
| } |
| |
| /// Checks if the set is empty or not. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let map = DashSet::<()>::new(); |
| /// assert!(map.is_empty()); |
| /// ``` |
| pub fn is_empty(&self) -> bool { |
| self.inner.is_empty() |
| } |
| |
| /// Removes all keys in the set. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let people = DashSet::new(); |
| /// people.insert("Albin"); |
| /// assert!(!people.is_empty()); |
| /// people.clear(); |
| /// assert!(people.is_empty()); |
| /// ``` |
| pub fn clear(&self) { |
| self.inner.clear() |
| } |
| |
| /// Returns how many keys the set can store without reallocating. |
| pub fn capacity(&self) -> usize { |
| self.inner.capacity() |
| } |
| |
| /// Checks if the set contains a specific key. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use dashmap::DashSet; |
| /// |
| /// let people = DashSet::new(); |
| /// people.insert("Dakota Cherries"); |
| /// assert!(people.contains("Dakota Cherries")); |
| /// ``` |
| pub fn contains<Q>(&self, key: &Q) -> bool |
| where |
| K: Borrow<Q>, |
| Q: Hash + Eq + ?Sized, |
| { |
| self.inner.contains_key(key) |
| } |
| } |
| |
| impl<K: Eq + Hash, S: BuildHasher + Clone> IntoIterator for DashSet<K, S> { |
| type Item = K; |
| |
| type IntoIter = OwningIter<K, S>; |
| |
| fn into_iter(self) -> Self::IntoIter { |
| OwningIter::new(self.inner.into_iter()) |
| } |
| } |
| |
| impl<K: Eq + Hash, S: BuildHasher + Clone> Extend<K> for DashSet<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 + Clone + Default> FromIterator<K> for DashSet<K, S> { |
| fn from_iter<I: IntoIterator<Item = K>>(iter: I) -> Self { |
| let mut set = DashSet::default(); |
| |
| set.extend(iter); |
| |
| set |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use crate::DashSet; |
| |
| #[test] |
| fn test_basic() { |
| let set = DashSet::new(); |
| |
| set.insert(0); |
| |
| assert_eq!(set.get(&0).as_deref(), Some(&0)); |
| } |
| |
| #[test] |
| fn test_default() { |
| let set: DashSet<u32> = DashSet::default(); |
| |
| set.insert(0); |
| |
| assert_eq!(set.get(&0).as_deref(), Some(&0)); |
| } |
| |
| #[test] |
| fn test_multiple_hashes() { |
| let set = DashSet::<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)); |
| } |
| } |
| } |