Skip to content

Commit 552cde7

Browse files
committed
BTreeMap: revert a part of rust-lang#78015 and test what it broke
1 parent b9a94c9 commit 552cde7

File tree

2 files changed

+50
-7
lines changed

2 files changed

+50
-7
lines changed

library/alloc/src/collections/btree/map.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ use core::borrow::Borrow;
22
use core::cmp::Ordering;
33
use core::fmt::{self, Debug};
44
use core::hash::{Hash, Hasher};
5-
use core::iter::{FromIterator, FusedIterator};
5+
use core::iter::{FromIterator, FusedIterator, Peekable};
66
use core::marker::PhantomData;
77
use core::mem::{self, ManuallyDrop};
88
use core::ops::{Index, RangeBounds};
99
use core::ptr;
1010

1111
use super::borrow::DormantMutRef;
12-
use super::merge_iter::MergeIterInner;
1312
use super::node::{self, marker, ForceResult::*, Handle, NodeRef};
1413
use super::search::{self, SearchResult::*};
1514
use super::unwrap_unchecked;
@@ -459,7 +458,10 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for RangeMut<'_, K, V> {
459458
}
460459

461460
// An iterator for merging two sorted sequences into one
462-
struct MergeIter<K, V, I: Iterator<Item = (K, V)>>(MergeIterInner<I>);
461+
struct MergeIter<K, V, I: Iterator<Item = (K, V)>> {
462+
left: Peekable<I>,
463+
right: Peekable<I>,
464+
}
463465

464466
impl<K: Ord, V> BTreeMap<K, V> {
465467
/// Makes a new empty BTreeMap.
@@ -911,7 +913,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
911913
// First, we merge `self` and `other` into a sorted sequence in linear time.
912914
let self_iter = mem::take(self).into_iter();
913915
let other_iter = mem::take(other).into_iter();
914-
let iter = MergeIter(MergeIterInner::new(self_iter, other_iter));
916+
let iter = MergeIter { left: self_iter.peekable(), right: other_iter.peekable() };
915917

916918
// Second, we build a tree from the sorted sequence in linear time.
917919
self.from_sorted_iter(iter);
@@ -2224,10 +2226,24 @@ where
22242226
{
22252227
type Item = (K, V);
22262228

2227-
/// If two keys are equal, returns the key/value-pair from the right source.
22282229
fn next(&mut self) -> Option<(K, V)> {
2229-
let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0));
2230-
b_next.or(a_next)
2230+
let res = match (self.left.peek(), self.right.peek()) {
2231+
(Some(&(ref left_key, _)), Some(&(ref right_key, _))) => left_key.cmp(right_key),
2232+
(Some(_), None) => Ordering::Less,
2233+
(None, Some(_)) => Ordering::Greater,
2234+
(None, None) => return None,
2235+
};
2236+
2237+
// Check which elements comes first and only advance the corresponding iterator.
2238+
// If two keys are equal, take the value from `right`.
2239+
match res {
2240+
Ordering::Less => self.left.next(),
2241+
Ordering::Greater => self.right.next(),
2242+
Ordering::Equal => {
2243+
self.left.next();
2244+
self.right.next()
2245+
}
2246+
}
22312247
}
22322248
}
22332249

library/alloc/src/collections/btree/map/tests.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,33 @@ create_append_test!(test_append_239, 239);
16601660
#[cfg(not(miri))] // Miri is too slow
16611661
create_append_test!(test_append_1700, 1700);
16621662

1663+
#[test]
1664+
fn test_append_drop_leak() {
1665+
static DROPS: AtomicUsize = AtomicUsize::new(0);
1666+
1667+
struct D;
1668+
1669+
impl Drop for D {
1670+
fn drop(&mut self) {
1671+
if DROPS.fetch_add(1, Ordering::SeqCst) == 0 {
1672+
panic!("panic in `drop`");
1673+
}
1674+
}
1675+
}
1676+
1677+
let mut left = BTreeMap::new();
1678+
let mut right = BTreeMap::new();
1679+
left.insert(0, D);
1680+
left.insert(1, D); // first to be dropped during append
1681+
left.insert(2, D);
1682+
right.insert(1, D);
1683+
right.insert(2, D);
1684+
1685+
catch_unwind(move || left.append(&mut right)).unwrap_err();
1686+
1687+
assert_eq!(DROPS.load(Ordering::SeqCst), 5);
1688+
}
1689+
16631690
fn rand_data(len: usize) -> Vec<(u32, u32)> {
16641691
let mut rng = DeterministicRng::new();
16651692
Vec::from_iter((0..len).map(|_| (rng.next(), rng.next())))

0 commit comments

Comments
 (0)