Implement the entirity of the entry api

This commit is contained in:
Gwilym Kuiper 2022-03-20 14:54:53 +00:00
parent 2706b2494d
commit 921a338c59

View file

@ -67,19 +67,21 @@ impl<K, V> HashMap<K, V>
where where
K: Eq + Hash, K: Eq + Hash,
{ {
pub fn insert(&mut self, key: K, value: V) -> Option<V> { pub fn insert(&mut self, key: K, value: V) -> &mut V {
let hash = self.hash(&key); let hash = self.hash(&key);
if let Some(location) = self.nodes.get_location(&key, hash) { let location = if let Some(location) = self.nodes.get_location(&key, hash) {
return self.nodes.replace_at_location(location, key, value); self.nodes.replace_at_location(location, key, value);
} location
} else {
if self.nodes.capacity() * 85 / 100 <= self.len() { if self.nodes.capacity() * 85 / 100 <= self.len() {
self.resize(self.nodes.capacity() * 2); self.resize(self.nodes.capacity() * 2);
} }
self.nodes.insert_new(key, value, hash); self.nodes.insert_new(key, value, hash)
None };
self.nodes.nodes[location].value_mut().unwrap()
} }
pub fn get(&self, key: &K) -> Option<&V> { pub fn get(&self, key: &K) -> Option<&V> {
@ -154,20 +156,27 @@ impl<'a, K, V> IntoIterator for &'a HashMap<K, V> {
} }
pub struct OccupiedEntry<'a, K: 'a, V: 'a> { pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
key: K,
entry: &'a mut Node<K, V>, entry: &'a mut Node<K, V>,
} }
impl<'a, K: 'a, V: 'a> OccupiedEntry<'a, K, V> {
fn value_mut(self) -> &'a mut V {
self.entry.value_mut().unwrap()
}
}
pub struct VacantEntry<'a, K: 'a, V: 'a> { pub struct VacantEntry<'a, K: 'a, V: 'a> {
key: K, key: K,
map: &'a mut HashMap<K, V>, map: &'a mut HashMap<K, V>,
} }
impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
fn insert(self, value: V) fn insert(self, value: V) -> &'a mut V
where where
K: Hash + Eq, K: Hash + Eq,
{ {
self.map.insert(self.key, value); self.map.insert(self.key, value)
} }
} }
@ -180,22 +189,32 @@ impl<'a, K, V> Entry<'a, K, V>
where where
K: Hash + Eq, K: Hash + Eq,
{ {
pub fn or_insert(self, value: V) { pub fn or_insert(self, value: V) -> &'a mut V {
match self { match self {
Entry::Occupied(_) => {} Entry::Occupied(e) => e.value_mut(),
Entry::Vacant(e) => e.insert(value), Entry::Vacant(e) => e.insert(value),
} }
} }
pub fn or_insert_with_key<F>(self, f: F) pub fn or_insert_with<F>(self, f: F) -> &'a mut V
where
F: FnOnce() -> V,
{
match self {
Entry::Occupied(e) => e.value_mut(),
Entry::Vacant(e) => e.insert(f()),
}
}
pub fn or_insert_with_key<F>(self, f: F) -> &'a mut V
where where
F: FnOnce(&K) -> V, F: FnOnce(&K) -> V,
{ {
match self { match self {
Entry::Occupied(_) => {} Entry::Occupied(e) => e.value_mut(),
Entry::Vacant(e) => { Entry::Vacant(e) => {
let value = f(&e.key); let value = f(&e.key);
e.insert(value); e.insert(value)
} }
} }
} }
@ -212,6 +231,23 @@ where
Entry::Vacant(e) => Entry::Vacant(e), Entry::Vacant(e) => Entry::Vacant(e),
} }
} }
pub fn or_default(self) -> &'a mut V
where
V: Default,
{
match self {
Entry::Occupied(e) => e.value_mut(),
Entry::Vacant(e) => e.insert(Default::default()),
}
}
pub fn key(&self) -> &K {
match self {
Entry::Occupied(e) => &e.key,
Entry::Vacant(e) => &e.key,
}
}
} }
impl<'a, K, V> HashMap<K, V> impl<'a, K, V> HashMap<K, V>
@ -224,6 +260,7 @@ where
if let Some(location) = location { if let Some(location) = location {
Entry::Occupied(OccupiedEntry { Entry::Occupied(OccupiedEntry {
key,
entry: &mut self.nodes.nodes[location], entry: &mut self.nodes.nodes[location],
}) })
} else { } else {
@ -258,7 +295,7 @@ impl<K, V> NodeStorage<K, V> {
self.number_of_items self.number_of_items
} }
fn insert_new(&mut self, key: K, value: V, hash: HashType) { fn insert_new(&mut self, key: K, value: V, hash: HashType) -> usize {
debug_assert!( debug_assert!(
self.capacity() * 85 / 100 > self.len(), self.capacity() * 85 / 100 > self.len(),
"Do not have space to insert into len {} with {}", "Do not have space to insert into len {} with {}",
@ -267,6 +304,7 @@ impl<K, V> NodeStorage<K, V> {
); );
let mut new_node = Node::new_with(key, value, hash); let mut new_node = Node::new_with(key, value, hash);
let mut inserted_location = usize::MAX;
loop { loop {
let location = fast_mod( let location = fast_mod(
@ -278,9 +316,16 @@ impl<K, V> NodeStorage<K, V> {
if current_node.has_value() { if current_node.has_value() {
if current_node.get_distance() <= new_node.get_distance() { if current_node.get_distance() <= new_node.get_distance() {
mem::swap(&mut new_node, current_node); mem::swap(&mut new_node, current_node);
if inserted_location == usize::MAX {
inserted_location = location;
}
} }
} else { } else {
self.nodes[location] = new_node; self.nodes[location] = new_node;
if inserted_location == usize::MAX {
inserted_location = location;
}
break; break;
} }
@ -291,6 +336,7 @@ impl<K, V> NodeStorage<K, V> {
} }
self.number_of_items += 1; self.number_of_items += 1;
inserted_location
} }
fn remove_from_location(&mut self, location: usize) -> V { fn remove_from_location(&mut self, location: usize) -> V {