@@ -477,37 +477,35 @@ where
477
477
}
478
478
}
479
479
480
+ /// Return the values for `N` keys. If any key is missing a value, or there
481
+ /// are duplicate keys, `None` is returned.
482
+ ///
483
+ /// # Examples
484
+ ///
485
+ /// ```
486
+ /// let mut map = indexmap::IndexMap::from([(1, 'a'), (3, 'b'), (2, 'c')]);
487
+ /// assert_eq!(map.get_many_mut([&2, &1]), Some([&mut 'c', &mut 'a']));
488
+ /// ```
480
489
pub fn get_many_mut < ' a , ' b , Q : ?Sized , const N : usize > (
481
490
& ' a mut self ,
482
491
keys : [ & ' b Q ; N ] ,
483
492
) -> Option < [ & ' a mut V ; N ] >
484
493
where
485
494
Q : Hash + Equivalent < K > ,
486
495
{
496
+ let len = self . len ( ) ;
487
497
let indices = keys. map ( |key| self . get_index_of ( key) ) ;
488
- if indices. iter ( ) . any ( Option :: is_none) {
489
- return None ;
490
- }
491
- let indices = indices. map ( Option :: unwrap) ;
492
498
493
- // SAFETY: Can't allow duplicate indices as we would return several mutable refs to the same data
494
- for i in 0 .. N {
495
- let idx = indices [ i ] ;
496
- if indices [ i + 1 .. N ] . contains ( & idx ) {
497
- return None ;
499
+ // Handle out-of-bounds indices with panic as this is an internal error in get_index_of.
500
+ for idx in indices {
501
+ let idx = idx? ;
502
+ if idx >= len {
503
+ panic ! ( "Index is out of range! Got '{idx}' but length is '{len}'" )
498
504
}
499
505
}
500
-
501
- let entries = self . as_entries_mut ( ) ;
502
- let out = indices. map ( |i| {
503
- // SAFETY: OK to discard mutable borrow lifetime as each index is unique
504
- #[ allow( unsafe_code) ]
505
- unsafe {
506
- & mut * ( & mut entries[ i] . value as * mut V )
507
- }
508
- } ) ;
509
-
510
- Some ( out)
506
+ let indices = indices. map ( Option :: unwrap) ;
507
+ let entries = self . get_many_index_mut ( indices) ?;
508
+ Some ( entries. map ( |( _key, value) | value) )
511
509
}
512
510
513
511
/// Remove the key-value pair equivalent to `key` and return
@@ -817,6 +815,45 @@ impl<K, V, S> IndexMap<K, V, S> {
817
815
self . as_entries_mut ( ) . get_mut ( index) . map ( Bucket :: ref_mut)
818
816
}
819
817
818
+ /// Get an array of `N` key-value pairs by `N` indices
819
+ ///
820
+ /// Valid indices are *0 <= index < self.len()* and each index needs to be unique.
821
+ ///
822
+ /// Computes in **O(1)** time.
823
+ ///
824
+ /// # Examples
825
+ ///
826
+ /// ```
827
+ /// let mut map = indexmap::IndexMap::from([(1, 'a'), (3, 'b'), (2, 'c')]);
828
+ /// assert_eq!(map.get_many_index_mut([2, 0]), Some([(&2, &mut 'c'), (&1, &mut 'a')]));
829
+ /// ```
830
+ pub fn get_many_index_mut < const N : usize > (
831
+ & mut self ,
832
+ indices : [ usize ; N ] ,
833
+ ) -> Option < [ ( & K , & mut V ) ; N ] > {
834
+ // SAFETY: Can't allow duplicate indices as we would return several mutable refs to the same data.
835
+ // Additionally, handle out-of-bounds indices (internal error in get_index_of) with panic.
836
+ let len = self . len ( ) ;
837
+ for i in 0 ..N {
838
+ let idx = indices[ i] ;
839
+ if idx >= len || indices[ i + 1 ..N ] . contains ( & idx) {
840
+ return None ;
841
+ }
842
+ }
843
+
844
+ let entries_ptr = self . as_entries_mut ( ) . as_mut_ptr ( ) ;
845
+ let out = indices. map ( |i| {
846
+ // SAFETY: The base pointer is valid as it comes from a slice and the deref is always
847
+ // in-bounds as we've already checked the indices above.
848
+ #[ allow( unsafe_code) ]
849
+ unsafe {
850
+ ( * ( entries_ptr. add ( i) ) ) . ref_mut ( )
851
+ }
852
+ } ) ;
853
+
854
+ Some ( out)
855
+ }
856
+
820
857
/// Returns a slice of key-value pairs in the given range of indices.
821
858
///
822
859
/// Valid indices are *0 <= index < self.len()*
0 commit comments