Skip to content

Commit

Permalink
Merge pull request rust-lang#170 from cuviper/entry-key
Browse files Browse the repository at this point in the history
Change OccupiedEntry::key() to return the existing key in the map
  • Loading branch information
cuviper authored Feb 23, 2021
2 parents 015eeea + 0d801a6 commit ddc2088
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 1 deletion.
22 changes: 22 additions & 0 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1648,6 +1648,28 @@ mod tests {
assert_eq!(&mut TestEnum::DefaultValue, map.entry(2).or_default());
}

#[test]
fn occupied_entry_key() {
// These keys match hash and equality, but their addresses are distinct.
let (k1, k2) = (&mut 1, &mut 1);
let k1_ptr = k1 as *const i32;
let k2_ptr = k2 as *const i32;
assert_ne!(k1_ptr, k2_ptr);

let mut map = IndexMap::new();
map.insert(k1, "value");
match map.entry(k2) {
Entry::Occupied(ref e) => {
// `OccupiedEntry::key` should reference the key in the map,
// not the key that was used to find the entry.
let ptr = *e.key() as *const i32;
assert_eq!(ptr, k1_ptr);
assert_ne!(ptr, k2_ptr);
},
Entry::Vacant(_) => panic!(),
}
}

#[test]
fn keys() {
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
Expand Down
12 changes: 12 additions & 0 deletions src/map/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,9 @@ pub enum Entry<'a, K, V> {
}

impl<'a, K, V> Entry<'a, K, V> {
/// Inserts the given default value in the entry if it is vacant and returns a mutable
/// reference to it. Otherwise a mutable reference to an already existent value is returned.
///
/// Computes in **O(1)** time (amortized average).
pub fn or_insert(self, default: V) -> &'a mut V {
match self {
Expand All @@ -453,6 +456,9 @@ impl<'a, K, V> Entry<'a, K, V> {
}
}

/// Inserts the result of the `call` function in the entry if it is vacant and returns a mutable
/// reference to it. Otherwise a mutable reference to an already existent value is returned.
///
/// Computes in **O(1)** time (amortized average).
pub fn or_insert_with<F>(self, call: F) -> &'a mut V
where
Expand All @@ -464,6 +470,8 @@ impl<'a, K, V> Entry<'a, K, V> {
}
}

/// Gets a reference to the entry's key, either within the map if occupied,
/// or else the new key that was used to find the entry.
pub fn key(&self) -> &K {
match *self {
Entry::Occupied(ref entry) => entry.key(),
Expand Down Expand Up @@ -583,10 +591,12 @@ pub struct VacantEntry<'a, K, V> {
}

impl<'a, K, V> VacantEntry<'a, K, V> {
/// Gets a reference to the key that was used to find the entry.
pub fn key(&self) -> &K {
&self.key
}

/// Takes ownership of the key, leaving the entry vacant.
pub fn into_key(self) -> K {
self.key
}
Expand All @@ -596,6 +606,8 @@ impl<'a, K, V> VacantEntry<'a, K, V> {
self.map.len()
}

/// Inserts the entry's key and the given value into the map, and returns a mutable reference
/// to the value.
pub fn insert(self, value: V) -> &'a mut V {
let i = self.map.push(self.hash, self.key, value);
&mut self.map.entries[i].value
Expand Down
14 changes: 13 additions & 1 deletion src/map/core/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,24 @@ unsafe impl<K: Sync, V: Sync> Sync for OccupiedEntry<'_, K, V> {}

// The parent module also adds methods that don't threaten the unsafe encapsulation.
impl<'a, K, V> OccupiedEntry<'a, K, V> {
/// Gets a reference to the entry's key in the map.
///
/// Note that this is not the key that was used to find the entry. There may be an observable
/// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like
/// extra fields or the memory address of an allocation.
pub fn key(&self) -> &K {
&self.key
&self.map.entries[self.index()].key
}

/// Gets a reference to the entry's value in the map.
pub fn get(&self) -> &V {
&self.map.entries[self.index()].value
}

/// Gets a mutable reference to the entry's value in the map.
///
/// If you need a reference which may outlive the destruction of the
/// `Entry` value, see `into_mut`.
pub fn get_mut(&mut self) -> &mut V {
let index = self.index();
&mut self.map.entries[index].value
Expand All @@ -131,6 +141,8 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
unsafe { self.raw_bucket.read() }
}

/// Converts into a mutable reference to the entry's value in the map,
/// with a lifetime bound to the map itself.
pub fn into_mut(self) -> &'a mut V {
let index = self.index();
&mut self.map.entries[index].value
Expand Down

0 comments on commit ddc2088

Please sign in to comment.