Skip to content

Commit f40a539

Browse files
committed
Add HashTable::iter_hash
This is a safe wrapper around `RawTable::iter_hash`. `iter_hash` can be useful for looking up duplicate values in the table. For example you might use it to build a "bag" / "multi map" type which blindly inserts with `HashTable::insert_unique` and allows lookup of multiple values for the same key.
1 parent e39e46e commit f40a539

File tree

1 file changed

+65
-1
lines changed

1 file changed

+65
-1
lines changed

src/table.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::{fmt, iter::FusedIterator, marker::PhantomData};
33
use crate::{
44
raw::{
55
Allocator, Bucket, Global, InsertSlot, RawDrain, RawExtractIf, RawIntoIter, RawIter,
6-
RawTable,
6+
RawIterHash, RawTable,
77
},
88
TryReserveError,
99
};
@@ -741,6 +741,45 @@ where
741741
}
742742
}
743743

744+
/// An iterator visiting all elements which may match a hash.
745+
/// The iterator element type is `&'a T`.
746+
///
747+
/// This iterator may return elements from the table that have a hash value
748+
/// different than the one provided. You should always validate the returned
749+
/// values before using them.
750+
///
751+
/// # Examples
752+
///
753+
/// ```
754+
/// # #[cfg(feature = "nightly")]
755+
/// # fn test() {
756+
/// use hashbrown::{HashTable, DefaultHashBuilder};
757+
/// use std::hash::BuildHasher;
758+
///
759+
/// let mut table = HashTable::new();
760+
/// let hasher = DefaultHashBuilder::default();
761+
/// let hasher = |val: &_| hasher.hash_one(val);
762+
/// table.insert_unique(hasher(&"a"), "a", hasher);
763+
/// table.insert_unique(hasher(&"a"), "b", hasher);
764+
/// table.insert_unique(hasher(&"b"), "c", hasher);
765+
///
766+
/// // Will print "a" and "b" (and possibly "c") in an arbitrary order.
767+
/// for x in table.iter_hash(hasher(&"a")) {
768+
/// println!("{}", x);
769+
/// }
770+
/// # }
771+
/// # fn main() {
772+
/// # #[cfg(feature = "nightly")]
773+
/// # test()
774+
/// # }
775+
/// ```
776+
pub fn iter_hash(&self, hash: u64) -> IterHash<'_, T> {
777+
IterHash {
778+
inner: unsafe { self.raw.iter_hash(hash) },
779+
_marker: PhantomData,
780+
}
781+
}
782+
744783
/// Retains only the elements specified by the predicate.
745784
///
746785
/// In other words, remove all elements `e` such that `f(&e)` returns `false`.
@@ -1932,6 +1971,31 @@ impl<T> ExactSizeIterator for IterMut<'_, T> {
19321971

19331972
impl<T> FusedIterator for IterMut<'_, T> {}
19341973

1974+
/// An iterator over the entries of a `HashTable` that could match a given hash.
1975+
/// The iterator element type is `&'a T`.
1976+
///
1977+
/// This `struct` is created by the [`iter_hash`] method on [`HashTable`]. See its
1978+
/// documentation for more.
1979+
///
1980+
/// [`iter_hash`]: struct.HashTable.html#method.iter_hash
1981+
/// [`HashTable`]: struct.HashTable.html
1982+
pub struct IterHash<'a, T> {
1983+
inner: RawIterHash<T>,
1984+
_marker: PhantomData<&'a T>,
1985+
}
1986+
1987+
impl<'a, T> Iterator for IterHash<'a, T> {
1988+
type Item = &'a T;
1989+
1990+
fn next(&mut self) -> Option<Self::Item> {
1991+
// Avoid `Option::map` because it bloats LLVM IR.
1992+
match self.inner.next() {
1993+
Some(bucket) => Some(unsafe { bucket.as_ref() }),
1994+
None => None,
1995+
}
1996+
}
1997+
}
1998+
19351999
/// An owning iterator over the entries of a `HashTable` in arbitrary order.
19362000
/// The iterator element type is `T`.
19372001
///

0 commit comments

Comments
 (0)