diff --git a/src/map.rs b/src/map.rs index 283970d2..d8741f1d 100644 --- a/src/map.rs +++ b/src/map.rs @@ -445,12 +445,52 @@ where } } + /// Insert a key-value pair in the map before the entry at the given index, or at the end. + /// + /// If an equivalent key already exists in the map: the key remains and + /// is moved to the new position in the map, its corresponding value is updated + /// with `value`, and the older value is returned inside `Some(_)`. The returned index + /// will either be the given index or one less, depending on how the entry moved. + /// (See [`shift_insert`](Self::shift_insert) for different behavior here.) + /// + /// If no equivalent key existed in the map: the new key-value pair is + /// inserted exactly at the given index, and `None` is returned. + /// + /// ***Panics*** if `index` is out of bounds. + /// Valid indices are `0..=map.len()` (inclusive). + /// + /// Computes in **O(n)** time (average). + /// + /// See also [`entry`][Self::entry] if you want to insert *or* modify, + /// perhaps only using the index for new entries with [`VacantEntry::shift_insert`]. + pub fn insert_before(&mut self, mut index: usize, key: K, value: V) -> (usize, Option) { + assert!(index <= self.len(), "index out of bounds"); + match self.entry(key) { + Entry::Occupied(mut entry) => { + if index > entry.index() { + // Some entries will shift down when this one moves up, + // so "insert before index" becomes "move to index - 1", + // keeping the entry at the original index unmoved. + index -= 1; + } + let old = mem::replace(entry.get_mut(), value); + entry.move_index(index); + (index, Some(old)) + } + Entry::Vacant(entry) => { + entry.shift_insert(index, value); + (index, None) + } + } + } + /// Insert a key-value pair in the map at the given index. /// /// If an equivalent key already exists in the map: the key remains and /// is moved to the given index in the map, its corresponding value is updated /// with `value`, and the older value is returned inside `Some(_)`. /// Note that existing entries **cannot** be moved to `index == map.len()`! + /// (See [`insert_before`](Self::insert_before) for different behavior here.) /// /// If no equivalent key existed in the map: the new key-value pair is /// inserted at the given index, and `None` is returned. diff --git a/src/set.rs b/src/set.rs index 1f5f84f9..b1603047 100644 --- a/src/set.rs +++ b/src/set.rs @@ -383,11 +383,30 @@ where (index, existing.is_none()) } + /// Insert the value into the set before the value at the given index, or at the end. + /// + /// If an equivalent item already exists in the set, it returns `false` leaving the + /// original value in the set, but moved to the new position. The returned index + /// will either be the given index or one less, depending on how the value moved. + /// (See [`shift_insert`](Self::shift_insert) for different behavior here.) + /// + /// Otherwise, it inserts the new value exactly at the given index and returns `true`. + /// + /// ***Panics*** if `index` is out of bounds. + /// Valid indices are `0..=set.len()` (inclusive). + /// + /// Computes in **O(n)** time (average). + pub fn insert_before(&mut self, index: usize, value: T) -> (usize, bool) { + let (index, existing) = self.map.insert_before(index, value, ()); + (index, existing.is_none()) + } + /// Insert the value into the set at the given index. /// /// If an equivalent item already exists in the set, it returns `false` leaving /// the original value in the set, but moved to the given index. /// Note that existing values **cannot** be moved to `index == set.len()`! + /// (See [`insert_before`](Self::insert_before) for different behavior here.) /// /// Otherwise, it inserts the new value at the given index and returns `true`. ///