Skip to content

Commit

Permalink
Auto merge of #118 - passcod:map-entry-insert, r=Amanieu
Browse files Browse the repository at this point in the history
Add RustcVacantEntry::insert_entry for rust-lang/rust#64656

See rust-lang/rust#64656.

~~This was based on v0.5.0 as that's what rustc uses; I can rebase onto master, but I'm not sure whether rustc wants v0.6.0 or if v0.6.0 is rustc-ready.~~

For context, this ultimately provides an API with this shape:

```rust
impl Entry<'a, K, V> {
    fn insert(self, value: V) -> OccupiedEntry<'a, K, V> {…}
}
```

to be used when one wants to insert a value without consuming the Entry, e.g. because one wants to keep a reference to the key around. There's more at the original (defunct) PR: rust-lang/rust#60142.
  • Loading branch information
bors committed Oct 4, 2019
2 parents 31ec80e + ecbdeb9 commit 62a1ae2
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 0 deletions.
90 changes: 90 additions & 0 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,33 @@ where
}

impl<'a, K, V, S> RawEntryMut<'a, K, V, S> {
/// Sets the value of the entry, and returns a RawOccupiedEntryMut.
///
/// # Examples
///
/// ```
/// use hashbrown::HashMap;
///
/// let mut map: HashMap<&str, u32> = HashMap::new();
/// let entry = map.raw_entry_mut().from_key("horseyland").insert("horseyland", 37);
///
/// assert_eq!(entry.remove_entry(), ("horseyland", 37));
/// ```
#[inline]
pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V>
where
K: Hash,
S: BuildHasher,
{
match self {
RawEntryMut::Occupied(mut entry) => {
entry.insert(value);
entry
}
RawEntryMut::Vacant(entry) => entry.insert_entry(key, value),
}
}

/// Ensures a value is in the entry by inserting the default if empty, and returns
/// mutable references to the key and value in the entry.
///
Expand Down Expand Up @@ -1674,6 +1701,25 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
(k, v)
}
}

#[inline]
fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V>
where
K: Hash,
S: BuildHasher,
{
let hash_builder = self.hash_builder;
let mut hasher = self.hash_builder.build_hasher();
key.hash(&mut hasher);

let elem = self.table.insert(hasher.finish(), (key, value), |k| {
make_hash(hash_builder, &k.0)
});
RawOccupiedEntryMut {
elem,
table: self.table,
}
}
}

impl<K, V, S> Debug for RawEntryBuilderMut<'_, K, V, S> {
Expand Down Expand Up @@ -2018,6 +2064,33 @@ where
}

impl<'a, K, V, S> Entry<'a, K, V, S> {
/// Sets the value of the entry, and returns an OccupiedEntry.
///
/// # Examples
///
/// ```
/// use hashbrown::HashMap;
///
/// let mut map: HashMap<&str, u32> = HashMap::new();
/// let entry = map.entry("horseyland").insert(37);
///
/// assert_eq!(entry.key(), &"horseyland");
/// ```
#[inline]
pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V, S>
where
K: Hash,
S: BuildHasher,
{
match self {
Entry::Occupied(mut entry) => {
entry.insert(value);
entry
}
Entry::Vacant(entry) => entry.insert_entry(value),
}
}

/// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry.
///
Expand Down Expand Up @@ -2449,6 +2522,23 @@ impl<'a, K, V, S> VacantEntry<'a, K, V, S> {
});
unsafe { &mut bucket.as_mut().1 }
}

#[inline]
fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, S>
where
K: Hash,
S: BuildHasher,
{
let hash_builder = &self.table.hash_builder;
let elem = self.table.table.insert(self.hash, (self.key, value), |x| {
make_hash(hash_builder, &x.0)
});
OccupiedEntry {
key: None,
elem,
table: self.table,
}
}
}

impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S>
Expand Down
48 changes: 48 additions & 0 deletions src/rustc_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,28 @@ impl<K: Debug, V> Debug for RustcVacantEntry<'_, K, V> {
}

impl<'a, K, V> RustcEntry<'a, K, V> {
/// Sets the value of the entry, and returns a RustcOccupiedEntry.
///
/// # Examples
///
/// ```
/// use hashbrown::HashMap;
///
/// let mut map: HashMap<&str, u32> = HashMap::new();
/// let entry = map.entry("horseyland").insert(37);
///
/// assert_eq!(entry.key(), &"horseyland");
/// ```
pub fn insert(self, value: V) -> RustcOccupiedEntry<'a, K, V> {
match self {
Vacant(entry) => entry.insert_entry(value),
Occupied(mut entry) => {
entry.insert(value);
entry
}
}
}

/// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry.
///
Expand Down Expand Up @@ -546,6 +568,32 @@ impl<'a, K, V> RustcVacantEntry<'a, K, V> {
let bucket = self.table.insert_no_grow(self.hash, (self.key, value));
unsafe { &mut bucket.as_mut().1 }
}

/// Sets the value of the entry with the RustcVacantEntry's key,
/// and returns a RustcOccupiedEntry.
///
/// # Examples
///
/// ```
/// use hashbrown::HashMap;
/// use hashbrown::hash_map::RustcEntry;
///
/// let mut map: HashMap<&str, u32> = HashMap::new();
///
/// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") {
/// let o = v.insert_entry(37);
/// assert_eq!(o.get(), &37);
/// }
/// ```
#[inline]
pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V> {
let bucket = self.table.insert_no_grow(self.hash, (self.key, value));
RustcOccupiedEntry {
key: None,
elem: bucket,
table: self.table,
}
}
}

impl<K, V> IterMut<'_, K, V> {
Expand Down

0 comments on commit 62a1ae2

Please sign in to comment.