Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 107 additions & 30 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::raw::{
Allocator, Bucket, Global, RawDrain, RawExtractIf, RawIntoIter, RawIter, RawTable,
};
use crate::{DefaultHashBuilder, Equivalent, TryReserveError};
use ::alloc::borrow::ToOwned;
use core::borrow::Borrow;
use core::fmt::{self, Debug};
use core::hash::{BuildHasher, Hash};
Expand Down Expand Up @@ -2910,13 +2911,11 @@ impl<K: Debug, V, S, A: Allocator> Debug for VacantEntry<'_, K, V, S, A> {
///
/// [`Hash`] and [`Eq`] on the borrowed form of the map's key type *must* match those
/// for the key type. It also require that key may be constructed from the borrowed
/// form through the [`From`] trait.
/// form through the [`ToOwned`] trait.
///
/// [`HashMap`]: struct.HashMap.html
/// [`entry_ref`]: struct.HashMap.html#method.entry_ref
/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html
/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
/// [`HashMap`]: HashMap
/// [`entry_ref`]: HashMap::entry_ref
/// [`ToOwned`]: alloc::borrow::ToOwned
///
/// # Examples
///
Expand Down Expand Up @@ -3963,6 +3962,42 @@ impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> {
unsafe { &mut self.elem.as_mut().1 }
}

/// Converts the `OccupiedEntry` into a reference to the key and a
/// mutable reference to the value in the entry with a lifetime bound to the
/// map itself.
///
/// If you need multiple references to the `OccupiedEntry`, see [`key`] and
/// [`get_mut`].
///
/// [`key`]: Self::key
/// [`get_mut`]: Self::get_mut
///
/// # Examples
///
/// ```
/// use hashbrown::hash_map::{Entry, HashMap};
///
/// let mut map: HashMap<&str, u32> = HashMap::new();
/// map.entry("poneyland").or_insert(12);
///
/// assert_eq!(map["poneyland"], 12);
///
/// let key_val: (&&str, &mut u32);
/// match map.entry("poneyland") {
/// Entry::Occupied(entry) => key_val = entry.into_entry(),
/// Entry::Vacant(_) => panic!(),
/// }
/// *key_val.1 += 10;
///
/// assert_eq!(key_val, (&"poneyland", &mut 22));
/// assert_eq!(map["poneyland"], 22);
/// ```
#[cfg_attr(feature = "inline-more", inline)]
pub fn into_entry(self) -> (&'a K, &'a mut V) {
let (key, val) = unsafe { self.elem.as_mut() };
(key, val)
}

