@@ -210,7 +210,11 @@ where
210210 let index = self . entries. len( ) ;
211211 unsafe { self . entries. push_unchecked( Bucket { hash, key, value } ) } ;
212212 return Insert :: Success ( Inserted {
213- index: self . insert_phase_2( probe, Pos :: new( index, hash) ) ,
213+ index: Self :: insert_phase_2(
214+ & mut self . indices,
215+ probe,
216+ Pos :: new( index, hash) ,
217+ ) ,
214218 old_value: None ,
215219 } ) ;
216220 } else if entry_hash == hash && unsafe { self . entries. get_unchecked( i) . key == key }
@@ -241,9 +245,9 @@ where
241245 }
242246
243247 // phase 2 is post-insert where we forward-shift `Pos` in the indices.
244- fn insert_phase_2 ( & mut self , mut probe : usize , mut old_pos : Pos ) -> usize {
245- probe_loop ! ( probe < self . indices. len( ) , {
246- let pos = unsafe { self . indices. get_unchecked_mut( probe) } ;
248+ fn insert_phase_2 ( indices : & mut [ Option < Pos > ; N ] , mut probe : usize , mut old_pos : Pos ) -> usize {
249+ probe_loop ! ( probe < indices. len( ) , {
250+ let pos = unsafe { indices. get_unchecked_mut( probe) } ;
247251
248252 let mut is_none = true ; // work around lack of NLL
249253 if let Some ( pos) = pos. as_mut( ) {
@@ -287,6 +291,50 @@ where
287291 ( entry. key , entry. value )
288292 }
289293
294+ fn retain_in_order < F > ( & mut self , mut keep : F )
295+ where
296+ F : FnMut ( & mut K , & mut V ) -> bool ,
297+ {
298+ const INIT : Option < Pos > = None ;
299+
300+ self . entries
301+ . retain_mut ( |entry| keep ( & mut entry. key , & mut entry. value ) ) ;
302+
303+ if self . entries . len ( ) < self . indices . len ( ) {
304+ for index in self . indices . iter_mut ( ) {
305+ * index = INIT ;
306+ }
307+
308+ for ( index, entry) in self . entries . iter ( ) . enumerate ( ) {
309+ let mut probe = entry. hash . desired_pos ( Self :: mask ( ) ) ;
310+ let mut dist = 0 ;
311+
312+ probe_loop ! ( probe < self . indices. len( ) , {
313+ let pos = & mut self . indices[ probe] ;
314+
315+ if let Some ( pos) = * pos {
316+ let entry_hash = pos. hash( ) ;
317+
318+ // robin hood: steal the spot if it's better for us
319+ let their_dist = entry_hash. probe_distance( Self :: mask( ) , probe) ;
320+ if their_dist < dist {
321+ Self :: insert_phase_2(
322+ & mut self . indices,
323+ probe,
324+ Pos :: new( index, entry. hash) ,
325+ ) ;
326+ break ;
327+ }
328+ } else {
329+ * pos = Some ( Pos :: new( index, entry. hash) ) ;
330+ break ;
331+ }
332+ dist += 1 ;
333+ } ) ;
334+ }
335+ }
336+ }
337+
290338 fn backward_shift_after_removal ( & mut self , probe_at_remove : usize ) {
291339 // backward shift deletion in self.indices
292340 // after probe, shift all non-ideally placed indices backward
@@ -890,6 +938,16 @@ where
890938 . map ( |( probe, found) | self . core . remove_found ( probe, found) . 1 )
891939 }
892940
941+ /// Retains only the elements specified by the predicate.
942+ ///
943+ /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
944+ pub fn retain < F > ( & mut self , mut f : F )
945+ where
946+ F : FnMut ( & K , & mut V ) -> bool ,
947+ {
948+ self . core . retain_in_order ( move |k, v| f ( k, v) ) ;
949+ }
950+
893951 /* Private API */
894952 /// Return probe (indices) and position (entries)
895953 fn find < Q > ( & self , key : & Q ) -> Option < ( usize , usize ) >
@@ -1328,6 +1386,33 @@ mod tests {
13281386 assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
13291387 }
13301388
1389+ #[ test]
1390+ fn retain ( ) {
1391+ let mut none = almost_filled_map ( ) ;
1392+ none. retain ( |_, _| false ) ;
1393+ assert ! ( none. is_empty( ) ) ;
1394+
1395+ let mut all = almost_filled_map ( ) ;
1396+ all. retain ( |_, _| true ) ;
1397+ assert_eq ! ( all. len( ) , MAP_SLOTS - 1 ) ;
1398+
1399+ let mut even = almost_filled_map ( ) ;
1400+ even. retain ( |_, & mut v| v % 2 == 0 ) ;
1401+ assert_eq ! ( even. len( ) , ( MAP_SLOTS - 1 ) / 2 ) ;
1402+ for & v in even. values ( ) {
1403+ assert_eq ! ( v % 2 , 0 ) ;
1404+ }
1405+
1406+ let mut odd = almost_filled_map ( ) ;
1407+ odd. retain ( |_, & mut v| v % 2 != 0 ) ;
1408+ assert_eq ! ( odd. len( ) , MAP_SLOTS / 2 ) ;
1409+ for & v in odd. values ( ) {
1410+ assert_ne ! ( v % 2 , 0 ) ;
1411+ }
1412+ assert_eq ! ( odd. insert( 2 , 2 ) , Ok ( None ) ) ;
1413+ assert_eq ! ( odd. len( ) , ( MAP_SLOTS / 2 ) + 1 ) ;
1414+ }
1415+
13311416 #[ test]
13321417 fn entry_roll_through_all ( ) {
13331418 let mut src: FnvIndexMap < usize , usize , MAP_SLOTS > = FnvIndexMap :: new ( ) ;
0 commit comments