Skip to content

Commit 6d6804a

Browse files
committed
add hashmap view
1 parent 4b62f17 commit 6d6804a

File tree

2 files changed

+208
-6
lines changed

2 files changed

+208
-6
lines changed

src/libstd/collections/hashmap/map.rs

+207-6
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ use ops::{Deref, DerefMut};
2525
use option::{Some, None, Option};
2626
use result::{Ok, Err};
2727
use ops::Index;
28+
use core::result::Result;
2829

2930
use super::table;
3031
use super::table::{
3132
Bucket,
3233
BucketWithTable,
3334
Empty,
35+
EmptyBucket,
3436
Full,
3537
FullBucket,
3638
FullBucketImm,
@@ -286,11 +288,11 @@ fn search_hashed<K: Eq, V, M: Deref<RawTable<K, V>>>(table: M, hash: &SafeHash,
286288
search_hashed_generic(table, hash, |k_| *k == *k_)
287289
}
288290

289-
fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> V {
290-
let (empty, _k, retval) = starting_bucket.take();
291+
fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> (K, V) {
292+
let (empty, retkey, retval) = starting_bucket.take();
291293
let mut gap = match empty.gap_peek() {
292294
Some(b) => b,
293-
None => return retval
295+
None => return (retkey, retval)
294296
};
295297

296298
while gap.full().distance() != 0 {
@@ -301,7 +303,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> V {
301303
}
302304

303305
// Now we've done all our shifting. Return the value we grabbed earlier.
304-
return retval;
306+
return (retkey, retval);
305307
}
306308

307309
/// Perform robin hood bucket stealing at the given `bucket`. You must
@@ -525,7 +527,8 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> MutableMap<K, V> for HashMap<K, V, H>
525527
self.make_some_room(potential_new_size);
526528

527529
self.search_mut(k).map(|bucket| {
528-
pop_internal(bucket)
530+
let (_k, val) = pop_internal(bucket);
531+
val
529532
})
530533
}
531534
}
@@ -855,6 +858,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
855858
/// // Find the existing key
856859
/// assert_eq!(*map.find_or_insert("a", -2), 1);
857860
/// ```
861+
//#[deprecated = "use view instead"]
858862
pub fn find_or_insert(&mut self, k: K, v: V) -> &mut V {
859863
self.find_with_or_insert_with(k, v, |_k, _v, _a| (), |_k, a| a)
860864
}
@@ -874,6 +878,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
874878
/// // Find the existing key
875879
/// assert_eq!(*map.find_or_insert_with(2, |&key| key as uint), 10);
876880
/// ```
881+
//#[deprecated = "use view instead"]
877882
pub fn find_or_insert_with<'a>(&'a mut self, k: K, f: |&K| -> V)
878883
-> &'a mut V {
879884
self.find_with_or_insert_with(k, (), |_k, _v, _a| (), |k, _a| f(k))
@@ -896,6 +901,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
896901
/// assert_eq!(*map.insert_or_update_with("a", 9, |_key, val| *val = 7), 7);
897902
/// assert_eq!(map["a"], 7);
898903
/// ```
904+
//#[deprecated = "use view instead"]
899905
pub fn insert_or_update_with<'a>(
900906
&'a mut self,
901907
k: K,
@@ -953,6 +959,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
953959
/// assert_eq!(map["b key"], vec!["new value"]);
954960
/// assert_eq!(map["z key"], vec!["new value", "value"]);
955961
/// ```
962+
//#[deprecated = "use view instead"]
956963
pub fn find_with_or_insert_with<'a, A>(&'a mut self,
957964
k: K,
958965
a: A,
@@ -1112,7 +1119,8 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
11121119

