Skip to content

Commit 9dce2c3

Browse files
authored
Merge pull request #39 from bluss/mutable-keys
Add trait MutableKeys
2 parents 8465215 + 32cd0e4 commit 9dce2c3

File tree

4 files changed

+109
-77
lines changed

4 files changed

+109
-77
lines changed

src/lib.rs

Lines changed: 29 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod macros;
66
mod serde;
77
mod util;
88
mod equivalent;
9+
mod mutable_keys;
910

1011
use std::hash::Hash;
1112
use std::hash::BuildHasher;
@@ -18,8 +19,9 @@ use std::fmt;
1819
use std::mem::{replace};
1920
use std::marker::PhantomData;
2021

21-
use util::{second, ptrdistance, enumerate};
22+
use util::{third, ptrdistance, enumerate};
2223
pub use equivalent::Equivalent;
24+
pub use mutable_keys::MutableKeys;
2325

2426
fn hash_elem_using<B: BuildHasher, K: ?Sized + Hash>(build: &B, k: &K) -> HashValue {
2527
let mut h = build.build_hasher();
@@ -210,16 +212,6 @@ impl<Sz> ShortHashProxy<Sz>
210212
///
211213
/// All iterators traverse the map in *the order*.
212214
///
213-
/// # Mutable Keys
214-
///
215-
/// Some methods expose `&mut K`, mutable references to the key as it is stored
216-
/// in the map. The key is allowed to be modified, but *only in a way that
217-
/// preserves its hash and equality* (it is only useful for composite key
218-
/// structs).
219-
///
220-
/// This is sound (memory safe) but a logical error hazard (just like
221-
/// implementing PartialEq, Eq, or Hash incorrectly would be).
222-
///
223215
/// # Examples
224216
///
225217
/// ```
@@ -837,22 +829,11 @@ impl<K, V, S> OrderMap<K, V, S>
837829
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
838830
where Q: Hash + Equivalent<K>,
839831
{
840-
self.get_pair(key).map(second)
841-
}
842-
843-
pub fn get_pair<Q: ?Sized>(&self, key: &Q) -> Option<(&K, &V)>
844-
where Q: Hash + Equivalent<K>,
845-
{
846-
if let Some((_, found)) = self.find(key) {
847-
let entry = &self.entries[found];
848-
Some((&entry.key, &entry.value))
849-
} else {
850-
None
851-
}
832+
self.get_full(key).map(third)
852833
}
853834

854835
/// Return item index, key and value
855-
pub fn get_pair_index<Q: ?Sized>(&self, key: &Q) -> Option<(usize, &K, &V)>
836+
pub fn get_full<Q: ?Sized>(&self, key: &Q) -> Option<(usize, &K, &V)>
856837
where Q: Hash + Equivalent<K>,
857838
{
858839
if let Some((_, found)) = self.find(key) {
@@ -866,31 +847,14 @@ impl<K, V, S> OrderMap<K, V, S>
866847
pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
867848
where Q: Hash + Equivalent<K>,
868849
{
869-
self.get_pair_mut(key).map(second)
850+
self.get_full_mut(key).map(third)
870851
}
871852

872-
pub fn get_pair_mut<Q: ?Sized>(&mut self, key: &Q)
873-
-> Option<(&mut K, &mut V)>
853+
pub fn get_full_mut<Q: ?Sized>(&mut self, key: &Q)
854+
-> Option<(usize, &K, &mut V)>
874855
where Q: Hash + Equivalent<K>,
875856
{
876-
if let Some((_, found)) = self.find(key) {
877-
let entry = &mut self.entries[found];
878-
Some((&mut entry.key, &mut entry.value))
879-
} else {
880-
None
881-
}
882-
}
883-
884-
pub fn get_pair_index_mut<Q: ?Sized>(&mut self, key: &Q)
885-
-> Option<(usize, &mut K, &mut V)>
886-
where Q: Hash + Equivalent<K>,
887-
{
888-
if let Some((_, found)) = self.find(key) {
889-
let entry = &mut self.entries[found];
890-
Some((found, &mut entry.key, &mut entry.value))
891-
} else {
892-
None
893-
}
857+
self.get_full_mut2(key).map(|(i, k, v)| (i, &*k, v))
894858
}
895859

896860
/// Return probe (indices) and position (entries)
@@ -902,6 +866,15 @@ impl<K, V, S> OrderMap<K, V, S>
902866
self.find_using(h, move |entry| { Q::equivalent(key, &entry.key) })
903867
}
904868

869+
/// FIXME Same as .swap_remove
870+
///
871+
/// Computes in **O(1)** time (average).
872+
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
873+
where Q: Hash + Equivalent<K>,
874+
{
875+
self.swap_remove(key)
876+
}
877+
905878
/// Remove the key-value pair equivalent to `key` and return
906879
/// its value.
907880
///
@@ -915,33 +888,26 @@ impl<K, V, S> OrderMap<K, V, S>
915888
pub fn swap_remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
916889
where Q: Hash + Equivalent<K>,
917890
{
918-
self.swap_remove_pair(key).map(second)
891+
self.swap_remove_full(key).map(third)
919892
}
920893

921-
/// FIXME Same as .swap_remove
922-
///
923-
/// Computes in **O(1)** time (average).
924-
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
925-
where Q: Hash + Equivalent<K>,
926-
{
927-
self.swap_remove(key)
928-
}
929-
930-
/// Remove the key-value pair equivalent to `key` and return it.
894+
/// Remove the key-value pair equivalent to `key` and return it and
895+
/// the index it had.
931896
///
932897
/// Like `Vec::swap_remove`, the pair is removed by swapping it with the
933898
/// last element of the map and popping it off. **This perturbs
934899
/// the postion of what used to be the last element!**
935900
///
936901
/// Return `None` if `key` is not in map.
937-
pub fn swap_remove_pair<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
902+
pub fn swap_remove_full<Q: ?Sized>(&mut self, key: &Q) -> Option<(usize, K, V)>
938903
where Q: Hash + Equivalent<K>,
939904
{
940905
let (probe, found) = match self.find(key) {
941906
None => return None,
942907
Some(t) => t,
943908
};
944-
Some(self.remove_found(probe, found))
909+
let (k, v) = self.remove_found(probe, found);
910+
Some((found, k, v))
945911
}
946912

947913
/// Remove the last key-value pair
@@ -958,22 +924,9 @@ impl<K, V, S> OrderMap<K, V, S>
958924
///
959925
/// Computes in **O(n)** time (average).
960926
pub fn retain<F>(&mut self, mut keep: F)
961-
where F: FnMut(&mut K, &mut V) -> bool,
927+
where F: FnMut(&K, &mut V) -> bool,
962928
{
963-
// We can use either forward or reverse scan, but forward was
964-
// faster in a microbenchmark
965-
let mut i = 0;
966-
while i < self.len() {
967-
{
968-
let entry = &mut self.entries[i];
969-
if keep(&mut entry.key, &mut entry.value) {
970-
i += 1;
971-
continue;
972-
}
973-
}
974-
self.swap_remove_index(i);
975-
// skip increment on remove
976-
}
929+
self.retain2(move |k, v| keep(&*k, v))
977930
}
978931

979932
/// Sort the key-value pairs of the map and return a by value iterator of
@@ -1712,12 +1665,13 @@ mod tests {
17121665
let remove = [4, 12, 8, 7];
17131666

17141667
for &key in &remove_fail {
1715-
assert!(map.swap_remove_pair(&key).is_none());
1668+
assert!(map.swap_remove_full(&key).is_none());
17161669
}
17171670
println!("{:?}", map);
17181671
for &key in &remove {
17191672
//println!("{:?}", map);
1720-
assert_eq!(map.swap_remove_pair(&key), Some((key, key)));
1673+
let index = map.get_full(&key).unwrap().0;
1674+
assert_eq!(map.swap_remove_full(&key), Some((index, key, key)));
17211675
}
17221676
println!("{:?}", map);
17231677

src/mutable_keys.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
use std::hash::Hash;
3+
use std::hash::BuildHasher;
4+
5+
use super::{OrderMap, Equivalent};
6+
7+
/// Opt-in mutable access to keys.
8+
///
9+
/// You are allowed to modify the keys in the hashmap **if the modifcation
10+
/// does not change the key's hash and equality**.
11+
///
12+
/// If keys are modified erronously, you can no longer look them up.
13+
///
14+
/// These methods expose `&mut K`, mutable references to the key as it is stored
15+
/// in the map. The key is allowed to be modified, but *only in a way that
16+
/// preserves its hash and equality* (it is only useful for composite key
17+
/// structs).
18+
///
19+
/// This is sound (memory safe) but a logical error hazard (just like
20+
/// implementing PartialEq, Eq, or Hash incorrectly would be).
21+
///
22+
pub trait MutableKeys {
23+
type Key;
24+
type Value;
25+
26+
/// Return item index, mutable reference to key and value
27+
fn get_full_mut2<Q: ?Sized>(&mut self, key: &Q)
28+
-> Option<(usize, &mut Self::Key, &mut Self::Value)>
29+
where Q: Hash + Equivalent<Self::Key>;
30+
31+
/// Scan through each key-value pair in the map and keep those where the
32+
/// closure `keep` returns `true`.
33+
///
34+
/// The order the elements are visited is not specified.
35+
///
36+
/// Computes in **O(n)** time (average).
37+
fn retain2<F>(&mut self, keep: F)
38+
where F: FnMut(&mut Self::Key, &mut Self::Value) -> bool;
39+
}
40+
41+
impl<K, V, S> MutableKeys for OrderMap<K, V, S>
42+
where K: Eq + Hash,
43+
S: BuildHasher,
44+
{
45+
type Key = K;
46+
type Value = V;
47+
fn get_full_mut2<Q: ?Sized>(&mut self, key: &Q)
48+
-> Option<(usize, &mut K, &mut V)>
49+
where Q: Hash + Equivalent<K>,
50+
{
51+
if let Some((_, found)) = self.find(key) {
52+
let entry = &mut self.entries[found];
53+
Some((found, &mut entry.key, &mut entry.value))
54+
} else {
55+
None
56+
}
57+
}
58+
59+
fn retain2<F>(&mut self, mut keep: F)
60+
where F: FnMut(&mut K, &mut V) -> bool,
61+
{
62+
// We can use either forward or reverse scan, but forward was
63+
// faster in a microbenchmark
64+
let mut i = 0;
65+
while i < self.len() {
66+
{
67+
let entry = &mut self.entries[i];
68+
if keep(&mut entry.key, &mut entry.value) {
69+
i += 1;
70+
continue;
71+
}
72+
}
73+
self.swap_remove_index(i);
74+
// skip increment on remove
75+
}
76+
}
77+
}

src/util.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
use std::iter::Enumerate;
33
use std::mem::size_of;
44

5-
pub fn second<A, B>(t: (A, B)) -> B { t.1 }
5+
pub fn third<A, B, C>(t: (A, B, C)) -> C { t.2 }
6+
67
pub fn enumerate<I>(iterable: I) -> Enumerate<I::IntoIter>
78
where I: IntoIterator
89
{

tests/quick.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ quickcheck! {
6868
map.insert(key, ());
6969
}
7070
for &key in &remove {
71-
map.swap_remove_pair(&key);
71+
map.swap_remove(&key);
7272
}
7373
let elements = &set(&insert) - &set(&remove);
7474
map.len() == elements.len() && map.iter().count() == elements.len() &&

0 commit comments

Comments
 (0)