Skip to content

Commit 4d68d14

Browse files
committed
FEAT: Add trait MutableKeys
- Remove get_pair, and rename get_pair_index to get_full. Same with the mutable variant. - Move mutable key methods to MutableKeys -- we want this feature to be out of the way, but opt-in. The trait has mutable key-versions of get_full and retain
1 parent 8465215 commit 4d68d14

File tree

3 files changed

+90
-60
lines changed

3 files changed

+90
-60
lines changed

src/lib.rs

Lines changed: 11 additions & 60 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::{second, 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)
@@ -958,22 +922,9 @@ impl<K, V, S> OrderMap<K, V, S>
958922
///
959923
/// Computes in **O(n)** time (average).
960924
pub fn retain<F>(&mut self, mut keep: F)
961-
where F: FnMut(&mut K, &mut V) -> bool,
925+
where F: FnMut(&K, &mut V) -> bool,
962926
{
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-
}
927+
self.retain_mut2(move |k, v| keep(&*k, v))
977928
}
978929

979930
/// Sort the key-value pairs of the map and return a by value iterator of

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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use std::iter::Enumerate;
33
use std::mem::size_of;
44

55
pub fn second<A, B>(t: (A, B)) -> B { t.1 }
6+
pub fn third<A, B, C>(t: (A, B, C)) -> C { t.2 }
7+
68
pub fn enumerate<I>(iterable: I) -> Enumerate<I::IntoIter>
79
where I: IntoIterator
810
{

0 commit comments

Comments
 (0)