| use core::{fmt, iter::FusedIterator, marker::PhantomData}; |
| |
| use crate::{ |
| raw::{ |
| Allocator, Bucket, Global, InsertSlot, RawDrain, RawExtractIf, RawIntoIter, RawIter, |
| RawTable, |
| }, |
| TryReserveError, |
| }; |
| |
| /// Low-level hash table with explicit hashing. |
| /// |
| /// The primary use case for this type over [`HashMap`] or [`HashSet`] is to |
| /// support types that do not implement the [`Hash`] and [`Eq`] traits, but |
| /// instead require additional data not contained in the key itself to compute a |
| /// hash and compare two elements for equality. |
| /// |
| /// Examples of when this can be useful include: |
| /// - An `IndexMap` implementation where indices into a `Vec` are stored as |
| /// elements in a `HashTable<usize>`. Hashing and comparing the elements |
| /// requires indexing the associated `Vec` to get the actual value referred to |
| /// by the index. |
| /// - Avoiding re-computing a hash when it is already known. |
| /// - Mutating the key of an element in a way that doesn't affect its hash. |
| /// |
| /// To achieve this, `HashTable` methods that search for an element in the table |
| /// require a hash value and equality function to be explicitly passed in as |
| /// arguments. The method will then iterate over the elements with the given |
| /// hash and call the equality function on each of them, until a match is found. |
| /// |
| /// In most cases, a `HashTable` will not be exposed directly in an API. It will |
| /// instead be wrapped in a helper type which handles the work of calculating |
| /// hash values and comparing elements. |
| /// |
| /// Due to its low-level nature, this type provides fewer guarantees than |
| /// [`HashMap`] and [`HashSet`]. Specifically, the API allows you to shoot |
| /// yourself in the foot by having multiple elements with identical keys in the |
| /// table. The table itself will still function correctly and lookups will |
| /// arbitrarily return one of the matching elements. However you should avoid |
| /// doing this because it changes the runtime of hash table operations from |
| /// `O(1)` to `O(k)` where `k` is the number of duplicate entries. |
| /// |
| /// [`HashMap`]: super::HashMap |
| /// [`HashSet`]: super::HashSet |
| pub struct HashTable<T, A = Global> |
| where |
| A: Allocator, |
| { |
| pub(crate) raw: RawTable<T, A>, |
| } |
| |
| impl<T> HashTable<T, Global> { |
| /// Creates an empty `HashTable`. |
| /// |
| /// The hash table is initially created with a capacity of 0, so it will not allocate until it |
| /// is first inserted into. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use hashbrown::HashTable; |
| /// let mut table: HashTable<&str> = HashTable::new(); |
| /// assert_eq!(table.len(), 0); |
| /// assert_eq!(table.capacity(), 0); |
| /// ``` |
| pub const fn new() -> Self { |
| Self { |
| raw: RawTable::new(), |
| } |
| } |
| |
| /// Creates an empty `HashTable` with the specified capacity. |
| /// |
| /// The hash table will be able to hold at least `capacity` elements without |
| /// reallocating. If `capacity` is 0, the hash table will not allocate. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use hashbrown::HashTable; |
| /// let mut table: HashTable<&str> = HashTable::with_capacity(10); |
| /// assert_eq!(table.len(), 0); |
| /// assert!(table.capacity() >= 10); |
| /// ``` |
| pub fn with_capacity(capacity: usize) -> Self { |
| Self { |
| raw: RawTable::with_capacity(capacity), |
| } |
| } |
| } |
| |
| impl<T, A> HashTable<T, A> |
| where |
| A: Allocator, |
| { |
| /// Creates an empty `HashTable` using the given allocator. |
| /// |
| /// The hash table is initially created with a capacity of 0, so it will not allocate until it |
| /// is first inserted into. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use bumpalo::Bump; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let bump = Bump::new(); |
| /// let mut table = HashTable::new_in(&bump); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// // The created HashTable holds none elements |
| /// assert_eq!(table.len(), 0); |
| /// |
| /// // The created HashTable also doesn't allocate memory |
| /// assert_eq!(table.capacity(), 0); |
| /// |
| /// // Now we insert element inside created HashTable |
| /// table.insert_unique(hasher(&"One"), "One", hasher); |
| /// // We can see that the HashTable holds 1 element |
| /// assert_eq!(table.len(), 1); |
| /// // And it also allocates some capacity |
| /// assert!(table.capacity() > 1); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub const fn new_in(alloc: A) -> Self { |
| Self { |
| raw: RawTable::new_in(alloc), |
| } |
| } |
| |
| /// Creates an empty `HashTable` with the specified capacity using the given allocator. |
| /// |
| /// The hash table will be able to hold at least `capacity` elements without |
| /// reallocating. If `capacity` is 0, the hash table will not allocate. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use bumpalo::Bump; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let bump = Bump::new(); |
| /// let mut table = HashTable::with_capacity_in(5, &bump); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// // The created HashTable holds none elements |
| /// assert_eq!(table.len(), 0); |
| /// // But it can hold at least 5 elements without reallocating |
| /// let empty_map_capacity = table.capacity(); |
| /// assert!(empty_map_capacity >= 5); |
| /// |
| /// // Now we insert some 5 elements inside created HashTable |
| /// table.insert_unique(hasher(&"One"), "One", hasher); |
| /// table.insert_unique(hasher(&"Two"), "Two", hasher); |
| /// table.insert_unique(hasher(&"Three"), "Three", hasher); |
| /// table.insert_unique(hasher(&"Four"), "Four", hasher); |
| /// table.insert_unique(hasher(&"Five"), "Five", hasher); |
| /// |
| /// // We can see that the HashTable holds 5 elements |
| /// assert_eq!(table.len(), 5); |
| /// // But its capacity isn't changed |
| /// assert_eq!(table.capacity(), empty_map_capacity) |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { |
| Self { |
| raw: RawTable::with_capacity_in(capacity, alloc), |
| } |
| } |
| |
| /// Returns a reference to the underlying allocator. |
| pub fn allocator(&self) -> &A { |
| self.raw.allocator() |
| } |
| |
| /// Returns a reference to an entry in the table with the given hash and |
| /// which satisfies the equality function passed. |
| /// |
| /// This method will call `eq` for all entries with the given hash, but may |
| /// also call it for entries with a different hash. `eq` should only return |
| /// true for the desired entry, at which point the search is stopped. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&1), 1, hasher); |
| /// table.insert_unique(hasher(&2), 2, hasher); |
| /// table.insert_unique(hasher(&3), 3, hasher); |
| /// assert_eq!(table.find(hasher(&2), |&val| val == 2), Some(&2)); |
| /// assert_eq!(table.find(hasher(&4), |&val| val == 4), None); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn find(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { |
| self.raw.get(hash, eq) |
| } |
| |
| /// Returns a mutable reference to an entry in the table with the given hash |
| /// and which satisfies the equality function passed. |
| /// |
| /// This method will call `eq` for all entries with the given hash, but may |
| /// also call it for entries with a different hash. `eq` should only return |
| /// true for the desired entry, at which point the search is stopped. |
| /// |
| /// When mutating an entry, you should ensure that it still retains the same |
| /// hash value as when it was inserted, otherwise lookups of that entry may |
| /// fail to find it. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); |
| /// if let Some(val) = table.find_mut(hasher(&1), |val| val.0 == 1) { |
| /// val.1 = "b"; |
| /// } |
| /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), Some(&(1, "b"))); |
| /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), None); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn find_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { |
| self.raw.get_mut(hash, eq) |
| } |
| |
| /// Returns an `OccupiedEntry` for an entry in the table with the given hash |
| /// and which satisfies the equality function passed. |
| /// |
| /// This can be used to remove the entry from the table. Call |
| /// [`HashTable::entry`] instead if you wish to insert an entry if the |
| /// lookup fails. |
| /// |
| /// This method will call `eq` for all entries with the given hash, but may |
| /// also call it for entries with a different hash. `eq` should only return |
| /// true for the desired entry, at which point the search is stopped. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); |
| /// if let Ok(entry) = table.find_entry(hasher(&1), |val| val.0 == 1) { |
| /// entry.remove(); |
| /// } |
| /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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 }), |
| } |
| } |
| |
| /// Returns an `Entry` for an entry in the table with the given hash |
| /// and which satisfies the equality function passed. |
| /// |
| /// This can be used to remove the entry from the table, or insert a new |
| /// entry with the given hash if one doesn't already exist. |
| /// |
| /// This method will call `eq` for all entries with the given hash, but may |
| /// also call it for entries with a different hash. `eq` should only return |
| /// true for the desired entry, at which point the search is stopped. |
| /// |
| /// This method may grow the table in preparation for an insertion. Call |
| /// [`HashTable::find_entry`] if this is undesirable. |
| /// |
| /// `hasher` is called if entries need to be moved or copied to a new table. |
| /// This must return the same hash value that each entry was inserted with. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::Entry; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); |
| /// if let Entry::Occupied(entry) = table.entry(hasher(&1), |val| val.0 == 1, |val| hasher(&val.0)) |
| /// { |
| /// entry.remove(); |
| /// } |
| /// if let Entry::Vacant(entry) = table.entry(hasher(&2), |val| val.0 == 2, |val| hasher(&val.0)) { |
| /// entry.insert((2, "b")); |
| /// } |
| /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); |
| /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), Some(&(2, "b"))); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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, |
| }), |
| } |
| } |
| |
| /// Inserts an element into the `HashTable` with the given hash value, but |
| /// without checking whether an equivalent element already exists within the |
| /// table. |
| /// |
| /// `hasher` is called if entries need to be moved or copied to a new table. |
| /// This must return the same hash value that each entry was inserted with. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut v = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// v.insert_unique(hasher(&1), 1, hasher); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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, |
| } |
| } |
| |
| /// Clears the table, removing all values. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut v = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// v.insert_unique(hasher(&1), 1, hasher); |
| /// v.clear(); |
| /// assert!(v.is_empty()); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn clear(&mut self) { |
| self.raw.clear(); |
| } |
| |
| /// Shrinks the capacity of the table as much as possible. It will drop |
| /// down as much as possible while maintaining the internal rules |
| /// and possibly leaving some space in accordance with the resize policy. |
| /// |
| /// `hasher` is called if entries need to be moved or copied to a new table. |
| /// This must return the same hash value that each entry was inserted with. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::with_capacity(100); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&1), 1, hasher); |
| /// table.insert_unique(hasher(&2), 2, hasher); |
| /// assert!(table.capacity() >= 100); |
| /// table.shrink_to_fit(hasher); |
| /// assert!(table.capacity() >= 2); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn shrink_to_fit(&mut self, hasher: impl Fn(&T) -> u64) { |
| self.raw.shrink_to(self.len(), hasher) |
| } |
| |
| /// Shrinks the capacity of the table with a lower limit. It will drop |
| /// down no lower than the supplied limit while maintaining the internal rules |
| /// and possibly leaving some space in accordance with the resize policy. |
| /// |
| /// `hasher` is called if entries need to be moved or copied to a new table. |
| /// This must return the same hash value that each entry was inserted with. |
| /// |
| /// Panics if the current capacity is smaller than the supplied |
| /// minimum capacity. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::with_capacity(100); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&1), 1, hasher); |
| /// table.insert_unique(hasher(&2), 2, hasher); |
| /// assert!(table.capacity() >= 100); |
| /// table.shrink_to(10, hasher); |
| /// assert!(table.capacity() >= 10); |
| /// table.shrink_to(0, hasher); |
| /// assert!(table.capacity() >= 2); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn shrink_to(&mut self, min_capacity: usize, hasher: impl Fn(&T) -> u64) { |
| self.raw.shrink_to(min_capacity, hasher); |
| } |
| |
| /// Reserves capacity for at least `additional` more elements to be inserted |
| /// in the `HashTable`. The collection may reserve more space to avoid |
| /// frequent reallocations. |
| /// |
| /// `hasher` is called if entries need to be moved or copied to a new table. |
| /// This must return the same hash value that each entry was inserted with. |
| /// |
| /// # Panics |
| /// |
| /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program |
| /// in case of allocation error. Use [`try_reserve`](HashTable::try_reserve) instead |
| /// if you want to handle memory allocation failure. |
| /// |
| /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html |
| /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<i32> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.reserve(10, hasher); |
| /// assert!(table.capacity() >= 10); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { |
| self.raw.reserve(additional, hasher) |
| } |
| |
| /// Tries to reserve capacity for at least `additional` more elements to be inserted |
| /// in the given `HashTable`. The collection may reserve more space to avoid |
| /// frequent reallocations. |
| /// |
| /// `hasher` is called if entries need to be moved or copied to a new table. |
| /// This must return the same hash value that each entry was inserted with. |
| /// |
| /// # Errors |
| /// |
| /// If the capacity overflows, or the allocator reports a failure, then an error |
| /// is returned. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<i32> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table |
| /// .try_reserve(10, hasher) |
| /// .expect("why is the test harness OOMing on 10 bytes?"); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn try_reserve( |
| &mut self, |
| additional: usize, |
| hasher: impl Fn(&T) -> u64, |
| ) -> Result<(), TryReserveError> { |
| self.raw.try_reserve(additional, hasher) |
| } |
| |
| /// Returns the number of elements the table can hold without reallocating. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use hashbrown::HashTable; |
| /// let table: HashTable<i32> = HashTable::with_capacity(100); |
| /// assert!(table.capacity() >= 100); |
| /// ``` |
| pub fn capacity(&self) -> usize { |
| self.raw.capacity() |
| } |
| |
| /// Returns the number of elements in the table. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// let mut v = HashTable::new(); |
| /// assert_eq!(v.len(), 0); |
| /// v.insert_unique(hasher(&1), 1, hasher); |
| /// assert_eq!(v.len(), 1); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn len(&self) -> usize { |
| self.raw.len() |
| } |
| |
| /// Returns `true` if the set contains no elements. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// let mut v = HashTable::new(); |
| /// assert!(v.is_empty()); |
| /// v.insert_unique(hasher(&1), 1, hasher); |
| /// assert!(!v.is_empty()); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn is_empty(&self) -> bool { |
| self.raw.is_empty() |
| } |
| |
| /// An iterator visiting all elements in arbitrary order. |
| /// The iterator element type is `&'a T`. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&"a"), "b", hasher); |
| /// table.insert_unique(hasher(&"b"), "b", hasher); |
| /// |
| /// // Will print in an arbitrary order. |
| /// for x in table.iter() { |
| /// println!("{}", x); |
| /// } |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn iter(&self) -> Iter<'_, T> { |
| Iter { |
| inner: unsafe { self.raw.iter() }, |
| marker: PhantomData, |
| } |
| } |
| |
| /// An iterator visiting all elements in arbitrary order, |
| /// with mutable references to the elements. |
| /// The iterator element type is `&'a mut T`. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&1), 1, hasher); |
| /// table.insert_unique(hasher(&2), 2, hasher); |
| /// table.insert_unique(hasher(&3), 3, hasher); |
| /// |
| /// // Update all values |
| /// for val in table.iter_mut() { |
| /// *val *= 2; |
| /// } |
| /// |
| /// assert_eq!(table.len(), 3); |
| /// let mut vec: Vec<i32> = Vec::new(); |
| /// |
| /// for val in &table { |
| /// println!("val: {}", val); |
| /// vec.push(*val); |
| /// } |
| /// |
| /// // The `Iter` iterator produces items in arbitrary order, so the |
| /// // items must be sorted to test them against a sorted array. |
| /// vec.sort_unstable(); |
| /// assert_eq!(vec, [2, 4, 6]); |
| /// |
| /// assert_eq!(table.len(), 3); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn iter_mut(&mut self) -> IterMut<'_, T> { |
| IterMut { |
| inner: unsafe { self.raw.iter() }, |
| marker: PhantomData, |
| } |
| } |
| |
| /// Retains only the elements specified by the predicate. |
| /// |
| /// In other words, remove all elements `e` such that `f(&e)` returns `false`. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// for x in 1..=6 { |
| /// table.insert_unique(hasher(&x), x, hasher); |
| /// } |
| /// table.retain(|&mut x| x % 2 == 0); |
| /// assert_eq!(table.len(), 3); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn retain(&mut self, mut f: impl FnMut(&mut T) -> bool) { |
| // Here we only use `iter` as a temporary, preventing use-after-free |
| unsafe { |
| for item in self.raw.iter() { |
| if !f(item.as_mut()) { |
| self.raw.erase(item); |
| } |
| } |
| } |
| } |
| |
| /// Clears the set, returning all elements in an iterator. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// for x in 1..=3 { |
| /// table.insert_unique(hasher(&x), x, hasher); |
| /// } |
| /// assert!(!table.is_empty()); |
| /// |
| /// // print 1, 2, 3 in an arbitrary order |
| /// for i in table.drain() { |
| /// println!("{}", i); |
| /// } |
| /// |
| /// assert!(table.is_empty()); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn drain(&mut self) -> Drain<'_, T, A> { |
| Drain { |
| inner: self.raw.drain(), |
| } |
| } |
| |
| /// Drains elements which are true under the given predicate, |
| /// and returns an iterator over the removed items. |
| /// |
| /// In other words, move all elements `e` such that `f(&e)` returns `true` out |
| /// into another iterator. |
| /// |
| /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating |
| /// or the iteration short-circuits, then the remaining elements will be retained. |
| /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. |
| /// |
| /// [`retain()`]: HashTable::retain |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// for x in 0..8 { |
| /// table.insert_unique(hasher(&x), x, hasher); |
| /// } |
| /// let drained: Vec<i32> = table.extract_if(|&mut v| v % 2 == 0).collect(); |
| /// |
| /// let mut evens = drained.into_iter().collect::<Vec<_>>(); |
| /// let mut odds = table.into_iter().collect::<Vec<_>>(); |
| /// evens.sort(); |
| /// odds.sort(); |
| /// |
| /// assert_eq!(evens, vec![0, 2, 4, 6]); |
| /// assert_eq!(odds, vec![1, 3, 5, 7]); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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, |
| }, |
| } |
| } |
| |
| /// Attempts to get mutable references to `N` values in the map at once. |
| /// |
| /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to |
| /// the `i`th key to be looked up. |
| /// |
| /// Returns an array of length `N` with the results of each query. For soundness, at most one |
| /// mutable reference will be returned to any value. `None` will be returned if any of the |
| /// keys are duplicates or missing. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::Entry; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// for (k, v) in [ |
| /// ("Bodleian Library", 1602), |
| /// ("Athenæum", 1807), |
| /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), |
| /// ("Library of Congress", 1800), |
| /// ] { |
| /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); |
| /// } |
| /// |
| /// let keys = ["Athenæum", "Library of Congress"]; |
| /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); |
| /// assert_eq!( |
| /// got, |
| /// Some([&mut ("Athenæum", 1807), &mut ("Library of Congress", 1800),]), |
| /// ); |
| /// |
| /// // Missing keys result in None |
| /// let keys = ["Athenæum", "New York Public Library"]; |
| /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); |
| /// assert_eq!(got, None); |
| /// |
| /// // Duplicate keys result in None |
| /// let keys = ["Athenæum", "Athenæum"]; |
| /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); |
| /// assert_eq!(got, None); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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) |
| } |
| |
| /// Attempts to get mutable references to `N` values in the map at once, without validating that |
| /// the values are unique. |
| /// |
| /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to |
| /// the `i`th key to be looked up. |
| /// |
| /// Returns an array of length `N` with the results of each query. `None` will be returned if |
| /// any of the keys are missing. |
| /// |
| /// For a safe alternative see [`get_many_mut`](`HashTable::get_many_mut`). |
| /// |
| /// # Safety |
| /// |
| /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting |
| /// references are not used. |
| /// |
| /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::Entry; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// for (k, v) in [ |
| /// ("Bodleian Library", 1602), |
| /// ("Athenæum", 1807), |
| /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), |
| /// ("Library of Congress", 1800), |
| /// ] { |
| /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); |
| /// } |
| /// |
| /// let keys = ["Athenæum", "Library of Congress"]; |
| /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); |
| /// assert_eq!( |
| /// got, |
| /// Some([&mut ("Athenæum", 1807), &mut ("Library of Congress", 1800),]), |
| /// ); |
| /// |
| /// // Missing keys result in None |
| /// let keys = ["Athenæum", "New York Public Library"]; |
| /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); |
| /// assert_eq!(got, None); |
| /// |
| /// // Duplicate keys result in None |
| /// let keys = ["Athenæum", "Athenæum"]; |
| /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); |
| /// assert_eq!(got, None); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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() |
| } |
| } |
| |
| /// A view into a single entry in a table, which may either be vacant or occupied. |
| /// |
| /// This `enum` is constructed from the [`entry`] method on [`HashTable`]. |
| /// |
| /// [`HashTable`]: struct.HashTable.html |
| /// [`entry`]: struct.HashTable.html#method.entry |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// for x in ["a", "b", "c"] { |
| /// table.insert_unique(hasher(&x), x, hasher); |
| /// } |
| /// assert_eq!(table.len(), 3); |
| /// |
| /// // Existing value (insert) |
| /// let entry: Entry<_> = table.entry(hasher(&"a"), |&x| x == "a", hasher); |
| /// let _raw_o: OccupiedEntry<_, _> = entry.insert("a"); |
| /// assert_eq!(table.len(), 3); |
| /// // Nonexistent value (insert) |
| /// table.entry(hasher(&"d"), |&x| x == "d", hasher).insert("d"); |
| /// |
| /// // Existing value (or_insert) |
| /// table |
| /// .entry(hasher(&"b"), |&x| x == "b", hasher) |
| /// .or_insert("b"); |
| /// // Nonexistent value (or_insert) |
| /// table |
| /// .entry(hasher(&"e"), |&x| x == "e", hasher) |
| /// .or_insert("e"); |
| /// |
| /// println!("Our HashTable: {:?}", table); |
| /// |
| /// let mut vec: Vec<_> = table.iter().copied().collect(); |
| /// // The `Iter` iterator produces items in arbitrary order, so the |
| /// // items must be sorted to test them against a sorted array. |
| /// vec.sort_unstable(); |
| /// assert_eq!(vec, ["a", "b", "c", "d", "e"]); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub enum Entry<'a, T, A = Global> |
| where |
| A: Allocator, |
| { |
| /// An occupied entry. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// for x in ["a", "b"] { |
| /// table.insert_unique(hasher(&x), x, hasher); |
| /// } |
| /// |
| /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { |
| /// Entry::Vacant(_) => unreachable!(), |
| /// Entry::Occupied(_) => {} |
| /// } |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| Occupied(OccupiedEntry<'a, T, A>), |
| |
| /// A vacant entry. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::<&str>::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { |
| /// Entry::Vacant(_) => {} |
| /// Entry::Occupied(_) => unreachable!(), |
| /// } |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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, |
| { |
| /// Sets the value of the entry, replacing any existing value if there is |
| /// one, and returns an [`OccupiedEntry`]. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<&str> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// let entry = table |
| /// .entry(hasher(&"horseyland"), |&x| x == "horseyland", hasher) |
| /// .insert("horseyland"); |
| /// |
| /// assert_eq!(entry.get(), &"horseyland"); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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), |
| } |
| } |
| |
| /// Ensures a value is in the entry by inserting if it was vacant. |
| /// |
| /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<&str> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// // nonexistent key |
| /// table |
| /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) |
| /// .or_insert("poneyland"); |
| /// assert!(table |
| /// .find(hasher(&"poneyland"), |&x| x == "poneyland") |
| /// .is_some()); |
| /// |
| /// // existing key |
| /// table |
| /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) |
| /// .or_insert("poneyland"); |
| /// assert!(table |
| /// .find(hasher(&"poneyland"), |&x| x == "poneyland") |
| /// .is_some()); |
| /// assert_eq!(table.len(), 1); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn or_insert(self, default: T) -> OccupiedEntry<'a, T, A> { |
| match self { |
| Entry::Occupied(entry) => entry, |
| Entry::Vacant(entry) => entry.insert(default), |
| } |
| } |
| |
| /// Ensures a value is in the entry by inserting the result of the default function if empty.. |
| /// |
| /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<String> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// table |
| /// .entry(hasher("poneyland"), |x| x == "poneyland", |val| hasher(val)) |
| /// .or_insert_with(|| "poneyland".to_string()); |
| /// |
| /// assert!(table |
| /// .find(hasher(&"poneyland"), |x| x == "poneyland") |
| /// .is_some()); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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()), |
| } |
| } |
| |
| /// Provides in-place mutable access to an occupied entry before any |
| /// potential inserts into the table. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<(&str, u32)> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// table |
| /// .entry( |
| /// hasher(&"poneyland"), |
| /// |&(x, _)| x == "poneyland", |
| /// |(k, _)| hasher(&k), |
| /// ) |
| /// .and_modify(|(_, v)| *v += 1) |
| /// .or_insert(("poneyland", 42)); |
| /// assert_eq!( |
| /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), |
| /// Some(&("poneyland", 42)) |
| /// ); |
| /// |
| /// table |
| /// .entry( |
| /// hasher(&"poneyland"), |
| /// |&(x, _)| x == "poneyland", |
| /// |(k, _)| hasher(&k), |
| /// ) |
| /// .and_modify(|(_, v)| *v += 1) |
| /// .or_insert(("poneyland", 42)); |
| /// assert_eq!( |
| /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), |
| /// Some(&("poneyland", 43)) |
| /// ); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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), |
| } |
| } |
| } |
| |
| /// A view into an occupied entry in a `HashTable`. |
| /// It is part of the [`Entry`] enum. |
| /// |
| /// [`Entry`]: enum.Entry.html |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// for x in ["a", "b", "c"] { |
| /// table.insert_unique(hasher(&x), x, hasher); |
| /// } |
| /// assert_eq!(table.len(), 3); |
| /// |
| /// let _entry_o: OccupiedEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap(); |
| /// assert_eq!(table.len(), 3); |
| /// |
| /// // Existing key |
| /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { |
| /// Entry::Vacant(_) => unreachable!(), |
| /// Entry::Occupied(view) => { |
| /// assert_eq!(view.get(), &"a"); |
| /// } |
| /// } |
| /// |
| /// assert_eq!(table.len(), 3); |
| /// |
| /// // Existing key (take) |
| /// match table.entry(hasher(&"c"), |&x| x == "c", hasher) { |
| /// Entry::Vacant(_) => unreachable!(), |
| /// Entry::Occupied(view) => { |
| /// assert_eq!(view.remove().0, "c"); |
| /// } |
| /// } |
| /// assert_eq!(table.find(hasher(&"c"), |&x| x == "c"), None); |
| /// assert_eq!(table.len(), 2); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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, |
| { |
| /// Takes the value out of the entry, and returns it along with a |
| /// `VacantEntry` that can be used to insert another value with the same |
| /// hash as the one that was just removed. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::Entry; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<&str> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// // The table is empty |
| /// assert!(table.is_empty() && table.capacity() == 0); |
| /// |
| /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); |
| /// let capacity_before_remove = table.capacity(); |
| /// |
| /// if let Entry::Occupied(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { |
| /// assert_eq!(o.remove().0, "poneyland"); |
| /// } |
| /// |
| /// assert!(table |
| /// .find(hasher(&"poneyland"), |&x| x == "poneyland") |
| /// .is_none()); |
| /// // Now table hold none elements but capacity is equal to the old one |
| /// assert!(table.len() == 0 && table.capacity() == capacity_before_remove); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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, |
| }, |
| ) |
| } |
| |
| /// Gets a reference to the value in the entry. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::Entry; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<&str> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); |
| /// |
| /// match table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { |
| /// Entry::Vacant(_) => panic!(), |
| /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), |
| /// } |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn get(&self) -> &T { |
| unsafe { self.bucket.as_ref() } |
| } |
| |
| /// Gets a mutable reference to the value in the entry. |
| /// |
| /// If you need a reference to the `OccupiedEntry` which may outlive the |
| /// destruction of the `Entry` value, see [`into_mut`]. |
| /// |
| /// [`into_mut`]: #method.into_mut |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::Entry; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<(&str, u32)> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); |
| /// |
| /// assert_eq!( |
| /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), |
| /// Some(&("poneyland", 12)) |
| /// ); |
| /// |
| /// if let Entry::Occupied(mut o) = table.entry( |
| /// hasher(&"poneyland"), |
| /// |&(x, _)| x == "poneyland", |
| /// |(k, _)| hasher(&k), |
| /// ) { |
| /// o.get_mut().1 += 10; |
| /// assert_eq!(o.get().1, 22); |
| /// |
| /// // We can use the same Entry multiple times. |
| /// o.get_mut().1 += 2; |
| /// } |
| /// |
| /// assert_eq!( |
| /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), |
| /// Some(&("poneyland", 24)) |
| /// ); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn get_mut(&mut self) -> &mut T { |
| unsafe { self.bucket.as_mut() } |
| } |
| |
| /// Converts the OccupiedEntry into a mutable reference to the value in the entry |
| /// with a lifetime bound to the table itself. |
| /// |
| /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. |
| /// |
| /// [`get_mut`]: #method.get_mut |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::Entry; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<(&str, u32)> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); |
| /// |
| /// assert_eq!( |
| /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), |
| /// Some(&("poneyland", 12)) |
| /// ); |
| /// |
| /// let value: &mut (&str, u32); |
| /// match table.entry( |
| /// hasher(&"poneyland"), |
| /// |&(x, _)| x == "poneyland", |
| /// |(k, _)| hasher(&k), |
| /// ) { |
| /// Entry::Occupied(entry) => value = entry.into_mut(), |
| /// Entry::Vacant(_) => panic!(), |
| /// } |
| /// value.1 += 10; |
| /// |
| /// assert_eq!( |
| /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), |
| /// Some(&("poneyland", 22)) |
| /// ); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| pub fn into_mut(self) -> &'a mut T { |
| unsafe { self.bucket.as_mut() } |
| } |
| |
| /// Converts the OccupiedEntry into a mutable reference to the underlying |
| /// table. |
| pub fn into_table(self) -> &'a mut HashTable<T, A> { |
| self.table |
| } |
| } |
| |
| /// A view into a vacant entry in a `HashTable`. |
| /// It is part of the [`Entry`] enum. |
| /// |
| /// [`Entry`]: enum.Entry.html |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::{Entry, HashTable, VacantEntry}; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<&str> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// let entry_v: VacantEntry<_, _> = match table.entry(hasher(&"a"), |&x| x == "a", hasher) { |
| /// Entry::Vacant(view) => view, |
| /// Entry::Occupied(_) => unreachable!(), |
| /// }; |
| /// entry_v.insert("a"); |
| /// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); |
| /// |
| /// // Nonexistent key (insert) |
| /// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { |
| /// Entry::Vacant(view) => { |
| /// view.insert("b"); |
| /// } |
| /// Entry::Occupied(_) => unreachable!(), |
| /// } |
| /// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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, |
| { |
| /// Inserts a new element into the table with the hash that was used to |
| /// obtain the `VacantEntry`. |
| /// |
| /// An `OccupiedEntry` is returned for the newly inserted element. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::Entry; |
| /// use hashbrown::HashTable; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<&str> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// if let Entry::Vacant(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { |
| /// o.insert("poneyland"); |
| /// } |
| /// assert_eq!( |
| /// table.find(hasher(&"poneyland"), |&x| x == "poneyland"), |
| /// Some(&"poneyland") |
| /// ); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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, |
| } |
| } |
| |
| /// Converts the VacantEntry into a mutable reference to the underlying |
| /// table. |
| pub fn into_table(self) -> &'a mut HashTable<T, A> { |
| self.table |
| } |
| } |
| |
| /// Type representing the absence of an entry, as returned by [`HashTable::find_entry`]. |
| /// |
| /// This type only exists due to [limitations] in Rust's NLL borrow checker. In |
| /// the future, `find_entry` will return an `Option<OccupiedEntry>` and this |
| /// type will be removed. |
| /// |
| /// [limitations]: https://smallcultfollowing.com/babysteps/blog/2018/06/15/mir-based-borrow-check-nll-status-update/#polonius |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// # #[cfg(feature = "nightly")] |
| /// # fn test() { |
| /// use ahash::AHasher; |
| /// use hashbrown::hash_table::{AbsentEntry, Entry, HashTable}; |
| /// use std::hash::{BuildHasher, BuildHasherDefault}; |
| /// |
| /// let mut table: HashTable<&str> = HashTable::new(); |
| /// let hasher = BuildHasherDefault::<AHasher>::default(); |
| /// let hasher = |val: &_| hasher.hash_one(val); |
| /// |
| /// let entry_v: AbsentEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap_err(); |
| /// entry_v |
| /// .into_table() |
| /// .insert_unique(hasher(&"a"), "a", hasher); |
| /// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); |
| /// |
| /// // Nonexistent key (insert) |
| /// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { |
| /// Entry::Vacant(view) => { |
| /// view.insert("b"); |
| /// } |
| /// Entry::Occupied(_) => unreachable!(), |
| /// } |
| /// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); |
| /// # } |
| /// # fn main() { |
| /// # #[cfg(feature = "nightly")] |
| /// # test() |
| /// # } |
| /// ``` |
| 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, |
| { |
| /// Converts the AbsentEntry into a mutable reference to the underlying |
| /// table. |
| pub fn into_table(self) -> &'a mut HashTable<T, A> { |
| self.table |
| } |
| } |
| |
| /// An iterator over the entries of a `HashTable` in arbitrary order. |
| /// The iterator element type is `&'a T`. |
| /// |
| /// This `struct` is created by the [`iter`] method on [`HashTable`]. See its |
| /// documentation for more. |
| /// |
| /// [`iter`]: struct.HashTable.html#method.iter |
| /// [`HashTable`]: struct.HashTable.html |
| 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> { |
| // Avoid `Option::map` because it bloats LLVM IR. |
| 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> {} |
| |
| /// A mutable iterator over the entries of a `HashTable` in arbitrary order. |
| /// The iterator element type is `&'a mut T`. |
| /// |
| /// This `struct` is created by the [`iter_mut`] method on [`HashTable`]. See its |
| /// documentation for more. |
| /// |
| /// [`iter_mut`]: struct.HashTable.html#method.iter_mut |
| /// [`HashTable`]: struct.HashTable.html |
| 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> { |
| // Avoid `Option::map` because it bloats LLVM IR. |
| 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> {} |
| |
| /// An owning iterator over the entries of a `HashTable` in arbitrary order. |
| /// The iterator element type is `T`. |
| /// |
| /// This `struct` is created by the [`into_iter`] method on [`HashTable`] |
| /// (provided by the [`IntoIterator`] trait). See its documentation for more. |
| /// The table cannot be used after calling that method. |
| /// |
| /// [`into_iter`]: struct.HashTable.html#method.into_iter |
| /// [`HashTable`]: struct.HashTable.html |
| /// [`IntoIterator`]: https://doc.rust-lang.org/core/iter/trait.IntoIterator.html |
| 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 {} |
| |
| /// A draining iterator over the items of a `HashTable`. |
| /// |
| /// This `struct` is created by the [`drain`] method on [`HashTable`]. |
| /// See its documentation for more. |
| /// |
| /// [`HashTable`]: struct.HashTable.html |
| /// [`drain`]: struct.HashTable.html#method.drain |
| pub struct Drain<'a, T, A: Allocator = Global> { |
| inner: RawDrain<'a, T, A>, |
| } |
| |
| impl<T, A: Allocator> Drain<'_, T, A> { |
| /// Returns a iterator of references over the remaining items. |
| 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() |
| } |
| } |
| |
| /// A draining iterator over entries of a `HashTable` which don't satisfy the predicate `f`. |
| /// |
| /// This `struct` is created by [`HashTable::extract_if`]. See its |
| /// documentation for more. |
| #[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 {} |