Skip to content

Commit 05bee57

Browse files
committed
Make HashTable::find_entry return AbsentEntry on failure
1 parent cce9925 commit 05bee57

File tree

1 file changed

+66
-2
lines changed

1 file changed

+66
-2
lines changed

src/table.rs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,14 +306,14 @@ where
306306
&mut self,
307307
hash: u64,
308308
eq: impl FnMut(&T) -> bool,
309-
) -> Result<OccupiedEntry<'_, T, A>, &mut Self> {
309+
) -> Result<OccupiedEntry<'_, T, A>, AbsentEntry<'_, T, A>> {
310310
match self.raw.find(hash, eq) {
311311
Some(bucket) => Ok(OccupiedEntry {
312312
hash,
313313
bucket,
314314
table: self,
315315
}),
316-
None => Err(self),
316+
None => Err(AbsentEntry { table: self }),
317317
}
318318
}
319319

@@ -1763,6 +1763,70 @@ where
17631763
}
17641764
}
17651765

1766+
/// Type representing the absence of an entry, as returned by [`HashTable::find_entry`].
1767+
///
1768+
/// This type only exists due to [limitations] in Rust's NLL borrow checker. In
1769+
/// the future, `find_entry` will return an `Option<OccupiedEntry>` and this
1770+
/// type will be removed.
1771+
///
1772+
/// [limitations]: https://smallcultfollowing.com/babysteps/blog/2018/06/15/mir-based-borrow-check-nll-status-update/#polonius
1773+
/// # Examples
1774+
///
1775+
/// ```
1776+
/// # #[cfg(feature = "nightly")]
1777+
/// # fn test() {
1778+
/// use ahash::AHasher;
1779+
/// use hashbrown::hash_table::{AbsentEntry, Entry, HashTable};
1780+
/// use std::hash::{BuildHasher, BuildHasherDefault};
1781+
///
1782+
/// let mut table: HashTable<&str> = HashTable::new();
1783+
/// let hasher = BuildHasherDefault::<AHasher>::default();
1784+
/// let hasher = |val: &_| hasher.hash_one(val);
1785+
///
1786+
/// let entry_v: AbsentEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap_err();
1787+
/// entry_v
1788+
/// .into_table()
1789+
/// .insert_unchecked(hasher(&"a"), "a", hasher);
1790+
/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1);
1791+
///
1792+
/// // Nonexistent key (insert)
1793+
/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) {
1794+
/// Entry::Vacant(view) => {
1795+
/// view.insert("b");
1796+
/// }
1797+
/// Entry::Occupied(_) => unreachable!(),
1798+
/// }
1799+
/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2);
1800+
/// # }
1801+
/// # fn main() {
1802+
/// # #[cfg(feature = "nightly")]
1803+
/// # test()
1804+
/// # }
1805+
/// ```
1806+
pub struct AbsentEntry<'a, T, A = Global>
1807+
where
1808+
A: Allocator,
1809+
{
1810+
table: &'a mut HashTable<T, A>,
1811+
}
1812+
1813+
impl<T: fmt::Debug, A: Allocator> fmt::Debug for AbsentEntry<'_, T, A> {
1814+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1815+
f.write_str("AbsentEntry")
1816+
}
1817+
}
1818+
1819+
impl<'a, T, A> AbsentEntry<'a, T, A>
1820+
where
1821+
A: Allocator,
1822+
{
1823+
/// Converts the AbsentEntry into a mutable reference to the underlying
1824+
/// table.
1825+
pub fn into_table(self) -> &'a mut HashTable<T, A> {
1826+
self.table
1827+
}
1828+
}
1829+
17661830
/// An iterator over the entries of a `HashTable` in arbitrary order.
17671831
/// The iterator element type is `&'a T`.
17681832
///

0 commit comments

Comments
 (0)