Skip to content

Commit eae9abf

Browse files
authored
Merge pull request #99 from cuviper/remove
Expand removal options
2 parents 5063c68 + d18bdf9 commit eae9abf

File tree

5 files changed

+278
-17
lines changed

5 files changed

+278
-17
lines changed

benches/bench.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ fn ordermap_merge_shuffle(b: &mut Bencher) {
574574
}
575575

576576
#[bench]
577-
fn remove_ordermap_100_000(b: &mut Bencher) {
577+
fn swap_remove_ordermap_100_000(b: &mut Bencher) {
578578
let map = OMAP_100K.clone();
579579
let mut keys = Vec::from_iter(map.keys().cloned());
580580
let mut rng = SmallRng::from_entropy();
@@ -583,7 +583,45 @@ fn remove_ordermap_100_000(b: &mut Bencher) {
583583
b.iter(|| {
584584
let mut map = map.clone();
585585
for key in &keys {
586-
map.remove(key);
586+
map.swap_remove(key);
587+
}
588+
assert_eq!(map.len(), 0);
589+
map
590+
});
591+
}
592+
593+
#[bench]
594+
fn shift_remove_ordermap_100_000_few(b: &mut Bencher) {
595+
let map = OMAP_100K.clone();
596+
let mut keys = Vec::from_iter(map.keys().cloned());
597+
let mut rng = SmallRng::from_entropy();
598+
keys.shuffle(&mut rng);
599+
keys.truncate(50);
600+
601+
b.iter(|| {
602+
let mut map = map.clone();
603+
for key in &keys {
604+
map.shift_remove(key);
605+
}
606+
assert_eq!(map.len(), OMAP_100K.len() - keys.len());
607+
map
608+
});
609+
}
610+
611+
#[bench]
612+
fn shift_remove_ordermap_2_000_full(b: &mut Bencher) {
613+
let mut keys = KEYS[..2_000].to_vec();
614+
let mut map = IndexMap::with_capacity(keys.len());
615+
for &key in &keys {
616+
map.insert(key, key);
617+
}
618+
let mut rng = SmallRng::from_entropy();
619+
keys.shuffle(&mut rng);
620+
621+
b.iter(|| {
622+
let mut map = map.clone();
623+
for key in &keys {
624+
map.shift_remove(key);
587625
}
588626
assert_eq!(map.len(), 0);
589627
map

src/map.rs

Lines changed: 171 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -664,13 +664,59 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
664664
replace(self.get_mut(), value)
665665
}
666666

667+
#[deprecated(note = "use `swap_remove` or `shift_remove`")]
667668
pub fn remove(self) -> V {
668-
self.remove_entry().1
669+
self.swap_remove()
670+
}
671+
672+
/// Remove the key, value pair stored in the map for this entry, and return the value.
673+
///
674+
/// Like `Vec::swap_remove`, the pair is removed by swapping it with the
675+
/// last element of the map and popping it off. **This perturbs
676+
/// the postion of what used to be the last element!**
677+
///
678+
/// Computes in **O(1)** time (average).
679+
pub fn swap_remove(self) -> V {
680+
self.swap_remove_entry().1
681+
}
682+
683+
/// Remove the key, value pair stored in the map for this entry, and return the value.
684+
///
685+
/// Like `Vec::remove`, the pair is removed by shifting all of the
686+
/// elements that follow it, preserving their relative order.
687+
/// **This perturbs the index of all of those elements!**
688+
///
689+
/// Computes in **O(n)** time (average).
690+
pub fn shift_remove(self) -> V {
691+
self.shift_remove_entry().1
669692
}
670693

671694
/// Remove and return the key, value pair stored in the map for this entry
695+
#[deprecated(note = "use `swap_remove_entry` or `shift_remove_entry`")]
672696
pub fn remove_entry(self) -> (K, V) {
673-
self.map.remove_found(self.probe, self.index)
697+
self.swap_remove_entry()
698+
}
699+
700+
/// Remove and return the key, value pair stored in the map for this entry
701+
///
702+
/// Like `Vec::swap_remove`, the pair is removed by swapping it with the
703+
/// last element of the map and popping it off. **This perturbs
704+
/// the postion of what used to be the last element!**
705+
///
706+
/// Computes in **O(1)** time (average).
707+
pub fn swap_remove_entry(self) -> (K, V) {
708+
self.map.swap_remove_found(self.probe, self.index)
709+
}
710+
711+
/// Remove and return the key, value pair stored in the map for this entry
712+
///
713+
/// Like `Vec::remove`, the pair is removed by shifting all of the
714+
/// elements that follow it, preserving their relative order.
715+
/// **This perturbs the index of all of those elements!**
716+
///
717+
/// Computes in **O(n)** time (average).
718+
pub fn shift_remove_entry(self) -> (K, V) {
719+
self.map.shift_remove_found(self.probe, self.index)
674720
}
675721
}
676722

@@ -955,6 +1001,7 @@ impl<K, V, S> IndexMap<K, V, S>
9551001
/// NOTE: Same as .swap_remove
9561002
///
9571003
/// Computes in **O(1)** time (average).
1004+
#[deprecated(note = "use `swap_remove`")]
9581005
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
9591006
where Q: Hash + Equivalent<K>,
9601007
{
@@ -985,14 +1032,53 @@ impl<K, V, S> IndexMap<K, V, S>
9851032
/// the postion of what used to be the last element!**
9861033
///
9871034
/// Return `None` if `key` is not in map.
1035+
///
1036+
/// Computes in **O(1)** time (average).
9881037
pub fn swap_remove_full<Q: ?Sized>(&mut self, key: &Q) -> Option<(usize, K, V)>
9891038
where Q: Hash + Equivalent<K>,
9901039
{
9911040
let (probe, found) = match self.find(key) {
9921041
None => return None,
9931042
Some(t) => t,
9941043
};
995-
let (k, v) = self.core.remove_found(probe, found);
1044+
let (k, v) = self.core.swap_remove_found(probe, found);
1045+
Some((found, k, v))
1046+
}
1047+
1048+
/// Remove the key-value pair equivalent to `key` and return
1049+
/// its value.
1050+
///
1051+
/// Like `Vec::remove`, the pair is removed by shifting all of the
1052+
/// elements that follow it, preserving their relative order.
1053+
/// **This perturbs the index of all of those elements!**
1054+
///
1055+
/// Return `None` if `key` is not in map.
1056+
///
1057+
/// Computes in **O(n)** time (average).
1058+
pub fn shift_remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
1059+
where Q: Hash + Equivalent<K>,
1060+
{
1061+
self.shift_remove_full(key).map(third)
1062+
}
1063+
1064+
/// Remove the key-value pair equivalent to `key` and return it and
1065+
/// the index it had.
1066+
///
1067+
/// Like `Vec::remove`, the pair is removed by shifting all of the
1068+
/// elements that follow it, preserving their relative order.
1069+
/// **This perturbs the index of all of those elements!**
1070+
///
1071+
/// Return `None` if `key` is not in map.
1072+
///
1073+
/// Computes in **O(n)** time (average).
1074+
pub fn shift_remove_full<Q: ?Sized>(&mut self, key: &Q) -> Option<(usize, K, V)>
1075+
where Q: Hash + Equivalent<K>,
1076+
{
1077+
let (probe, found) = match self.find(key) {
1078+
None => return None,
1079+
Some(t) => t,
1080+
};
1081+
let (k, v) = self.core.shift_remove_found(probe, found);
9961082
Some((found, k, v))
9971083
}
9981084

@@ -1103,6 +1189,10 @@ impl<K, V, S> IndexMap<K, V, S> {
11031189
///
11041190
/// Valid indices are *0 <= index < self.len()*
11051191
///
1192+
/// Like `Vec::swap_remove`, the pair is removed by swapping it with the
1193+
/// last element of the map and popping it off. **This perturbs
1194+
/// the postion of what used to be the last element!**
1195+
///
11061196
/// Computes in **O(1)** time (average).
11071197
pub fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> {
11081198
let (probe, found) = match self.core.entries.get(index)
@@ -1111,7 +1201,26 @@ impl<K, V, S> IndexMap<K, V, S> {
11111201
None => return None,
11121202
Some(t) => t,
11131203
};
1114-
Some(self.core.remove_found(probe, found))
1204+
Some(self.core.swap_remove_found(probe, found))
1205+
}
1206+
1207+
/// Remove the key-value pair by index
1208+
///
1209+
/// Valid indices are *0 <= index < self.len()*
1210+
///
1211+
/// Like `Vec::remove`, the pair is removed by shifting all of the
1212+
/// elements that follow it, preserving their relative order.
1213+
/// **This perturbs the index of all of those elements!**
1214+
///
1215+
/// Computes in **O(n)** time (average).
1216+
pub fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> {
1217+
let (probe, found) = match self.core.entries.get(index)
1218+
.map(|e| self.core.find_existing_entry(e))
1219+
{
1220+
None => return None,
1221+
Some(t) => t,
1222+
};
1223+
Some(self.core.shift_remove_found(probe, found))
11151224
}
11161225
}
11171226

@@ -1225,7 +1334,7 @@ impl<K, V> OrderMapCore<K, V> {
12251334
Some(t) => t,
12261335
};
12271336
debug_assert_eq!(found, self.entries.len() - 1);
1228-
Some(self.remove_found(probe, found))
1337+
Some(self.swap_remove_found(probe, found))
12291338
}
12301339

12311340
// FIXME: reduce duplication (compare with insert)
@@ -1375,11 +1484,61 @@ impl<K, V> OrderMapCore<K, V> {
13751484
(probe, actual_pos)
13761485
}
13771486

1378-
fn remove_found(&mut self, probe: usize, found: usize) -> (K, V) {
1379-
dispatch_32_vs_64!(self.remove_found_impl(probe, found))
1487+
/// Remove an entry by shifting all entries that follow it
1488+
fn shift_remove_found(&mut self, probe: usize, found: usize) -> (K, V) {
1489+
dispatch_32_vs_64!(self.shift_remove_found_impl(probe, found))
1490+
}
1491+
1492+
fn shift_remove_found_impl<Sz>(&mut self, probe: usize, found: usize) -> (K, V)
1493+
where Sz: Size
1494+
{
1495+
// index `probe` and entry `found` is to be removed
1496+
// use Vec::remove, but then we need to update the indices that point
1497+
// to all of the other entries that have to move
1498+
self.indices[probe] = Pos::none();
1499+
let entry = self.entries.remove(found);
1500+
1501+
// correct indices that point to the entries that followed the removed entry.
1502+
// use a heuristic between a full sweep vs. a `probe_loop!` for every shifted item.
1503+
if self.indices.len() < (self.entries.len() - found) * 2 {
1504+
// shift all indices greater than `found`
1505+
for pos in self.indices.iter_mut() {
1506+
if let Some((i, _)) = pos.resolve::<Sz>() {
1507+
if i > found {
1508+
// shift the index
1509+
pos.set_pos::<Sz>(i - 1);
1510+
}
1511+
}
1512+
}
1513+
} else {
1514+
// find each following entry to shift its index
1515+
for (offset, entry) in enumerate(&self.entries[found..]) {
1516+
let index = found + offset;
1517+
let mut probe = desired_pos(self.mask, entry.hash);
1518+
probe_loop!(probe < self.indices.len(), {
1519+
let pos = &mut self.indices[probe];
1520+
if let Some((i, _)) = pos.resolve::<Sz>() {
1521+
if i == index + 1 {
1522+
// found it, shift it
1523+
pos.set_pos::<Sz>(index);
1524+
break;
1525+
}
1526+
}
1527+
});
1528+
}
1529+
}
1530+
1531+
self.backward_shift_after_removal::<Sz>(probe);
1532+
1533+
(entry.key, entry.value)
1534+
}
1535+
1536+
/// Remove an entry by swapping it with the last
1537+
fn swap_remove_found(&mut self, probe: usize, found: usize) -> (K, V) {
1538+
dispatch_32_vs_64!(self.swap_remove_found_impl(probe, found))
13801539
}
13811540

1382-
fn remove_found_impl<Sz>(&mut self, probe: usize, found: usize) -> (K, V)
1541+
fn swap_remove_found_impl<Sz>(&mut self, probe: usize, found: usize) -> (K, V)
13831542
where Sz: Size
13841543
{
13851544
// index `probe` and entry `found` is to be removed
@@ -1394,10 +1553,11 @@ impl<K, V> OrderMapCore<K, V> {
13941553
// examine new element in `found` and find it in indices
13951554
let mut probe = desired_pos(self.mask, entry.hash);
13961555
probe_loop!(probe < self.indices.len(), {
1397-
if let Some((i, _)) = self.indices[probe].resolve::<Sz>() {
1556+
let pos = &mut self.indices[probe];
1557+
if let Some((i, _)) = pos.resolve::<Sz>() {
13981558
if i >= self.entries.len() {
13991559
// found it
1400-
self.indices[probe] = Pos::with_hash::<Sz>(found, entry.hash);
1560+
pos.set_pos::<Sz>(found);
14011561
break;
14021562
}
14031563
}
@@ -2151,7 +2311,7 @@ mod tests {
21512311
map_a.insert(2, "2");
21522312
let mut map_b = map_a.clone();
21532313
assert_eq!(map_a, map_b);
2154-
map_b.remove(&1);
2314+
map_b.swap_remove(&1);
21552315
assert_ne!(map_a, map_b);
21562316

21572317
let map_c: IndexMap<_, String> = map_b.into_iter().map(|(k, v)| (k, v.to_owned())).collect();

0 commit comments

Comments
 (0)