mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-23 15:46:33 +11:00
Implement remove
This commit is contained in:
parent
019872b8cc
commit
bfebba1ec1
1 changed files with 105 additions and 20 deletions
|
@ -20,13 +20,16 @@ where
|
||||||
K: Sized,
|
K: Sized,
|
||||||
V: Sized,
|
V: Sized,
|
||||||
{
|
{
|
||||||
fn with_new_key_value(&self, new_key: K, new_value: V) -> Self {
|
fn with_new_key_value(self, new_key: K, new_value: V) -> (Self, V) {
|
||||||
|
(
|
||||||
Self {
|
Self {
|
||||||
hash: self.hash,
|
hash: self.hash,
|
||||||
distance_to_initial_bucket: self.distance_to_initial_bucket,
|
distance_to_initial_bucket: self.distance_to_initial_bucket,
|
||||||
key: new_key,
|
key: new_key,
|
||||||
value: new_value,
|
value: new_value,
|
||||||
}
|
},
|
||||||
|
self.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +53,10 @@ impl<K, V> HashMap<K, V> {
|
||||||
hasher: Default::default(),
|
hasher: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.number_of_elements
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fast_mod(len: usize, hash: HashType) -> usize {
|
fn fast_mod(len: usize, hash: HashType) -> usize {
|
||||||
|
@ -62,7 +69,7 @@ where
|
||||||
K: Eq,
|
K: Eq,
|
||||||
{
|
{
|
||||||
fn get_location(&self, key: &K, hash: HashType) -> Option<usize> {
|
fn get_location(&self, key: &K, hash: HashType) -> Option<usize> {
|
||||||
for distance_to_initial_bucket in 0..=self.max_distance_to_initial_bucket + 1 {
|
for distance_to_initial_bucket in 0..=self.max_distance_to_initial_bucket {
|
||||||
let location = fast_mod(self.nodes.len(), hash + distance_to_initial_bucket);
|
let location = fast_mod(self.nodes.len(), hash + distance_to_initial_bucket);
|
||||||
|
|
||||||
let node = &self.nodes[location];
|
let node = &self.nodes[location];
|
||||||
|
@ -83,28 +90,44 @@ impl<K, V> HashMap<K, V>
|
||||||
where
|
where
|
||||||
K: Eq + Hash,
|
K: Eq + Hash,
|
||||||
{
|
{
|
||||||
pub fn put(&mut self, key: K, value: V) {
|
pub fn put(&mut self, key: K, value: V) -> Option<V> {
|
||||||
let mut hasher = self.hasher.build_hasher();
|
let hash = self.hash(&key);
|
||||||
key.hash(&mut hasher);
|
|
||||||
let hash = hasher.finish() as HashType;
|
|
||||||
|
|
||||||
if let Some(location) = self.get_location(&key, hash) {
|
if let Some(location) = self.get_location(&key, hash) {
|
||||||
let old_node = self.nodes[location].as_ref().unwrap();
|
let old_node = self.nodes[location].take().unwrap();
|
||||||
self.nodes[location] = Some(old_node.with_new_key_value(key, value));
|
let (new_node, old_value) = old_node.with_new_key_value(key, value);
|
||||||
|
self.nodes[location] = Some(new_node);
|
||||||
|
|
||||||
return;
|
return Some(old_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.insert_new(key, value, hash);
|
self.insert_new(key, value, hash);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &K) -> Option<&V> {
|
pub fn get(&self, key: &K) -> Option<&V> {
|
||||||
|
let hash = self.hash(key);
|
||||||
|
|
||||||
|
self.get_location(key, hash)
|
||||||
|
.map(|location| &self.nodes[location].as_ref().unwrap().value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, key: &K) -> Option<V> {
|
||||||
|
let hash = self.hash(key);
|
||||||
|
|
||||||
|
self.get_location(key, hash)
|
||||||
|
.map(|location| self.remove_from_location(location))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> HashMap<K, V>
|
||||||
|
where
|
||||||
|
K: Hash,
|
||||||
|
{
|
||||||
|
fn hash(&self, key: &K) -> HashType {
|
||||||
let mut hasher = self.hasher.build_hasher();
|
let mut hasher = self.hasher.build_hasher();
|
||||||
key.hash(&mut hasher);
|
key.hash(&mut hasher);
|
||||||
let hash = hasher.finish() as HashType;
|
hasher.finish() as HashType
|
||||||
|
|
||||||
self.get_location(&key, hash)
|
|
||||||
.map(|location| &self.nodes[location].as_ref().unwrap().value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +167,29 @@ impl<K, V> HashMap<K, V> {
|
||||||
|
|
||||||
self.number_of_elements += 1;
|
self.number_of_elements += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_from_location(&mut self, location: usize) -> V {
|
||||||
|
let mut current_location = location;
|
||||||
|
|
||||||
|
let result = loop {
|
||||||
|
let next_location = fast_mod(self.nodes.len(), (current_location + 1) as HashType);
|
||||||
|
|
||||||
|
// if the next node is empty, then we can clear the current node
|
||||||
|
if self.nodes[next_location].is_none() {
|
||||||
|
break self.nodes[current_location].take().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.nodes.swap(current_location, next_location);
|
||||||
|
self.nodes[current_location]
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.distance_to_initial_bucket -= 1;
|
||||||
|
current_location = next_location;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.number_of_elements -= 1;
|
||||||
|
result.value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -152,7 +198,7 @@ mod test {
|
||||||
use crate::Gba;
|
use crate::Gba;
|
||||||
|
|
||||||
#[test_case]
|
#[test_case]
|
||||||
fn can_store_up_to_initial_capacity_elements(_gba: &mut Gba) {
|
fn can_store_and_retrieve_8_elements(_gba: &mut Gba) {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
|
@ -163,4 +209,43 @@ mod test {
|
||||||
assert_eq!(map.get(&i), Some(&(i % 4)));
|
assert_eq!(map.get(&i), Some(&(i % 4)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn can_get_the_length(_gba: &mut Gba) {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
map.put(i / 2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(map.len(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn returns_none_if_element_does_not_exist(_gba: &mut Gba) {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
map.put(i, i % 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(map.get(&12), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn can_delete_entries(_gba: &mut Gba) {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
map.put(i, i % 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..4 {
|
||||||
|
map.remove(&i);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(map.len(), 4);
|
||||||
|
assert_eq!(map.get(&3), None);
|
||||||
|
assert_eq!(map.get(&7), Some(&1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue