Skip to content

Commit 686cbfa

Browse files
authored
Merge pull request rust-lang#6 from bluss/retain
Implement .retain()
2 parents e0e5be0 + 02a9bf7 commit 686cbfa

File tree

3 files changed

+137
-2
lines changed

3 files changed

+137
-2
lines changed

benches/bench.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,3 +544,36 @@ fn pop_ordermap_100_000(b: &mut Bencher) {
544544
map
545545
});
546546
}
547+
548+
#[bench]
549+
fn retain_few_ordermap_100_000(b: &mut Bencher) {
550+
let map = OMAP_100K.clone();
551+
552+
b.iter(|| {
553+
let mut map = map.clone();
554+
map.retain(|k, _| *k % 7 == 0);
555+
map
556+
});
557+
}
558+
559+
#[bench]
560+
fn retain_half_ordermap_100_000(b: &mut Bencher) {
561+
let map = OMAP_100K.clone();
562+
563+
b.iter(|| {
564+
let mut map = map.clone();
565+
map.retain(|k, _| *k % 2 == 0);
566+
map
567+
});
568+
}
569+
570+
#[bench]
571+
fn retain_many_ordermap_100_000(b: &mut Bencher) {
572+
let map = OMAP_100K.clone();
573+
574+
b.iter(|| {
575+
let mut map = map.clone();
576+
map.retain(|k, _| *k % 100 != 0);
577+
map
578+
});
579+
}

src/lib.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,23 @@ impl<Sz> ShortHashProxy<Sz>
198198

199199
/// A hash map with consistent order of the key-value pairs.
200200
///
201+
/// # Order
202+
///
201203
/// The key-value pairs have a consistent order that is determined by
202204
/// the sequence of insertion and removal calls on the map. The order does
203205
/// not depend on the keys or the hash function at all.
204206
///
205-
/// All iterators traverse the map in the same order.
207+
/// All iterators traverse the map in *the order*.
208+
///
209+
/// # Mutable Keys
210+
///
211+
/// Some methods expose `&mut K`, mutable references to the key as it is stored
212+
/// in the map. The key is allowed to be modified, but *only in a way that
213+
/// preserves its hash and equality* (it is only useful for composite key
214+
/// structs).
215+
///
216+
/// This is sound (memory safe) but a logical error hazard (just like
217+
/// implementing PartialEq, Eq, or Hash incorrectly would be).
206218
///
207219
/// # Examples
208220
///
@@ -314,17 +326,26 @@ macro_rules! probe_loop {
314326
}
315327

316328
impl<K, V> OrderMap<K, V> {
329+
/// Create a new map. (Does not allocate.)
317330
pub fn new() -> Self {
318331
Self::with_capacity(0)
319332
}
320333

334+
/// Create a new map with capacity for `n` key-value pairs. (Does not
335+
/// allocate if `n` is zero.)
336+
///
337+
/// Computes in **O(n)** time.
321338
pub fn with_capacity(n: usize) -> Self {
322339
Self::with_capacity_and_hasher(n, <_>::default())
323340
}
324341
}
325342

326343
impl<K, V, S> OrderMap<K, V, S>
327344
{
345+
/// Create a new map with capacity for `n` key-value pairs. (Does not
346+
/// allocate if `n` is zero.)
347+
///
348+
/// Computes in **O(n)** time.
328349
pub fn with_capacity_and_hasher(n: usize, hash_builder: S) -> Self
329350
where S: BuildHasher
330351
{
@@ -347,6 +368,9 @@ impl<K, V, S> OrderMap<K, V, S>
347368
}
348369
}
349370

371+
/// Return the number of key-value pairs in the map.
372+
///
373+
/// Computes in **O(1)** time.
350374
pub fn len(&self) -> usize { self.entries.len() }
351375

352376
// Return whether we need 32 or 64 bits to specify a bucket or entry index
@@ -367,6 +391,7 @@ impl<K, V, S> OrderMap<K, V, S>
367391
self.indices.len()
368392
}
369393

394+
/// Computes in **O(1)** time.
370395
pub fn capacity(&self) -> usize {
371396
usable_capacity(self.raw_capacity())
372397
}
@@ -420,13 +445,15 @@ pub enum Entry<'a, K: 'a, V: 'a, S: 'a = RandomState> {
420445
}
421446

422447
impl<'a, K, V, S> Entry<'a, K, V, S> {
448+
/// Computes in **O(1)** time (amortized average).
423449
pub fn or_insert(self, default: V) -> &'a mut V {
424450
match self {
425451
Entry::Occupied(entry) => entry.into_mut(),
426452
Entry::Vacant(entry) => entry.insert(default),
427453
}
428454
}
429455