11131120
match self.search_equiv_mut(k) {
11141121
Some(bucket) => {
1115-
Some(pop_internal(bucket))
1122+
let (_k, val) = pop_internal(bucket);
1123+
Some(val)
11161124
}
11171125
_ => None
11181126
}
@@ -1230,6 +1238,55 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
12301238
inner: self.table.move_iter().map(|(_, k, v)| (k, v))
12311239
}
12321240
}
1241+
1242+
/// Creates a view into a single spot in the map for inplace manipulation
1243+
pub fn view<'a>(&'a mut self, key: K) -> Entry<'a, K, V> {
1244+
let potential_new_size = self.table.size() + 1;
1245+
self.make_some_room(potential_new_size);
1246+
1247+
let hash = self.make_hash(&key);
1248+
let elem = search_entry_hashed(&mut self.table, &hash, &key);
1249+
Entry{ key: key, hash: hash, elem: elem }
1250+
}
1251+
}
1252+
1253+
fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: &SafeHash, k: &K)
1254+
-> EntryState<K, V, &'a mut RawTable<K, V>>{
1255+
// Worst case, we'll find one empty bucket among `size + 1` buckets.
1256+
let size = table.size();
1257+
let mut probe = Bucket::new(table, hash);
1258+
let ib = probe.index();
1259+
1260+
loop {
1261+
let bucket = match probe.peek() {
1262+
Empty(bucket) => {
1263+
// Found a hole!
1264+
return NoElem(bucket);
1265+
},
1266+
Full(bucket) => bucket
1267+
};
1268+
1269+
if bucket.hash() == *hash {
1270+
let is_eq = {
1271+
let (bucket_k, _) = bucket.read();
1272+
*k == *bucket_k
1273+
};
1274+
1275+
if is_eq {
1276+
return EqElem(bucket);
1277+
}
1278+
}
1279+
1280+
let robin_ib = bucket.index() as int - bucket.distance() as int;
1281+
1282+
if (ib as int) < robin_ib {
1283+
// Found a luckier bucket than me. Better steal his spot.
1284+
return NeqElem(bucket, robin_ib as uint);
1285+
}
1286+
1287+
probe = bucket.next();
1288+
assert!(probe.index() != ib + size + 1);
1289+
}
12331290
}
12341291

