@@ -283,29 +283,77 @@ impl<K, V> IndexMapCore<K, V> {
283
283
///
284
284
/// The index should already be removed from `self.indices`.
285
285
fn shift_remove_finish ( & mut self , index : usize ) -> ( K , V ) {
286
- // use Vec::remove, but then we need to update the indices that point
287
- // to all of the other entries that have to move
286
+ // Correct indices that point to the entries that followed the removed entry.
287
+ self . decrement_indices ( index + 1 , self . entries . len ( ) ) ;
288
+
289
+ // Use Vec::remove to actually remove the entry.
288
290
let entry = self . entries . remove ( index) ;
291
+ ( entry. key , entry. value )
292
+ }
289
293
290
- // correct indices that point to the entries that followed the removed entry.
291
- // use a heuristic between a full sweep vs. a `find()` for every shifted item.
292
- let raw_capacity = self . indices . buckets ( ) ;
293
- let shifted_entries = & self . entries [ index..] ;
294
- if shifted_entries. len ( ) > raw_capacity / 2 {
295
- // shift all indices greater than `index`
294
+ /// Decrement all indices in the range `start..end`.
295
+ ///
296
+ /// The index `start - 1` should not exist in `self.indices`.
297
+ /// All entries should still be in their original positions.
298
+ fn decrement_indices ( & mut self , start : usize , end : usize ) {
299
+ // Use a heuristic between a full sweep vs. a `find()` for every shifted item.
300
+ let shifted_entries = & self . entries [ start..end] ;
301
+ if shifted_entries. len ( ) > self . indices . buckets ( ) / 2 {
302
+ // Shift all indices in range.
296
303
for i in self . indices_mut ( ) {
297
- if * i > index {
304
+ if start <= * i && * i < end {
298
305
* i -= 1 ;
299
306
}
300
307
}
301
308
} else {
302
- // find each following entry to shift its index
303
- for ( i, entry) in ( index + 1 .. ) . zip ( shifted_entries) {
309
+ // Find each entry in range to shift its index.
310
+ for ( i, entry) in ( start..end ) . zip ( shifted_entries) {
304
311
update_index ( & mut self . indices , entry. hash , i, i - 1 ) ;
305
312
}
306
313
}
314
+ }
307
315
308
- ( entry. key , entry. value )
316
+ /// Increment all indices in the range `start..end`.
317
+ ///
318
+ /// The index `end` should not exist in `self.indices`.
319
+ /// All entries should still be in their original positions.
320
+ fn increment_indices ( & mut self , start : usize , end : usize ) {
321
+ // Use a heuristic between a full sweep vs. a `find()` for every shifted item.
322
+ let shifted_entries = & self . entries [ start..end] ;
323
+ if shifted_entries. len ( ) > self . indices . buckets ( ) / 2 {
324
+ // Shift all indices in range.
325
+ for i in self . indices_mut ( ) {
326
+ if start <= * i && * i < end {
327
+ * i += 1 ;
328
+ }
329
+ }
330
+ } else {
331
+ // Find each entry in range to shift its index, updated in reverse so
332
+ // we never have duplicated indices that might have a hash collision.
333
+ for ( i, entry) in ( start..end) . zip ( shifted_entries) . rev ( ) {
334
+ update_index ( & mut self . indices , entry. hash , i, i + 1 ) ;
335
+ }
336
+ }
337
+ }
338
+
339
+ pub ( super ) fn move_index ( & mut self , from : usize , to : usize ) {
340
+ let from_hash = self . entries [ from] . hash ;
341
+ if from != to {
342
+ // Use a sentinal index so other indices don't collide.
343
+ update_index ( & mut self . indices , from_hash, from, usize:: MAX ) ;
344
+
345
+ // Update all other indices and rotate the entry positions.
346
+ if from < to {
347
+ self . decrement_indices ( from + 1 , to + 1 ) ;
348
+ self . entries [ from..=to] . rotate_left ( 1 ) ;
349
+ } else if to < from {
350
+ self . increment_indices ( to, from) ;
351
+ self . entries [ to..=from] . rotate_right ( 1 ) ;
352
+ }
353
+
354
+ // Change the sentinal index to its final position.
355
+ update_index ( & mut self . indices , from_hash, usize:: MAX , to) ;
356
+ }
309
357
}
310
358
311
359
/// Remove an entry by swapping it with the last
0 commit comments