@@ -420,7 +420,7 @@ where
420
420
///
421
421
/// This is equivalent to finding the position with
422
422
/// [`binary_search_keys`][Self::binary_search_keys], then either updating
423
- /// it or calling [`shift_insert `][Self::shift_insert ] for a new key.
423
+ /// it or calling [`insert_before `][Self::insert_before ] for a new key.
424
424
///
425
425
/// If the sorted key is found in the map, its corresponding value is
426
426
/// updated with `value`, and the older value is returned inside
@@ -441,33 +441,147 @@ where
441
441
{
442
442
match self . binary_search_keys ( & key) {
443
443
Ok ( i) => ( i, Some ( mem:: replace ( & mut self [ i] , value) ) ) ,
444
- Err ( i) => ( i , self . shift_insert ( i, key, value) ) ,
444
+ Err ( i) => self . insert_before ( i, key, value) ,
445
445
}
446
446
}
447
447
448
- /// Insert a key-value pair in the map at the given index.
448
+ /// Insert a key-value pair in the map before the entry at the given index, or at the end .
449
449
///
450
450
/// If an equivalent key already exists in the map: the key remains and
451
451
/// is moved to the new position in the map, its corresponding value is updated
452
+ /// with `value`, and the older value is returned inside `Some(_)`. The returned index
453
+ /// will either be the given index or one less, depending on how the entry moved.
454
+ /// (See [`shift_insert`](Self::shift_insert) for different behavior here.)
455
+ ///
456
+ /// If no equivalent key existed in the map: the new key-value pair is
457
+ /// inserted exactly at the given index, and `None` is returned.
458
+ ///
459
+ /// ***Panics*** if `index` is out of bounds.
460
+ /// Valid indices are `0..=map.len()` (inclusive).
461
+ ///
462
+ /// Computes in **O(n)** time (average).
463
+ ///
464
+ /// See also [`entry`][Self::entry] if you want to insert *or* modify,
465
+ /// perhaps only using the index for new entries with [`VacantEntry::shift_insert`].
466
+ ///
467
+ /// # Examples
468
+ ///
469
+ /// ```
470
+ /// use indexmap::IndexMap;
471
+ /// let mut map: IndexMap<char, ()> = ('a'..='z').map(|c| (c, ())).collect();
472
+ ///
473
+ /// // The new key '*' goes exactly at the given index.
474
+ /// assert_eq!(map.get_index_of(&'*'), None);
475
+ /// assert_eq!(map.insert_before(10, '*', ()), (10, None));
476
+ /// assert_eq!(map.get_index_of(&'*'), Some(10));
477
+ ///
478
+ /// // Moving the key 'a' up will shift others down, so this moves *before* 10 to index 9.
479
+ /// assert_eq!(map.insert_before(10, 'a', ()), (9, Some(())));
480
+ /// assert_eq!(map.get_index_of(&'a'), Some(9));
481
+ /// assert_eq!(map.get_index_of(&'*'), Some(10));
482
+ ///
483
+ /// // Moving the key 'z' down will shift others up, so this moves to exactly 10.
484
+ /// assert_eq!(map.insert_before(10, 'z', ()), (10, Some(())));
485
+ /// assert_eq!(map.get_index_of(&'z'), Some(10));
486
+ /// assert_eq!(map.get_index_of(&'*'), Some(11));
487
+ ///
488
+ /// // Moving or inserting before the endpoint is also valid.
489
+ /// assert_eq!(map.len(), 27);
490
+ /// assert_eq!(map.insert_before(map.len(), '*', ()), (26, Some(())));
491
+ /// assert_eq!(map.get_index_of(&'*'), Some(26));
492
+ /// assert_eq!(map.insert_before(map.len(), '+', ()), (27, None));
493
+ /// assert_eq!(map.get_index_of(&'+'), Some(27));
494
+ /// assert_eq!(map.len(), 28);
495
+ /// ```
496
+ pub fn insert_before ( & mut self , mut index : usize , key : K , value : V ) -> ( usize , Option < V > ) {
497
+ assert ! ( index <= self . len( ) , "index out of bounds" ) ;
498
+ match self . entry ( key) {
499
+ Entry :: Occupied ( mut entry) => {
500
+ if index > entry. index ( ) {
501
+ // Some entries will shift down when this one moves up,
502
+ // so "insert before index" becomes "move to index - 1",
503
+ // keeping the entry at the original index unmoved.
504
+ index -= 1 ;
505
+ }
506
+ let old = mem:: replace ( entry. get_mut ( ) , value) ;
507
+ entry. move_index ( index) ;
508
+ ( index, Some ( old) )
509
+ }
510
+ Entry :: Vacant ( entry) => {
511
+ entry. shift_insert ( index, value) ;
512
+ ( index, None )
513
+ }
514
+ }
515
+ }
516
+
517
+ /// Insert a key-value pair in the map at the given index.
518
+ ///
519
+ /// If an equivalent key already exists in the map: the key remains and
520
+ /// is moved to the given index in the map, its corresponding value is updated
452
521
/// with `value`, and the older value is returned inside `Some(_)`.
522
+ /// Note that existing entries **cannot** be moved to `index == map.len()`!
523
+ /// (See [`insert_before`](Self::insert_before) for different behavior here.)
453
524
///
454
525
/// If no equivalent key existed in the map: the new key-value pair is
455
526
/// inserted at the given index, and `None` is returned.
456
527
///
457
528
/// ***Panics*** if `index` is out of bounds.
529
+ /// Valid indices are `0..map.len()` (exclusive) when moving an existing entry, or
530
+ /// `0..=map.len()` (inclusive) when inserting a new key.
458
531
///
459
532
/// Computes in **O(n)** time (average).
460
533
///
461
534
/// See also [`entry`][Self::entry] if you want to insert *or* modify,
462
535
/// perhaps only using the index for new entries with [`VacantEntry::shift_insert`].
536
+ ///
537
+ /// # Examples
538
+ ///
539
+ /// ```
540
+ /// use indexmap::IndexMap;
541
+ /// let mut map: IndexMap<char, ()> = ('a'..='z').map(|c| (c, ())).collect();
542
+ ///
543
+ /// // The new key '*' goes exactly at the given index.
544
+ /// assert_eq!(map.get_index_of(&'*'), None);
545
+ /// assert_eq!(map.shift_insert(10, '*', ()), None);
546
+ /// assert_eq!(map.get_index_of(&'*'), Some(10));
547
+ ///
548
+ /// // Moving the key 'a' up to 10 will shift others down, including the '*' that was at 10.
549
+ /// assert_eq!(map.shift_insert(10, 'a', ()), Some(()));
550
+ /// assert_eq!(map.get_index_of(&'a'), Some(10));
551
+ /// assert_eq!(map.get_index_of(&'*'), Some(9));
552
+ ///
553
+ /// // Moving the key 'z' down to 9 will shift others up, including the '*' that was at 9.
554
+ /// assert_eq!(map.shift_insert(9, 'z', ()), Some(()));
555
+ /// assert_eq!(map.get_index_of(&'z'), Some(9));
556
+ /// assert_eq!(map.get_index_of(&'*'), Some(10));
557
+ ///
558
+ /// // Existing keys can move to len-1 at most, but new keys can insert at the endpoint.
559
+ /// assert_eq!(map.len(), 27);
560
+ /// assert_eq!(map.shift_insert(map.len() - 1, '*', ()), Some(()));
561
+ /// assert_eq!(map.get_index_of(&'*'), Some(26));
562
+ /// assert_eq!(map.shift_insert(map.len(), '+', ()), None);
563
+ /// assert_eq!(map.get_index_of(&'+'), Some(27));
564
+ /// assert_eq!(map.len(), 28);
565
+ /// ```
566
+ ///
567
+ /// ```should_panic
568
+ /// use indexmap::IndexMap;
569
+ /// let mut map: IndexMap<char, ()> = ('a'..='z').map(|c| (c, ())).collect();
570
+ ///
571
+ /// // This is an invalid index for moving an existing key!
572
+ /// map.shift_insert(map.len(), 'a', ());
573
+ /// ```
463
574
pub fn shift_insert ( & mut self , index : usize , key : K , value : V ) -> Option < V > {
575
+ let len = self . len ( ) ;
464
576
match self . entry ( key) {
465
577
Entry :: Occupied ( mut entry) => {
578
+ assert ! ( index < len, "index out of bounds" ) ;
466
579
let old = mem:: replace ( entry. get_mut ( ) , value) ;
467
580
entry. move_index ( index) ;
468
581
Some ( old)
469
582
}
470
583
Entry :: Vacant ( entry) => {
584
+ assert ! ( index <= len, "index out of bounds" ) ;
471
585
entry. shift_insert ( index, value) ;
472
586
None
473
587
}
0 commit comments