@@ -210,7 +210,11 @@ where
210
210
let index = self . entries. len( ) ;
211
211
unsafe { self . entries. push_unchecked( Bucket { hash, key, value } ) } ;
212
212
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
+ ) ,
214
218
old_value: None ,
215
219
} ) ;
216
220
} else if entry_hash == hash && unsafe { self . entries. get_unchecked( i) . key == key }
@@ -241,9 +245,9 @@ where
241
245
}
242
246
243
247
// 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) } ;
247
251
248
252
let mut is_none = true ; // work around lack of NLL
249
253
if let Some ( pos) = pos. as_mut( ) {
@@ -287,6 +291,50 @@ where
287
291
( entry. key , entry. value )
288
292
}
289
293
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
+
290
338
fn backward_shift_after_removal ( & mut self , probe_at_remove : usize ) {
291
339
// backward shift deletion in self.indices
292
340
// after probe, shift all non-ideally placed indices backward
@@ -892,6 +940,16 @@ where
892
940
. map ( |( probe, found) | self . core . remove_found ( probe, found) . 1 )
893
941
}
894
942
943
+ /// Retains only the elements specified by the predicate.
944
+ ///
945
+ /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
946
+ pub fn retain < F > ( & mut self , mut f : F )
947
+ where
948
+ F : FnMut ( & K , & mut V ) -> bool ,
949
+ {
950
+ self . core . retain_in_order ( move |k, v| f ( k, v) ) ;
951
+ }
952
+
895
953
/* Private API */
896
954
/// Return probe (indices) and position (entries)
897
955
fn find < Q > ( & self , key : & Q ) -> Option < ( usize , usize ) >
@@ -1320,6 +1378,33 @@ mod tests {
1320
1378
assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
1321
1379
}
1322
1380
1381
+ #[ test]
1382
+ fn retain ( ) {
1383
+ let mut none = almost_filled_map ( ) ;
1384
+ none. retain ( |_, _| false ) ;
1385
+ assert ! ( none. is_empty( ) ) ;
1386
+
1387
+ let mut all = almost_filled_map ( ) ;
1388
+ all. retain ( |_, _| true ) ;
1389
+ assert_eq ! ( all. len( ) , MAP_SLOTS - 1 ) ;
1390
+
1391
+ let mut even = almost_filled_map ( ) ;
1392
+ even. retain ( |_, & mut v| v % 2 == 0 ) ;
1393
+ assert_eq ! ( even. len( ) , ( MAP_SLOTS - 1 ) / 2 ) ;
1394
+ for & v in even. values ( ) {
1395
+ assert_eq ! ( v % 2 , 0 ) ;
1396
+ }
1397
+
1398
+ let mut odd = almost_filled_map ( ) ;
1399
+ odd. retain ( |_, & mut v| v % 2 != 0 ) ;
1400
+ assert_eq ! ( odd. len( ) , MAP_SLOTS / 2 ) ;
1401
+ for & v in odd. values ( ) {
1402
+ assert_ne ! ( v % 2 , 0 ) ;
1403
+ }
1404
+ assert_eq ! ( odd. insert( 2 , 2 ) , Ok ( None ) ) ;
1405
+ assert_eq ! ( odd. len( ) , ( MAP_SLOTS / 2 ) + 1 ) ;
1406
+ }
1407
+
1323
1408
#[ test]
1324
1409
fn entry_roll_through_all ( ) {
1325
1410
let mut src: FnvIndexMap < usize , usize , MAP_SLOTS > = FnvIndexMap :: new ( ) ;
0 commit comments