mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-21 04:03:11 +00:00
Refactor some hashmap code into a new private function mangle()
Add new private hashmap function fn mangle(&mut self, k: K, not_found: &fn(&K) -> V, found: &fn(&K, &mut V)) -> uint Rewrite find_or_insert() and find_or_insert_with() on top of mangle(). Also take the opportunity to change the return type of find_or_insert() and find_or_insert_with() to &'a mut V. This fixes #6394.
This commit is contained in:
parent
44af5064d0
commit
7bc950c43c
@ -425,9 +425,10 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the value corresponding to the key in the map, or insert
|
/// Modify and return the value corresponding to the key in the map, or
|
||||||
/// and return the value if it doesn't exist.
|
/// insert and return a new value if it doesn't exist.
|
||||||
pub fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a V {
|
pub fn mangle<'a,A>(&'a mut self, k: K, a: A, not_found: &fn(&K, A) -> V,
|
||||||
|
found: &fn(&K, &mut V, A)) -> &'a mut V {
|
||||||
if self.size >= self.resize_at {
|
if self.size >= self.resize_at {
|
||||||
// n.b.: We could also do this after searching, so
|
// n.b.: We could also do this after searching, so
|
||||||
// that we do not resize if this call to insert is
|
// that we do not resize if this call to insert is
|
||||||
@ -441,46 +442,29 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
|
|||||||
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
||||||
let idx = match self.bucket_for_key_with_hash(hash, &k) {
|
let idx = match self.bucket_for_key_with_hash(hash, &k) {
|
||||||
TableFull => fail!("Internal logic error"),
|
TableFull => fail!("Internal logic error"),
|
||||||
FoundEntry(idx) => idx,
|
FoundEntry(idx) => { found(&k, self.mut_value_for_bucket(idx), a); idx }
|
||||||
FoundHole(idx) => {
|
FoundHole(idx) => {
|
||||||
self.buckets[idx] = Some(Bucket{hash: hash, key: k,
|
let v = not_found(&k, a);
|
||||||
value: v});
|
self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v});
|
||||||
self.size += 1;
|
self.size += 1;
|
||||||
idx
|
idx
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.value_for_bucket(idx)
|
self.mut_value_for_bucket(idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the value corresponding to the key in the map, or insert
|
||||||
|
/// and return the value if it doesn't exist.
|
||||||
|
pub fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a mut V {
|
||||||
|
self.mangle(k, v, |_k, a| a, |_k,_v,_a| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the value corresponding to the key in the map, or create,
|
/// Return the value corresponding to the key in the map, or create,
|
||||||
/// insert, and return a new value if it doesn't exist.
|
/// insert, and return a new value if it doesn't exist.
|
||||||
pub fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V)
|
pub fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V)
|
||||||
-> &'a V {
|
-> &'a mut V {
|
||||||
if self.size >= self.resize_at {
|
self.mangle(k, (), |k,_a| f(k), |_k,_v,_a| ())
|
||||||
// n.b.: We could also do this after searching, so
|
|
||||||
// that we do not resize if this call to insert is
|
|
||||||
// simply going to update a key in place. My sense
|
|
||||||
// though is that it's worse to have to search through
|
|
||||||
// buckets to find the right spot twice than to just
|
|
||||||
// resize in this corner case.
|
|
||||||
self.expand();
|
|
||||||
}
|
|
||||||
|
|
||||||
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
|
||||||
let idx = match self.bucket_for_key_with_hash(hash, &k) {
|
|
||||||
TableFull => fail!("Internal logic error"),
|
|
||||||
FoundEntry(idx) => idx,
|
|
||||||
FoundHole(idx) => {
|
|
||||||
let v = f(&k);
|
|
||||||
self.buckets[idx] = Some(Bucket{hash: hash, key: k,
|
|
||||||
value: v});
|
|
||||||
self.size += 1;
|
|
||||||
idx
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
self.value_for_bucket(idx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls a function on each element of a hash map, destroying the hash
|
/// Calls a function on each element of a hash map, destroying the hash
|
||||||
@ -763,15 +747,15 @@ mod test_map {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_find_or_insert() {
|
fn test_find_or_insert() {
|
||||||
let mut m = HashMap::new::<int, int>();
|
let mut m = HashMap::new::<int, int>();
|
||||||
assert_eq!(m.find_or_insert(1, 2), &2);
|
assert_eq!(*m.find_or_insert(1, 2), 2);
|
||||||
assert_eq!(m.find_or_insert(1, 3), &2);
|
assert_eq!(*m.find_or_insert(1, 3), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_find_or_insert_with() {
|
fn test_find_or_insert_with() {
|
||||||
let mut m = HashMap::new::<int, int>();
|
let mut m = HashMap::new::<int, int>();
|
||||||
assert_eq!(m.find_or_insert_with(1, |_| 2), &2);
|
assert_eq!(*m.find_or_insert_with(1, |_| 2), 2);
|
||||||
assert_eq!(m.find_or_insert_with(1, |_| 3), &2);
|
assert_eq!(*m.find_or_insert_with(1, |_| 3), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user