Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add IndexMap::shift_insert based on Entry
  • Loading branch information
cuviper committed Feb 11, 2024
1 parent 209e3e1 commit 3b217ca
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 4 deletions.
38 changes: 34 additions & 4 deletions src/map.rs
Expand Up @@ -26,6 +26,7 @@ pub use crate::rayon::map as rayon;
use ::core::cmp::Ordering;
use ::core::fmt;
use ::core::hash::{BuildHasher, Hash, Hasher};
use ::core::mem;
use ::core::ops::{Index, IndexMut, RangeBounds};
use alloc::boxed::Box;
use alloc::vec::Vec;
Expand Down Expand Up @@ -380,14 +381,14 @@ where
///
/// If an equivalent key already exists in the map: the key remains and
/// retains in its place in the order, its corresponding value is updated
/// with `value` and the older value is returned inside `Some(_)`.
/// with `value`, and the older value is returned inside `Some(_)`.
///
/// If no equivalent key existed in the map: the new key-value pair is
/// inserted, last in order, and `None` is returned.
///
/// Computes in **O(1)** time (amortized average).
///
/// See also [`entry`][Self::entry] if you you want to insert *or* modify,
/// See also [`entry`][Self::entry] if you want to insert *or* modify,
/// or [`insert_full`][Self::insert_full] if you need to get the index of
/// the corresponding key-value pair.
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
Expand All @@ -398,19 +399,48 @@ where
///
/// If an equivalent key already exists in the map: the key remains and
/// retains in its place in the order, its corresponding value is updated
/// with `value` and the older value is returned inside `(index, Some(_))`.
/// with `value`, and the older value is returned inside `(index, Some(_))`.
///
/// If no equivalent key existed in the map: the new key-value pair is
/// inserted, last in order, and `(index, None)` is returned.
///
/// Computes in **O(1)** time (amortized average).
///
/// See also [`entry`][Self::entry] if you you want to insert *or* modify.
/// See also [`entry`][Self::entry] if you want to insert *or* modify.
pub fn insert_full(&mut self, key: K, value: V) -> (usize, Option<V>) {
let hash = self.hash(&key);
self.core.insert_full(hash, key, value)
}

/// 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 new position in the map, its corresponding value is updated
/// with `value`, and the older value is returned inside `Some(_)`.
///
/// If no equivalent key existed in the map: the new key-value pair is
/// inserted at the given index, and `None` is returned.
///
/// ***Panics*** if `index` is out of bounds.
///
/// 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 shift_insert(&mut self, index: usize, key: K, value: V) -> Option<V> {
match self.entry(key) {
Entry::Occupied(mut entry) => {
let old = mem::replace(entry.get_mut(), value);
entry.move_index(index);
Some(old)
}
Entry::Vacant(entry) => {
entry.shift_insert(index, value);
None
}
}
}

/// Get the given key’s corresponding entry in the map for insertion and/or
/// in-place manipulation.
///
Expand Down
19 changes: 19 additions & 0 deletions src/map/tests.rs
Expand Up @@ -108,6 +108,25 @@ fn insert_order() {
}
}

#[test]
fn shift_insert() {
let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23];
let mut map = IndexMap::new();

for &elt in &insert {
map.shift_insert(0, elt, ());
}

assert_eq!(map.keys().count(), map.len());
assert_eq!(map.keys().count(), insert.len());
for (a, b) in insert.iter().rev().zip(map.keys()) {
assert_eq!(a, b);
}
for (i, k) in (0..insert.len()).zip(map.keys()) {
assert_eq!(map.get_index(i).unwrap().0, k);
}
}

#[test]
fn grow() {
let insert = [0, 4, 2, 12, 8, 7, 11];
Expand Down

0 comments on commit 3b217ca

Please sign in to comment.