@@ -34,6 +34,27 @@ fn get_hash<K, V>(entries: &[Bucket<K, V>]) -> impl Fn(&usize) -> u64 + '_ {
3434 move |& i| entries[ i] . hash . get ( )
3535}
3636
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+
3758impl < K , V > Clone for IndexMapCore < K , V >
3859where
3960 K : Clone ,
@@ -160,7 +181,7 @@ impl<K, V> IndexMapCore<K, V> {
160181 pub ( crate ) fn pop ( & mut self ) -> Option < ( K , V ) > {
161182 if let Some ( entry) = self . entries . pop ( ) {
162183 let last = self . entries . len ( ) ;
163- self . erase_index ( entry. hash , last) ;
184+ erase_index ( & mut self . indices , entry. hash , last) ;
164185 Some ( ( entry. key , entry. value ) )
165186 } else {
166187 None
@@ -181,6 +202,15 @@ impl<K, V> IndexMapCore<K, V> {
181202 i
182203 }
183204
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+
184214 pub ( crate ) fn insert_full ( & mut self , hash : HashValue , key : K , value : V ) -> ( usize , Option < V > )
185215 where
186216 K : Eq ,
@@ -191,6 +221,154 @@ impl<K, V> IndexMapCore<K, V> {
191221 }
192222 }
193223
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+
194372 pub ( crate ) fn retain_in_order < F > ( & mut self , mut keep : F )
195373 where
196374 F : FnMut ( & mut K , & mut V ) -> bool ,
@@ -225,6 +403,17 @@ impl<K, V> IndexMapCore<K, V> {
225403 self . indices . insert_no_grow ( entry. hash . get ( ) , i) ;
226404 }
227405 }
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+ }
228417}
229418
230419/// Entry for an existing key-value pair or a vacant location to
0 commit comments