456+
/// Computes in **O(1)** time (amortized average).
430457
pub fn or_insert_with<F>(self, call: F) -> &'a mut V
431458
where F: FnOnce() -> V,
432459
{
@@ -512,6 +539,8 @@ impl<K, V, S> OrderMap<K, V, S>
512539
S: BuildHasher,
513540
{
514541
/// Get the given key’s corresponding entry in the map for in-place manipulation.
542+
///
543+
/// Computes in **O(1)** time (amortized average).
515544
pub fn entry(&mut self, key: K) -> Entry<K, V, S> {
516545
self.reserve_one();
517546
dispatch_32_vs_64!(self.entry_phase_1(key))
@@ -709,7 +738,7 @@ impl<K, V, S> OrderMap<K, V, S>
709738
/// If a value already existed for `key`, that old value is returned
710739
/// in `Some`; otherwise, return `None`.
711740
///
712-
/// Computes in **O(1)** time (amortized).
741+
/// Computes in **O(1)** time (amortized average).
713742
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
714743
self.reserve_one();
715744
if self.size_class_is_64bit() {
@@ -754,6 +783,9 @@ impl<K, V, S> OrderMap<K, V, S>
754783
}
755784
}
756785

786+
/// Return `true` if and equivalent to `key` exists in the map.
787+
///
788+
/// Computes in **O(1)** time (average).
757789
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
758790
where K: Borrow<Q>,
759791
Q: Eq + Hash,
@@ -848,6 +880,8 @@ impl<K, V, S> OrderMap<K, V, S>
848880
/// the postion of what used to be the last element!**
849881
///
850882
/// Return `None` if `key` is not in map.
883+
///
884+
/// Computes in **O(1)** time (average).
851885
pub fn swap_remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
852886
where K: Borrow<Q>,
853887
Q: Eq + Hash,
@@ -889,19 +923,48 @@ impl<K, V, S> OrderMap<K, V, S>
889923
pub fn pop(&mut self) -> Option<(K, V)> {
890924
self.pop_impl()
891925
}
926+
927+
/// Scan through each key-value pair in the map and keep those where the
928+
/// closure `keep` returns `true`.
929+
///
930+
/// The order the elements are visited is not specified.
931+
///
932+
/// Computes in **O(n)** time (average).
933+
pub fn retain<F>(&mut self, mut keep: F)
934+
where F: FnMut(&mut K, &mut V) -> bool,
935+
{
936+
// We can use either forward or reverse scan, but forward was
937+
// faster in a microbenchmark
938+
let mut i = 0;
939+
while i < self.len() {
940+
{
941+
let entry = &mut self.entries[i];
942+
if keep(&mut entry.key, &mut entry.value) {
943+
i += 1;
944+
continue;
945+
}
946+
}
947+
self.swap_remove_index(i);
948+
// skip increment on remove
949+
}
950+
}
892951
}
893952

894953
impl<K, V, S> OrderMap<K, V, S> {
895954
/// Get a key-value pair by index
896955
///
897956
/// Valid indices are *0 <= index < self.len()*
957+
///
958+
/// Computes in **O(1)** time.
898959
pub fn get_index(&self, index: usize) -> Option<(&K, &V)> {
899960
self.entries.get(index).map(|ent| (&ent.key, &ent.value))
900961
}
901962

902963
/// Get a key-value pair by index
903964
///
904965
/// Valid indices are *0 <= index < self.len()*
966+
///
967+
/// Computes in **O(1)** time.
905968
pub fn get_index_mut(&mut self, index: usize) -> Option<(&mut K, &mut V)> {
906969
self.entries.get_mut(index).map(|ent| (&mut ent.key, &mut ent.value))
907970
}

tests/quick.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use quickcheck::Gen;
1212

1313
use std::collections::HashSet;
1414
use std::collections::HashMap;
15+
use std::iter::FromIterator;
1516
use std::hash::Hash;
1617
use std::fmt::Debug;
1718
use std::ops::Deref;
@@ -28,6 +29,13 @@ fn set<'a, T: 'a, I>(iter: I) -> HashSet<T>
2829
iter.into_iter().cloned().collect()
2930
}
3031

32+
fn ordermap<'a, T: 'a, I>(iter: I) -> OrderMap<T, ()>
33+
where I: IntoIterator<Item=&'a T>,
34+
T: Copy + Hash + Eq
35+
{
36+
OrderMap::from_iter(iter.into_iter().cloned().map(|k| (k, ())))
37+
}
38+
3139
quickcheck! {
3240
fn contains(insert: Vec<u32>) -> bool {
3341
let mut map = OrderMap::new();
@@ -179,6 +187,37 @@ quickcheck! {
179187
do_ops(&ops, &mut map, &mut reference);
180188
assert_maps_equivalent(&map, &reference)
181189
}
190+
191+
fn retain(keys: Large<Vec<i8>>, remove: Large<Vec<i8>>) -> bool {
192+
let mut map = ordermap(keys.iter());
193+
let remove_map = ordermap(remove.iter());
194+
let keys_s = set(keys.iter());
195+
let remove_s = set(remove.iter());
196+
let answer = &keys_s - &remove_s;
197+
map.retain(|k, _| !remove_map.contains_key(k));
198+
assert_eq!(map.len(), answer.len());
199+
for key in &answer {
200+
assert!(map.contains_key(key));
201+
}
202+
true
203+
204+
}
205+
206+
// Check that retain visits each key exactly once
207+
fn retain_visit(keys: Large<Vec<i8>>, remove: Large<Vec<i8>>) -> bool {
208+
let mut map = ordermap(keys.iter());
209+
let initial_map = map.clone();
210+
let mut visit = OrderMap::with_capacity(map.len());
211+
let remove_map = ordermap(remove.iter());
212+
map.retain(|k, _| {
213+
*visit.entry(*k).or_insert(0) += 1;
214+
!remove_map.contains_key(k)
215+
});
216+
217+
assert_eq!(visit.len(), initial_map.len());
218+
assert!(visit.iter().all(|(_, v)| *v == 1));
219+
true
220+
}
182221
}
183222

184223
#[derive(Clone, Debug, Hash, PartialEq, Eq)]

0 commit comments

Comments
 (0)