Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change OccupiedEntry::key() to return the existing key in the map #170

Merged
merged 2 commits into from
Feb 23, 2021
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
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