Skip to content

Commit

Permalink
Better SmallMap::retain
Browse files Browse the repository at this point in the history
Summary: Without realloc.

Reviewed By: ndmitchell

Differential Revision: D62112736

fbshipit-source-id: 46c24260481a64b4aa724b1c82a0cc67490687ec
  • Loading branch information
stepancheg authored and facebook-github-bot committed Sep 3, 2024
1 parent ce527e7 commit abaceca
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 14 deletions.
46 changes: 32 additions & 14 deletions starlark_map/src/small_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,18 @@ impl<K, V> SmallMap<K, V> {
self.index = Some(Box::new(index));
}

/// Rebuild the index after entries are reordered or removed.
fn rebuild_index(&mut self) {
if let Some(index) = &mut self.index {
index.clear();
for (i, (k, _)) in self.entries.iter_hashed().enumerate() {
index.insert_unique(k.hash().promote(), i, |_| {
unreachable!("Must have enough capacity")
});
}
}
}

/// Hasher for index resize.
#[inline(always)]
fn hasher(entries: &VecMap<K, V>) -> impl Fn(&usize) -> u64 + '_ {
Expand Down Expand Up @@ -685,14 +697,7 @@ impl<K, V> SmallMap<K, V> {

impl<'a, K, V> Drop for RebuildIndexOnDrop<'a, K, V> {
fn drop(&mut self) {
if let Some(index) = &mut self.map.index {
index.clear();
for (i, (k, _)) in self.map.entries.iter_hashed().enumerate() {
index.insert_unique(k.hash().promote(), i, |_| {
unreachable!("Must have enough capacity")
});
}
}
self.map.rebuild_index();
}
}

Expand Down Expand Up @@ -732,17 +737,30 @@ impl<K, V> SmallMap<K, V> {
}

/// Retains only the elements specified by the predicate.
pub fn retain<F>(&mut self, mut f: F)
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
let mut res = SmallMap::new();
for (k, mut v) in mem::take(self).into_iter_hashed() {
if f(&*k, &mut v) {
res.insert_hashed_unique_unchecked(k, v);
struct RebuildIndexOnDrop<'a, K, V> {
original_len: usize,
map: &'a mut SmallMap<K, V>,
}

impl<'a, K, V> Drop for RebuildIndexOnDrop<'a, K, V> {
fn drop(&mut self) {
debug_assert!(self.map.entries.len() <= self.original_len);
if self.map.len() < self.original_len {
self.map.rebuild_index();
}
}
}
*self = res;

let work = RebuildIndexOnDrop {
original_len: self.len(),
map: self,
};

work.map.entries.retain(f);
}
}

Expand Down
7 changes: 7 additions & 0 deletions starlark_map/src/vec_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,11 @@ impl<K, V> VecMap<K, V> {
self.buckets.aaa_mut().reverse();
self.buckets.bbb_mut().reverse();
}

pub(crate) fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
self.buckets.retain(|(k, v), _| f(k, v));
}
}

0 comments on commit abaceca

Please sign in to comment.