/// Sets the value of the entry, and returns the entry's old value.
///
/// # Examples
Expand Down Expand Up @@ -4212,7 +4247,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> {
pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V, S, A>
where
K: Hash,
&'b Q: Into<K>,
Q: ToOwned<Owned = K>,
S: BuildHasher,
{
match self {
Expand Down Expand Up @@ -4246,7 +4281,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> {
pub fn or_insert(self, default: V) -> &'a mut V
where
K: Hash,
&'b Q: Into<K>,
Q: ToOwned<Owned = K>,
S: BuildHasher,
{
match self {
Expand Down Expand Up @@ -4277,7 +4312,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> {
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V
where
K: Hash,
&'b Q: Into<K>,
Q: ToOwned<Owned = K>,
S: BuildHasher,
{
match self {
Expand Down Expand Up @@ -4309,7 +4344,7 @@ impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> {
pub fn or_insert_with_key<F: FnOnce(&Q) -> V>(self, default: F) -> &'a mut V
where
K: Hash + Borrow<Q>,
&'b Q: Into<K>,
Q: ToOwned<Owned = K>,
S: BuildHasher,
{
match self {
Expand Down Expand Up @@ -4405,7 +4440,7 @@ impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator> EntryRef<'a, 'b, K, Q, V
pub fn or_default(self) -> &'a mut V
where
K: Hash,
&'b Q: Into<K>,
Q: ToOwned<Owned = K>,
S: BuildHasher,
{
match self {
Expand Down Expand Up @@ -4438,7 +4473,8 @@ impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator> EntryRef<'a, 'b, K, Q, V
#[cfg_attr(feature = "inline-more", inline)]
pub fn or_default_entry(self) -> OccupiedEntry<'a, K, V, S, A>
where
K: Hash + From<&'b Q>,
K: Hash,
Q: ToOwned<Owned = K>,
S: BuildHasher,
{
match self {
Expand Down Expand Up @@ -4487,13 +4523,13 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K,
pub fn insert(self, value: V) -> &'map mut V
where
K: Hash,
&'key Q: Into<K>,
Q: ToOwned<Owned = K>,
S: BuildHasher,
{
let table = &mut self.table.table;
let entry = table.insert_entry(
self.hash,
(self.key.into(), value),
(self.key.to_owned(), value),
make_hasher::<_, V, S>(&self.table.hash_builder),
);
&mut entry.1
Expand All @@ -4504,7 +4540,7 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K,
///
/// Unlike [`VacantEntryRef::insert`], this method allows the key to be
/// explicitly specified, which is useful for key types that don't implement
/// `K: From<&Q>`.
/// `ToOwned`.
///
/// # Panics
///
Expand All @@ -4520,7 +4556,7 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K,
/// let mut map = HashMap::<(String, String), char>::new();
/// let k = ("c".to_string(), "C".to_string());
/// let v = match map.entry_ref(&k) {
/// // Insert cannot be used here because tuples do not implement From.
/// // Insert cannot be used here because tuples do not implement ToOwned.
/// // However this works because we can manually clone instead.
/// EntryRef::Vacant(r) => r.insert_with_key(k.clone(), 'c'),
/// // In this branch we avoid the clone.
Expand All @@ -4535,17 +4571,7 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K,
Q: Equivalent<K>,
S: BuildHasher,
{
let table = &mut self.table.table;
assert!(
(self.key).equivalent(&key),
"key used for Entry creation is not equivalent to the one used for insertion"
);
let entry = table.insert_entry(
self.hash,
(key, value),
make_hasher::<_, V, S>(&self.table.hash_builder),
);
&mut entry.1
self.insert_entry_with_key(key, value).into_mut()
}

/// Sets the value of the entry with the [`VacantEntryRef`]'s key,
Expand All @@ -4559,7 +4585,7 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K,
///
/// let mut map: HashMap<&str, u32> = HashMap::new();
///
/// if let EntryRef::Vacant(v) = map.entry_ref("poneyland") {
/// if let EntryRef::Vacant(v) = map.entry_ref(&"poneyland") {
/// let o = v.insert_entry(37);
/// assert_eq!(o.get(), &37);
/// }
Expand All @@ -4568,12 +4594,63 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K,
pub fn insert_entry(self, value: V) -> OccupiedEntry<'map, K, V, S, A>
where
K: Hash,
&'key Q: Into<K>,
Q: ToOwned<Owned = K>,
S: BuildHasher,
{
let elem = self.table.table.insert(
self.hash,
(self.key.to_owned(), value),
make_hasher::<_, V, S>(&self.table.hash_builder),
);
OccupiedEntry {
hash: self.hash,
elem,
table: self.table,
}
}

/// Sets the key and value of the entry and returns an [`OccupiedEntry`].
///
/// Unlike [`VacantEntryRef::insert_entry`], this method allows the key to
/// be explicitly specified, which is useful for key types that don't
/// implement `ToOwned`.
///
/// # Panics
///
/// This method panics if `key` is not equivalent to the key used to create
/// the `VacantEntryRef`.
///
/// # Example
///
/// ```
/// use hashbrown::hash_map::EntryRef;
/// use hashbrown::HashMap;
///
/// let mut map = HashMap::<(String, String), char>::new();
/// let k = ("c".to_string(), "C".to_string());
/// let r = match map.entry_ref(&k) {
/// // Insert cannot be used here because tuples do not implement ToOwned.
/// // However this works because we can manually clone instead.
/// EntryRef::Vacant(r) => r.insert_entry_with_key(k.clone(), 'c'),
/// // In this branch we avoid the clone.
/// EntryRef::Occupied(r) => r,
/// };
/// assert_eq!(r.get(), &'c');
/// ```
#[cfg_attr(feature = "inline-more", inline)]
pub fn insert_entry_with_key(self, key: K, value: V) -> OccupiedEntry<'map, K, V, S, A>
where
K: Hash,
Q: Equivalent<K>,
S: BuildHasher,
{
assert!(
(self.key).equivalent(&key),
"key used for Entry creation is not equivalent to the one used for insertion"
);
let elem = self.table.table.insert(
self.hash,
(self.key.into(), value),
(key, value),
make_hasher::<_, V, S>(&self.table.hash_builder),
);
OccupiedEntry {
Expand Down
45 changes: 19 additions & 26 deletions src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -912,12 +912,12 @@ where
/// ```
#[cfg_attr(feature = "inline-more", inline)]
pub fn get_or_insert(&mut self, value: T) -> &T {
let hash = make_hash(&self.map.hash_builder, &value);
let bucket = match self.map.find_or_find_insert_index(hash, &value) {
Ok(bucket) => bucket,
Err(index) => unsafe { self.map.table.insert_at_index(hash, index, (value, ())) },
};
unsafe { &bucket.as_ref().0 }
match self.map.entry(value) {
map::Entry::Occupied(entry) => entry,
map::Entry::Vacant(entry) => entry.insert_entry(()),
}
.into_entry()
.0
}

/// Inserts a value computed from `f` into the set if the given `value` is
Expand Down Expand Up @@ -951,16 +951,12 @@ where
Q: Hash + Equivalent<T> + ?Sized,
F: FnOnce(&Q) -> T,
{
let hash = make_hash(&self.map.hash_builder, value);
let bucket = match self.map.find_or_find_insert_index(hash, value) {
Ok(bucket) => bucket,
Err(index) => {
let new = f(value);
assert!(value.equivalent(&new), "new value is not equivalent");
unsafe { self.map.table.insert_at_index(hash, index, (new, ())) }
}
};
unsafe { &bucket.as_ref().0 }
match self.map.entry_ref(value) {
map::EntryRef::Occupied(entry) => entry,
map::EntryRef::Vacant(entry) => entry.insert_entry_with_key(f(value), ()),
}
.into_entry()
.0
}

/// Gets the given value's corresponding entry in the set for in-place manipulation.
Expand Down Expand Up @@ -1585,16 +1581,13 @@ where
/// ```
fn bitxor_assign(&mut self, rhs: &HashSet<T, S, A>) {
for item in rhs {
let hash = make_hash(&self.map.hash_builder, item);
match self.map.find_or_find_insert_index(hash, item) {
Ok(bucket) => unsafe {
self.map.table.remove(bucket);
},
Err(index) => unsafe {
self.map
.table
.insert_at_index(hash, index, (item.clone(), ()));
},
match self.map.entry_ref(item) {
map::EntryRef::Occupied(entry) => {
entry.remove();
}
map::EntryRef::Vacant(entry) => {
entry.insert(());
}
}
}
}
Expand Down