Skip to content

Commit 420e83b

Browse files
authored
Merge pull request rust-lang#722 from cuviper/rustc_try_insert
Add `HashMap::rustc_try_insert`
2 parents 18a04c5 + 51cecbd commit 420e83b

1 file changed

Lines changed: 67 additions & 1 deletion

File tree

src/rustc_entry.rs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use self::RustcEntry::*;
22
use crate::alloc::{Allocator, Global};
3-
use crate::map::{Drain, HashMap, IntoIter, Iter, IterMut, make_hash};
3+
use crate::map::{Drain, HashMap, IntoIter, Iter, IterMut, make_hash, make_hasher};
44
use crate::raw::{Bucket, RawTable};
55
use core::fmt::{self, Debug};
66
use core::hash::{BuildHasher, Hash};
@@ -52,6 +52,72 @@ where
5252
})
5353
}
5454
}
55+
56+
/// Tries to insert a key-value pair into the map, and returns
57+
/// a mutable reference to the value in the entry.
58+
///
59+
/// # Errors
60+
///
61+
/// If the map already had this key present, nothing is updated, and an error
62+
/// containing the occupied entry, the key, and the value is returned.
63+
///
64+
/// # Examples
65+
///
66+
/// Basic usage:
67+
///
68+
/// ```
69+
/// use hashbrown::HashMap;
70+
/// use hashbrown::hash_map::RustcOccupiedError;
71+
///
72+
/// let mut map = HashMap::new();
73+
/// assert_eq!(map.rustc_try_insert(37, "a").ok().unwrap(), &"a");
74+
///
75+
/// match map.rustc_try_insert(37, "b") {
76+
/// Err(RustcOccupiedError { entry, key, value, .. }) => {
77+
/// assert_eq!(entry.key(), &37);
78+
/// assert_eq!(entry.get(), &"a");
79+
/// assert_eq!(key, 37);
80+
/// assert_eq!(value, "b");
81+
/// }
82+
/// _ => panic!()
83+
/// }
84+
/// ```
85+
#[cfg_attr(feature = "inline-more", inline)]
86+
pub fn rustc_try_insert(
87+
&mut self,
88+
key: K,
89+
value: V,
90+
) -> Result<&mut V, RustcOccupiedError<'_, K, V, A>> {
91+
let hash = make_hash(&self.hash_builder, &key);
92+
if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) {
93+
let entry = RustcOccupiedEntry {
94+
elem,
95+
table: &mut self.table,
96+
};
97+
Err(RustcOccupiedError { entry, key, value })
98+
} else {
99+
let hasher = make_hasher(&self.hash_builder);
100+
let entry = self.table.insert_entry(hash, (key, value), hasher);
101+
Ok(&mut entry.1)
102+
}
103+
}
104+
}
105+
106+
/// The error returned by [`rustc_try_insert`](HashMap::rustc_try_insert) when the key already exists.
107+
///
108+
/// Note: There are no impls for this type, because we expect the standard library will
109+
/// immediately reconstruct these errors into its own `OccupiedError`.
110+
#[non_exhaustive]
111+
pub struct RustcOccupiedError<'a, K, V, A = Global>
112+
where
113+
A: Allocator,
114+
{
115+
/// The entry in the map that was already occupied.
116+
pub entry: RustcOccupiedEntry<'a, K, V, A>,
117+
/// The key which was not inserted, because the entry was already occupied.
118+
pub key: K,
119+
/// The value which was not inserted, because the entry was already occupied.
120+
pub value: V,
55121
}
56122

57123
/// A view into a single entry in a map, which may either be vacant or occupied.

0 commit comments

Comments
 (0)