@@ -34,6 +34,27 @@ fn get_hash<K, V>(entries: &[Bucket<K, V>]) -> impl Fn(&usize) -> u64 + '_ {
34
34
move |& i| entries[ i] . hash . get ( )
35
35
}
36
36
37
+ #[ inline]
38
+ fn equivalent < ' a , K , V , Q : ?Sized + Equivalent < K > > (
39
+ key : & ' a Q ,
40
+ entries : & ' a [ Bucket < K , V > ] ,
41
+ ) -> impl Fn ( & usize ) -> bool + ' a {
42
+ move |& i| Q :: equivalent ( key, & entries[ i] . key )
43
+ }
44
+
45
+ #[ inline]
46
+ fn erase_index ( table : & mut RawTable < usize > , hash : HashValue , index : usize ) {
47
+ table. erase_entry ( hash. get ( ) , move |& i| i == index) ;
48
+ }
49
+
50
+ #[ inline]
51
+ fn update_index ( table : & mut RawTable < usize > , hash : HashValue , old : usize , new : usize ) {
52
+ let index = table
53
+ . get_mut ( hash. get ( ) , move |& i| i == old)
54
+ . expect ( "index not found" ) ;
55
+ * index = new;
56
+ }
57
+
37
58
impl < K , V > Clone for IndexMapCore < K , V >
38
59
where
39
60
K : Clone ,
@@ -160,7 +181,7 @@ impl<K, V> IndexMapCore<K, V> {
160
181
pub ( crate ) fn pop ( & mut self ) -> Option < ( K , V ) > {
161
182
if let Some ( entry) = self . entries . pop ( ) {
162
183
let last = self . entries . len ( ) ;
163
- self . erase_index ( entry. hash , last) ;
184
+ erase_index ( & mut self . indices , entry. hash , last) ;
164
185
Some ( ( entry. key , entry. value ) )
165
186
} else {
166
187
None
@@ -181,6 +202,15 @@ impl<K, V> IndexMapCore<K, V> {
181
202
i
182
203
}
183
204
205
+ /// Return the index in `entries` where an equivalent key can be found
206
+ pub ( crate ) fn get_index_of < Q > ( & self , hash : HashValue , key : & Q ) -> Option < usize >
207
+ where
208
+ Q : ?Sized + Equivalent < K > ,
209
+ {
210
+ let eq = equivalent ( key, & self . entries ) ;
211
+ self . indices . get ( hash. get ( ) , eq) . copied ( )
212
+ }
213
+
184
214
pub ( crate ) fn insert_full ( & mut self , hash : HashValue , key : K , value : V ) -> ( usize , Option < V > )
185
215
where
186
216
K : Eq ,
@@ -191,6 +221,154 @@ impl<K, V> IndexMapCore<K, V> {
191
221
}
192
222
}
193
223
224
+ /// Remove an entry by shifting all entries that follow it
225
+ pub ( crate ) fn shift_remove_full < Q > ( & mut self , hash : HashValue , key : & Q ) -> Option < ( usize , K , V ) >
226
+ where
227
+ Q : ?Sized + Equivalent < K > ,
228
+ {
229
+ let eq = equivalent ( key, & self . entries ) ;
230
+ match self . indices . remove_entry ( hash. get ( ) , eq) {
231
+ Some ( index) => {
232
+ let ( key, value) = self . shift_remove_finish ( index) ;
233
+ Some ( ( index, key, value) )
234
+ }
235
+ None => None ,
236
+ }
237
+ }
238
+
239
+ /// Remove an entry by shifting all entries that follow it
240
+ pub ( crate ) fn shift_remove_index ( & mut self , index : usize ) -> Option < ( K , V ) > {
241
+ match self . entries . get ( index) {
242
+ Some ( entry) => {
243
+ erase_index ( & mut self . indices , entry. hash , index) ;
244
+ Some ( self . shift_remove_finish ( index) )
245
+ }
246
+ None => None ,
247
+ }
248
+ }
249
+
250
+ /// Remove an entry by shifting all entries that follow it
251
+ ///
252
+ /// The index should already be removed from `self.indices`.
253
+ fn shift_remove_finish ( & mut self , index : usize ) -> ( K , V ) {
254
+ // use Vec::remove, but then we need to update the indices that point
255
+ // to all of the other entries that have to move
256
+ let entry = self . entries . remove ( index) ;
257
+
258
+ // correct indices that point to the entries that followed the removed entry.
259
+ // use a heuristic between a full sweep vs. a `find()` for every shifted item.
260
+ let raw_capacity = self . indices . buckets ( ) ;
261
+ let shifted_entries = & self . entries [ index..] ;
262
+ if shifted_entries. len ( ) > raw_capacity / 2 {
263
+ // shift all indices greater than `index`
264
+ for i in self . indices_mut ( ) {
265
+ if * i > index {
266
+ * i -= 1 ;
267
+ }
268
+ }
269
+ } else {
270
+ // find each following entry to shift its index
271
+ for ( i, entry) in ( index + 1 ..) . zip ( shifted_entries) {
272
+ update_index ( & mut self . indices , entry. hash , i, i - 1 ) ;
273
+ }
274
+ }
275
+
276
+ ( entry. key , entry. value )
277
+ }
278
+
279
+ /// Remove an entry by swapping it with the last
280
+ pub ( crate ) fn swap_remove_full < Q > ( & mut self , hash : HashValue , key : & Q ) -> Option < ( usize , K , V ) >
281
+ where
282
+ Q : ?Sized + Equivalent < K > ,
283
+ {
284
+ let eq = equivalent ( key, & self . entries ) ;
285
+ match self . indices . remove_entry ( hash. get ( ) , eq) {
286
+ Some ( index) => {
287
+ let ( key, value) = self . swap_remove_finish ( index) ;
288
+ Some ( ( index, key, value) )
289
+ }
290
+ None => None ,
291
+ }
292
+ }
293
+
294
+ /// Remove an entry by swapping it with the last
295
+ pub ( crate ) fn swap_remove_index ( & mut self , index : usize ) -> Option < ( K , V ) > {
296
+ match self . entries . get ( index) {
297
+ Some ( entry) => {
298
+ erase_index ( & mut self . indices , entry. hash , index) ;
299
+ Some ( self . swap_remove_finish ( index) )
300
+ }
301
+ None => None ,
302
+ }
303
+ }
304
+
305
+ /// Finish removing an entry by swapping it with the last
306
+ ///
307
+ /// The index should already be removed from `self.indices`.
308
+ fn swap_remove_finish ( & mut self , index : usize ) -> ( K , V ) {
309
+ // use swap_remove, but then we need to update the index that points
310
+ // to the other entry that has to move
311
+ let entry = self . entries . swap_remove ( index) ;
312
+
313
+ // correct index that points to the entry that had to swap places
314
+ if let Some ( entry) = self . entries . get ( index) {
315
+ // was not last element
316
+ // examine new element in `index` and find it in indices
317
+ let last = self . entries . len ( ) ;
318
+ update_index ( & mut self . indices , entry. hash , last, index) ;
319
+ }
320
+
321
+ ( entry. key , entry. value )
322
+ }
323
+
324
+ /// Erase `start..end` from `indices`, and shift `end..` indices down to `start..`
325
+ ///
326
+ /// All of these items should still be at their original location in `entries`.
327
+ /// This is used by `drain`, which will let `Vec::drain` do the work on `entries`.
328
+ fn erase_indices ( & mut self , start : usize , end : usize ) {
329
+ let ( init, shifted_entries) = self . entries . split_at ( end) ;
330
+ let ( start_entries, erased_entries) = init. split_at ( start) ;
331
+
332
+ let erased = erased_entries. len ( ) ;
333
+ let shifted = shifted_entries. len ( ) ;
334
+ let half_capacity = self . indices . buckets ( ) / 2 ;
335
+
336
+ // Use a heuristic between different strategies
337
+ if erased == 0 {
338
+ // Degenerate case, nothing to do
339
+ } else if start + shifted < half_capacity && start < erased {
340
+ // Reinsert everything, as there are few kept indices
341
+ self . indices . clear ( ) ;
342
+
343
+ // Reinsert stable indices
344
+ for ( i, entry) in enumerate ( start_entries) {
345
+ self . indices . insert_no_grow ( entry. hash . get ( ) , i) ;
346
+ }
347
+
348
+ // Reinsert shifted indices
349
+ for ( i, entry) in ( start..) . zip ( shifted_entries) {
350
+ self . indices . insert_no_grow ( entry. hash . get ( ) , i) ;
351
+ }
352
+ } else if erased + shifted < half_capacity {
353
+ // Find each affected index, as there are few to adjust
354
+
355
+ // Find erased indices
356
+ for ( i, entry) in ( start..) . zip ( erased_entries) {
357
+ erase_index ( & mut self . indices , entry. hash , i) ;
358
+ }
359
+
360
+ // Find shifted indices
361
+ for ( ( new, old) , entry) in ( start..) . zip ( end..) . zip ( shifted_entries) {
362
+ update_index ( & mut self . indices , entry. hash , old, new) ;
363
+ }
364
+ } else {
365
+ // Sweep the whole table for adjustments
366
+ self . erase_indices_sweep ( start, end) ;
367
+ }
368
+
369
+ debug_assert_eq ! ( self . indices. len( ) , start + shifted) ;
370
+ }
371
+
194
372
pub ( crate ) fn retain_in_order < F > ( & mut self , mut keep : F )
195
373
where
196
374
F : FnMut ( & mut K , & mut V ) -> bool ,
@@ -225,6 +403,17 @@ impl<K, V> IndexMapCore<K, V> {
225
403
self . indices . insert_no_grow ( entry. hash . get ( ) , i) ;
226
404
}
227
405
}
406
+
407
+ pub ( crate ) fn reverse ( & mut self ) {
408
+ self . entries . reverse ( ) ;
409
+
410
+ // No need to save hash indices, can easily calculate what they should
411
+ // be, given that this is an in-place reversal.
412
+ let len = self . entries . len ( ) ;
413
+ for i in self . indices_mut ( ) {
414
+ * i = len - * i - 1 ;
415
+ }
416
+ }
228
417
}
229
418
230
419
/// Entry for an existing key-value pair or a vacant location to
0 commit comments