Skip to content

Commit 1d7b8e2

Browse files
committed
Add insert_sorted
1 parent e0a7f23 commit 1d7b8e2

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

src/map.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,35 @@ where
414414
self.core.insert_full(hash, key, value)
415415
}
416416

417+
/// Insert a key-value pair in the map at its ordered position among sorted keys.
418+
///
419+
/// This is equivalent to finding the position with
420+
/// [`binary_search_keys`][Self::binary_search_keys], then either updating
421+
/// it or calling [`shift_insert`][Self::shift_insert] for a new key.
422+
///
423+
/// If the sorted key is found in the map, its corresponding value is
424+
/// updated with `value`, and the older value is returned inside
425+
/// `(index, Some(_))`. Otherwise, the new key-value pair is inserted at
426+
/// the sorted position, and `(index, None)` is returned.
427+
///
428+
/// If the existing keys are **not** already sorted, then the insertion
429+
/// index is unspecified (like [`slice::binary_search`]), but the key-value
430+
/// pair is moved to or inserted at that position regardless.
431+
///
432+
/// Computes in **O(n)** time (average). Instead of repeating calls to
433+
/// `insert_sorted`, it may be faster to call batched [`insert`][Self::insert]
434+
/// or [`extend`][Self::extend] and only call [`sort_keys`][Self::sort_keys]
435+
/// or [`sort_unstable_keys`][Self::sort_unstable_keys] once.
436+
pub fn insert_sorted(&mut self, key: K, value: V) -> (usize, Option<V>)
437+
where
438+
K: Ord,
439+
{
440+
match self.binary_search_keys(&key) {
441+
Ok(i) => (i, Some(mem::replace(&mut self[i], value))),
442+
Err(i) => (i, self.shift_insert(i, key, value)),
443+
}
444+
}
445+
417446
/// Insert a key-value pair in the map at the given index.
418447
///
419448
/// If an equivalent key already exists in the map: the key remains and
@@ -788,6 +817,10 @@ impl<K, V, S> IndexMap<K, V, S> {
788817

789818
/// Sort the map’s key-value pairs by the default ordering of the keys.
790819
///
820+
/// This is a stable sort -- but equivalent keys should not normally coexist in
821+
/// a map at all, so [`sort_unstable_keys`][Self::sort_unstable_keys] is preferred
822+
/// because it is generally faster and doesn't allocate auxiliary memory.
823+
///
791824
/// See [`sort_by`](Self::sort_by) for details.
792825
pub fn sort_keys(&mut self)
793826
where

src/map/core/entry.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,24 @@ impl<'a, K, V> VacantEntry<'a, K, V> {
310310
&mut map.entries[i].value
311311
}
312312

313+
/// Inserts the entry's key and the given value into the map at its ordered
314+
/// position among sorted keys, and returns the new index and a mutable
315+
/// reference to the value.
316+
///
317+
/// If the existing keys are **not** already sorted, then the insertion
318+
/// index is unspecified (like [`slice::binary_search`]), but the key-value
319+
/// pair is inserted at that position regardless.
320+
///
321+
/// Computes in **O(n)** time (average).
322+
pub fn insert_sorted(self, value: V) -> (usize, &'a mut V)
323+
where
324+
K: Ord,
325+
{
326+
let slice = crate::map::Slice::from_slice(&self.map.entries);
327+
let i = slice.binary_search_keys(&self.key).unwrap_err();
328+
(i, self.shift_insert(i, value))
329+
}
330+
313331
/// Inserts the entry's key and the given value into the map at the given index,
314332
/// shifting others to the right, and returns a mutable reference to the value.
315333
///

src/set.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,32 @@ where
355355
(index, existing.is_none())
356356
}
357357

358+
/// Insert the value into the set at its ordered position among sorted values.
359+
///
360+
/// This is equivalent to finding the position with
361+
/// [`binary_search`][Self::binary_search], and if needed calling
362+
/// [`shift_insert`][Self::shift_insert] for a new value.
363+
///
364+
/// If the sorted item is found in the set, it returns the index of that
365+
/// existing item and `false`, without any change. Otherwise, it inserts the
366+
/// new item and returns its sorted index and `true`.
367+
///
368+
/// If the existing items are **not** already sorted, then the insertion
369+
/// index is unspecified (like [`slice::binary_search`]), but the value
370+
/// is moved to or inserted at that position regardless.
371+
///
372+
/// Computes in **O(n)** time (average). Instead of repeating calls to
373+
/// `insert_sorted`, it may be faster to call batched [`insert`][Self::insert]
374+
/// or [`extend`][Self::extend] and only call [`sort`][Self::sort] or
375+
/// [`sort_unstable`][Self::sort_unstable] once.
376+
pub fn insert_sorted(&mut self, value: T) -> (usize, bool)
377+
where
378+
T: Ord,
379+
{
380+
let (index, existing) = self.map.insert_sorted(value, ());
381+
(index, existing.is_none())
382+
}
383+
358384
/// Insert the value into the set at the given index.
359385
///
360386
/// If an equivalent item already exists in the set, it returns
@@ -670,6 +696,10 @@ impl<T, S> IndexSet<T, S> {
670696

671697
/// Sort the set’s values by their default ordering.
672698
///
699+
/// This is a stable sort -- but equivalent values should not normally coexist in
700+
/// a set at all, so [`sort_unstable`][Self::sort_unstable] is preferred
701+
/// because it is generally faster and doesn't allocate auxiliary memory.
702+
///
673703
/// See [`sort_by`](Self::sort_by) for details.
674704
pub fn sort(&mut self)
675705
where

tests/quick.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,23 @@ quickcheck_limit! {
113113
true
114114
}
115115

116+
fn insert_sorted(insert: Vec<(u32, u32)>) -> bool {
117+
let mut hmap = HashMap::new();
118+
let mut map = IndexMap::new();
119+
let mut map2 = IndexMap::new();
120+
for &(key, value) in &insert {
121+
hmap.insert(key, value);
122+
map.insert_sorted(key, value);
123+
match map2.entry(key) {
124+
Entry::Occupied(e) => *e.into_mut() = value,
125+
Entry::Vacant(e) => { e.insert_sorted(value); }
126+
}
127+
}
128+
itertools::assert_equal(hmap.iter().sorted(), &map);
129+
itertools::assert_equal(&map, &map2);
130+
true
131+
}
132+
116133
fn pop(insert: Vec<u8>) -> bool {
117134
let mut map = IndexMap::new();
118135
for &key in &insert {

0 commit comments

Comments
 (0)