Skip to content

Commit a84c824

Browse files
committed
Add hash_map::{OccupiedEntry::into_entry, VacantEntryRef::insert_entry_with_key}
1 parent cfe5ba1 commit a84c824

File tree

2 files changed

+94
-21
lines changed

2 files changed

+94
-21
lines changed

src/map.rs

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3926,6 +3926,42 @@ impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> {
39263926
&mut self.inner.into_mut().1
39273927
}
39283928

3929+
/// Converts the `OccupiedEntry` into a reference to the key and a
3930+
/// mutable reference to the value in the entry with a lifetime bound to the
3931+
/// map itself.
3932+
///
3933+
/// If you need multiple references to the `OccupiedEntry`, see [`key`] and
3934+
/// [`get_mut`].
3935+
///
3936+
/// [`key`]: Self::key
3937+
/// [`get_mut`]: Self::get_mut
3938+
///
3939+
/// # Examples
3940+
///
3941+
/// ```
3942+
/// use hashbrown::hash_map::{Entry, HashMap};
3943+
///
3944+
/// let mut map: HashMap<&str, u32> = HashMap::new();
3945+
/// map.entry("poneyland").or_insert(12);
3946+
///
3947+
/// assert_eq!(map["poneyland"], 12);
3948+
///
3949+
/// let key_val: (&&str, &mut u32);
3950+
/// match map.entry("poneyland") {
3951+
/// Entry::Occupied(entry) => key_val = entry.into_entry(),
3952+
/// Entry::Vacant(_) => panic!(),
3953+
/// }
3954+
/// *key_val.1 += 10;
3955+
///
3956+
/// assert_eq!(key_val, (&"poneyland", &mut 22));
3957+
/// assert_eq!(map["poneyland"], 22);
3958+
/// ```
3959+
#[cfg_attr(feature = "inline-more", inline)]
3960+
pub fn into_entry(self) -> (&'a K, &'a mut V) {
3961+
let (key, val) = unsafe { self.elem.as_mut() };
3962+
(key, val)
3963+
}
3964+
39293965
/// Sets the value of the entry, and returns the entry's old value.
39303966
///
39313967
/// # Examples
@@ -4476,11 +4512,7 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K,
44764512
Q: Equivalent<K>,
44774513
S: BuildHasher,
44784514
{
4479-
assert!(
4480-
(self.key).equivalent(&key),
4481-
"key used for Entry creation is not equivalent to the one used for insertion"
4482-
);
4483-
&mut self.inner.insert((key, value)).into_mut().1
4515+
self.insert_entry_with_key(key, value).into_mut()
44844516
}
44854517

44864518
/// Sets the value of the entry with the [`VacantEntryRef`]'s key,
@@ -4511,6 +4543,51 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K,
45114543
marker: PhantomData,
45124544
}
45134545
}
4546+
4547+
/// Sets the key and value of the entry and returns an [`OccupiedEntry`].
4548+
///
4549+
/// Unlike [`VacantEntryRef::insert_entry`], this method allows the key to
4550+
/// be explicitly specified, which is useful for key types that don't
4551+
/// implement `K: From<&Q>`.
4552+
///
4553+
/// # Panics
4554+
///
4555+
/// This method panics if `key` is not equivalent to the key used to create
4556+
/// the `VacantEntryRef`.
4557+
///
4558+
/// # Example
4559+
///
4560+
/// ```
4561+
/// use hashbrown::hash_map::EntryRef;
4562+
/// use hashbrown::HashMap;
4563+
///
4564+
/// let mut map = HashMap::<(String, String), char>::new();
4565+
/// let k = ("c".to_string(), "C".to_string());
4566+
/// let r = match map.entry_ref(&k) {
4567+
/// // Insert cannot be used here because tuples do not implement From.
4568+
/// // However this works because we can manually clone instead.
4569+
/// EntryRef::Vacant(r) => r.insert_entry_with_key(k.clone(), 'c'),
4570+
/// // In this branch we avoid the clone.
4571+
/// EntryRef::Occupied(r) => r,
4572+
/// };
4573+
/// assert_eq!(r.get(), &'c');
4574+
/// ```
4575+
#[cfg_attr(feature = "inline-more", inline)]
4576+
pub fn insert_entry_with_key(self, key: K, value: V) -> OccupiedEntry<'map, K, V, S, A>
4577+
where
4578+
K: Hash,
4579+
Q: Equivalent<K>,
4580+
S: BuildHasher,
4581+
{
4582+
assert!(
4583+
(self.key).equivalent(&key),
4584+
"key used for Entry creation is not equivalent to the one used for insertion"
4585+
);
4586+
OccupiedEntry {
4587+
inner: self.inner.insert((key, value)),
4588+
marker: PhantomData,
4589+
}
4590+
}
45144591
}
45154592

45164593
impl<K, V, S, A> FromIterator<(K, V)> for HashMap<K, V, S, A>

src/set.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -912,12 +912,12 @@ where
912912
/// ```
913913
#[cfg_attr(feature = "inline-more", inline)]
914914
pub fn get_or_insert(&mut self, value: T) -> &T {
915-
let hash = make_hash(&self.map.hash_builder, &value);
916-
let bucket = match self.map.find_or_find_insert_index(hash, &value) {
917-
Ok(bucket) => bucket,
918-
Err(index) => unsafe { self.map.table.raw.insert_at_index(hash, index, (value, ())) },
919-
};
920-
unsafe { &bucket.as_ref().0 }
915+
match self.map.entry(value) {
916+
map::Entry::Occupied(entry) => entry,
917+
map::Entry::Vacant(entry) => entry.insert_entry(()),
918+
}
919+
.into_entry()
920+
.0
921921
}
922922

923923
/// Inserts a value computed from `f` into the set if the given `value` is
@@ -951,16 +951,12 @@ where
951951
Q: Hash + Equivalent<T> + ?Sized,
952952
F: FnOnce(&Q) -> T,
953953
{
954-
let hash = make_hash(&self.map.hash_builder, value);
955-
let bucket = match self.map.find_or_find_insert_index(hash, value) {
956-
Ok(bucket) => bucket,
957-
Err(index) => {
958-
let new = f(value);
959-
assert!(value.equivalent(&new), "new value is not equivalent");
960-
unsafe { self.map.table.raw.insert_at_index(hash, index, (new, ())) }
961-
}
962-
};
963-
unsafe { &bucket.as_ref().0 }
954+
match self.map.entry_ref(value) {
955+
map::EntryRef::Occupied(entry) => entry,
956+
map::EntryRef::Vacant(entry) => entry.insert_entry_with_key(f(value), ()),
957+
}
958+
.into_entry()
959+
.0
964960
}
965961

966962
/// Gets the given value's corresponding entry in the set for in-place manipulation.

0 commit comments

Comments
 (0)