12351292
impl<K: Eq + Hash<S>, V: Clone, S, H: Hasher<S>> HashMap<K, V, H> {
@@ -1329,6 +1386,20 @@ pub struct MoveEntries<K, V> {
13291386
inner: iter::Map<'static, (SafeHash, K, V), (K, V), table::MoveEntries<K, V>>
13301387
}
13311388

1389+
/// Possible states of an Entry
1390+
enum EntryState<K, V, M> {
1391+
EqElem(FullBucket<K, V, M>),
1392+
NeqElem(FullBucket<K, V, M>, uint),
1393+
NoElem(EmptyBucket<K, V, M>),
1394+
}
1395+
1396+
/// Mutable View into a HashMap's index
1397+
pub struct Entry<'a, K, V> {
1398+
hash: SafeHash,
1399+
key: K,
1400+
elem: EntryState<K,V, &'a mut RawTable<K, V>>,
1401+
}
1402+
13321403
impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> {
13331404
#[inline]
13341405
fn next(&mut self) -> Option<(&'a K, &'a V)> {
@@ -1362,6 +1433,81 @@ impl<K, V> Iterator<(K, V)> for MoveEntries<K, V> {
13621433
}
13631434
}
13641435

1436+
impl<'a, K, V> Entry<'a, K, V> {
1437+
/// Get a reference to both the key and value at the Entry's location
1438+
#[inline]
1439+
fn get_internal(&self) -> Option<(&K, &V)> {
1440+
match self.elem {
1441+
EqElem(ref bucket) => Some(bucket.read()),
1442+
_ => None
1443+
}
1444+
}
1445+
1446+
/// Get a reference to the value at the Entry's location
1447+
#[inline]
1448+
pub fn get(&self) -> Option<&V> {
1449+
self.get_internal().map(|(_, v)| v)
1450+
}
1451+
1452+
/// Get a mutable reference to the value at the Entry's location
1453+
#[inline]
1454+
pub fn get_mut(&mut self) -> Option<&mut V> {
1455+
match self.elem {
1456+
EqElem(ref mut bucket) => {
1457+
let (_, v) = bucket.read_mut();
1458+
Some(v)
1459+
},
1460+
_ => None
1461+
}
1462+
}
1463+
1464+
/// Get a reference to the key at the Entry's location
1465+
#[inline]
1466+
pub fn get_key(&self) -> Option<&K> {
1467+
self.get_internal().map(|(k, _)| k)
1468+
}
1469+
1470+
/// Return whether the Entry's location contains anything
1471+
#[inline]
1472+
pub fn is_empty(&self) -> bool {
1473+
self.get_internal().is_none()
1474+
}
1475+
1476+
/// Set the key and value of the location pointed to by the Entry, and return any old
1477+
/// key and value that might have been there
1478+
#[inline]
1479+
pub fn set(self, value: V) -> Option<(K, V)> {
1480+
match self.elem {
1481+
EqElem(mut bucket) => {
1482+
let (_, k, v) = bucket.replace(self.hash, self.key, value);
1483+
Some((k, v))
1484+
},
1485+
NeqElem(bucket, ib) => {
1486+
robin_hood(bucket, ib, self.hash, self.key, value);
1487+
None
1488+
},
1489+
NoElem(bucket) => {
1490+
bucket.put(self.hash, self.key, value);
1491+
None
1492+
}
1493+
}
1494+
}
1495+
1496+
/// Get a reference to the Entry's key
1497+
#[inline]
1498+
pub fn key(&self) -> &K {
1499+
&self.key
1500+
}
1501+
1502+
/// Retrieve the Entry's key
1503+
#[inline]
1504+
pub fn into_key(self) -> K {
1505+
self.key
1506+
}
1507+
}
1508+
1509+
1510+
13651511
/// HashMap keys iterator
13661512
pub type Keys<'a, K, V> =
13671513
iter::Map<'static, (&'a K, &'a V), &'a K, Entries<'a, K, V>>;
@@ -2002,4 +2148,59 @@ mod test_map {
20022148

20032149
map[4];
20042150
}
2151+
2152+
#[test]
2153+
fn test_view(){
2154+
let xs = [(1i, 10i), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
2155+
2156+
let mut map: HashMap<int, int> = xs.iter().map(|&x| x).collect();
2157+
2158+
{
2159+
// Existing key (insert)
2160+
let view = map.view(1);
2161+
assert!(!view.is_empty());
2162+
assert_eq!(view.key(), &1);
2163+
assert_eq!(view.get().unwrap(), &10);
2164+
assert_eq!(view.get_key().unwrap(), &1);
2165+
assert_eq!(view.set(100), Some((1, 10)));
2166+
}
2167+
assert_eq!(map.find(&1).unwrap(), &100);
2168+
assert_eq!(map.len(), 6);
2169+
2170+
2171+
// Existing key (update)
2172+
{
2173+
let mut view = map.view(2);
2174+
{
2175+
let v = view.get_mut().unwrap();
2176+
let new_v = (*v) * 10;
2177+
*v = new_v;
2178+
}
2179+
assert_eq!(view.key(), &2);
2180+
}
2181+
assert_eq!(map.find(&2).unwrap(), &200);
2182+
assert_eq!(map.len(), 6);
2183+
2184+
2185+
// Inexistent key (insert)
2186+
{
2187+
let view = map.view(10);
2188+
assert!(view.is_empty());
2189+
assert_eq!(view.key(), &10);
2190+
assert_eq!(view.get(), None);
2191+
assert_eq!(view.get_key(), None);
2192+
assert_eq!(view.set(1000), None);
2193+
}
2194+
assert_eq!(map.find(&10).unwrap(), &1000);
2195+
assert_eq!(map.len(), 7);
2196+
2197+
2198+
// Inexistent key (update)
2199+
{
2200+
let mut view = map.view(20);
2201+
assert_eq!(view.get_mut(), None);
2202+
assert_eq!(view.key(), &20);
2203+
}
2204+
assert_eq!(map.find(&20), None);
2205+
}
20052206
}

src/libstd/collections/hashmap/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub use self::map::HashMap;
1414
pub use self::map::Entries;
1515
pub use self::map::MutEntries;
1616
pub use self::map::MoveEntries;
17+
pub use self::map::Entry;
1718
pub use self::map::Keys;
1819
pub use self::map::Values;
1920
pub use self::map::INITIAL_CAPACITY;

0 commit comments

Comments
 (0)