Skip to content

Commit 685fd53

Browse files
committed
BTreeMap: split off most code of append, slightly improve interfaces
1 parent b1277d0 commit 685fd53

File tree

5 files changed

+176
-114
lines changed

5 files changed

+176
-114
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
use super::map::MIN_LEN;
2+
use super::merge_iter::MergeIterInner;
3+
use super::node::{self, ForceResult::*, Root};
4+
use core::iter::FusedIterator;
5+
6+
impl<K, V> Root<K, V> {
7+
/// Appends all key-value pairs from the union of two ascending iterators,
8+
/// incrementing a `length` variable along the way. The latter makes it
9+
/// easier for the caller to avoid a leak when a drop handler panicks.
10+
///
11+
/// If both iterators produce the same key, this method drops the pair from
12+
/// the left iterator and appends the pair from the right iterator.
13+
///
14+
/// If you want the tree to end up in a strictly ascending order, like for
15+
/// a `BTreeMap`, both iterators should produce keys in strictly ascending
16+
/// order, each greater than all keys in the tree, including any keys
17+
/// already in the tree upon entry.
18+
pub fn append_from_sorted_iters<I>(&mut self, left: I, right: I, length: &mut usize)
19+
where
20+
K: Ord,
21+
I: Iterator<Item = (K, V)> + FusedIterator,
22+
{
23+
// We prepare to merge `left` and `right` into a sorted sequence in linear time.
24+
let iter = MergeIter(MergeIterInner::new(left, right));
25+
26+
// Meanwhile, we build a tree from the sorted sequence in linear time.
27+
self.bulk_push(iter, length)
28+
}
29+
30+
/// Pushes all key-value pairs to the end of the tree, incrementing a
31+
/// `length` variable along the way. The latter makes it easier for the
32+
/// caller to avoid a leak when the iterator panicks.
33+
fn bulk_push<I>(&mut self, iter: I, length: &mut usize)
34+
where
35+
I: Iterator<Item = (K, V)>,
36+
{
37+
let mut cur_node = self.node_as_mut().last_leaf_edge().into_node();
38+
// Iterate through all key-value pairs, pushing them into nodes at the right level.
39+
for (key, value) in iter {
40+
// Try to push key-value pair into the current leaf node.
41+
if cur_node.len() < node::CAPACITY {
42+
cur_node.push(key, value);
43+
} else {
44+
// No space left, go up and push there.
45+
let mut open_node;
46+
let mut test_node = cur_node.forget_type();
47+
loop {
48+
match test_node.ascend() {
49+
Ok(parent) => {
50+
let parent = parent.into_node();
51+
if parent.len() < node::CAPACITY {
52+
// Found a node with space left, push here.
53+
open_node = parent;
54+
break;
55+
} else {
56+
// Go up again.
57+
test_node = parent.forget_type();
58+
}
59+
}
60+
Err(_) => {
61+
// We are at the top, create a new root node and push there.
62+
open_node = self.push_internal_level();
63+
break;
64+
}
65+
}
66+
}
67+
68+
// Push key-value pair and new right subtree.
69+
let tree_height = open_node.height() - 1;
70+
let mut right_tree = Root::new_leaf();
71+
for _ in 0..tree_height {
72+
right_tree.push_internal_level();
73+
}
74+
open_node.push(key, value, right_tree);
75+
76+
// Go down to the right-most leaf again.
77+
cur_node = open_node.forget_type().last_leaf_edge().into_node();
78+
}
79+
80+
// Increment length every iteration, to make sure the map drops
81+
// the appended elements even if advancing the iterator panicks.
82+
*length += 1;
83+
}
84+
self.fix_right_edge();
85+
}
86+
87+
fn fix_right_edge(&mut self) {
88+
// Handle underfull nodes, start from the top.
89+
let mut cur_node = self.node_as_mut();
90+
while let Internal(internal) = cur_node.force() {
91+
// Check if right-most child is underfull.
92+
let mut last_edge = internal.last_edge();
93+
let right_child_len = last_edge.reborrow().descend().len();
94+
if right_child_len < MIN_LEN {
95+
// We need to steal.
96+
let mut last_kv = match last_edge.left_kv() {
97+
Ok(left) => left,
98+
Err(_) => unreachable!(),
99+
};
100+
last_kv.bulk_steal_left(MIN_LEN - right_child_len);
101+
last_edge = last_kv.right_edge();
102+
}
103+
104+
// Go further down.
105+
cur_node = last_edge.descend();
106+
}
107+
}
108+
}
109+
110+
// An iterator for merging two sorted sequences into one
111+
struct MergeIter<K, V, I: Iterator<Item = (K, V)>>(MergeIterInner<I>);
112+
113+
impl<K: Ord, V, I> Iterator for MergeIter<K, V, I>
114+
where
115+
I: Iterator<Item = (K, V)> + FusedIterator,
116+
{
117+
type Item = (K, V);
118+
119+
/// If two keys are equal, returns the key-value pair from the right source.
120+
fn next(&mut self) -> Option<(K, V)> {
121+
let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0));
122+
b_next.or(a_next)
123+
}
124+
}

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

+2-94
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ 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;
@@ -458,9 +457,6 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for RangeMut<'_, K, V> {
458457
}
459458
}
460459

461-
// An iterator for merging two sorted sequences into one
462-
struct MergeIter<K, V, I: Iterator<Item = (K, V)>>(MergeIterInner<I>);
463-
464460
impl<K: Ord, V> BTreeMap<K, V> {
465461
/// Makes a new empty BTreeMap.
466462
///
@@ -908,13 +904,10 @@ impl<K: Ord, V> BTreeMap<K, V> {
908904
return;
909905
}
910906

911-
// First, we merge `self` and `other` into a sorted sequence in linear time.
912907
let self_iter = mem::take(self).into_iter();
913908
let other_iter = mem::take(other).into_iter();
914-
let iter = MergeIter(MergeIterInner::new(self_iter, other_iter));
915-
916-
// Second, we build a tree from the sorted sequence in linear time.
917-
self.from_sorted_iter(iter);
909+
let root = BTreeMap::ensure_is_owned(&mut self.root);
910+
root.append_from_sorted_iters(self_iter, other_iter, &mut self.length)
918911
}
919912

920913
/// Constructs a double-ended iterator over a sub-range of elements in the map.
@@ -1039,78 +1032,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
10391032
}
10401033
}
10411034

1042-
fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
1043-
let root = Self::ensure_is_owned(&mut self.root);
1044-
let mut cur_node = root.node_as_mut().last_leaf_edge().into_node();
1045-
// Iterate through all key-value pairs, pushing them into nodes at the right level.
1046-
for (key, value) in iter {
1047-
// Try to push key-value pair into the current leaf node.
1048-
if cur_node.len() < node::CAPACITY {
1049-
cur_node.push(key, value);
1050-
} else {
1051-
// No space left, go up and push there.
1052-
let mut open_node;
1053-
let mut test_node = cur_node.forget_type();
1054-
loop {
1055-
match test_node.ascend() {
1056-
Ok(parent) => {
1057-
let parent = parent.into_node();
1058-
if parent.len() < node::CAPACITY {
1059-
// Found a node with space left, push here.
1060-
open_node = parent;
1061-
break;
1062-
} else {
1063-
// Go up again.
1064-
test_node = parent.forget_type();
1065-
}
1066-
}
1067-
Err(_) => {
1068-
// We are at the top, create a new root node and push there.
1069-
open_node = root.push_internal_level();
1070-
break;
1071-
}
1072-
}
1073-
}
1074-
1075-
// Push key-value pair and new right subtree.
1076-
let tree_height = open_node.height() - 1;
1077-
let mut right_tree = node::Root::new_leaf();
1078-
for _ in 0..tree_height {
1079-
right_tree.push_internal_level();
1080-
}
1081-
open_node.push(key, value, right_tree);
1082-
1083-
// Go down to the right-most leaf again.
1084-
cur_node = open_node.forget_type().last_leaf_edge().into_node();
1085-
}
1086-
1087-
self.length += 1;
1088-
}
1089-
Self::fix_right_edge(root)
1090-
}
1091-
1092-
fn fix_right_edge(root: &mut node::Root<K, V>) {
1093-
// Handle underfull nodes, start from the top.
1094-
let mut cur_node = root.node_as_mut();
1095-
while let Internal(internal) = cur_node.force() {
1096-
// Check if right-most child is underfull.
1097-
let mut last_edge = internal.last_edge();
1098-
let right_child_len = last_edge.reborrow().descend().len();
1099-
if right_child_len < MIN_LEN {
1100-
// We need to steal.
1101-
let mut last_kv = match last_edge.left_kv() {
1102-
Ok(left) => left,
1103-
Err(_) => unreachable!(),
1104-
};
1105-
last_kv.bulk_steal_left(MIN_LEN - right_child_len);
1106-
last_edge = last_kv.right_edge();
1107-
}
1108-
1109-
// Go further down.
1110-
cur_node = last_edge.descend();
1111-
}
1112-
}
1113-
11141035
/// Splits the collection into two at the given key. Returns everything after the given key,
11151036
/// including the key.
11161037
///
@@ -2220,18 +2141,5 @@ impl<K, V> BTreeMap<K, V> {
22202141
}
22212142
}
22222143

2223-
impl<K: Ord, V, I> Iterator for MergeIter<K, V, I>
2224-
where
2225-
I: Iterator<Item = (K, V)> + ExactSizeIterator + FusedIterator,
2226-
{
2227-
type Item = (K, V);
2228-
2229-
/// If two keys are equal, returns the key/value-pair from the right source.
2230-
fn next(&mut self) -> Option<(K, V)> {
2231-
let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0));
2232-
b_next.or(a_next)
2233-
}
2234-
}
2235-
22362144
#[cfg(test)]
22372145
mod tests;

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

+27
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,33 @@ create_append_test!(test_append_239, 239);
16671667
#[cfg(not(miri))] // Miri is too slow
16681668
create_append_test!(test_append_1700, 1700);
16691669

1670+
#[test]
1671+
fn test_append_drop_leak() {
1672+
static DROPS: AtomicUsize = AtomicUsize::new(0);
1673+
1674+
struct D;
1675+
1676+
impl Drop for D {
1677+
fn drop(&mut self) {
1678+
if DROPS.fetch_add(1, Ordering::SeqCst) == 0 {
1679+
panic!("panic in `drop`");
1680+
}
1681+
}
1682+
}
1683+
1684+
let mut left = BTreeMap::new();
1685+
let mut right = BTreeMap::new();
1686+
left.insert(0, D);
1687+
left.insert(1, D); // first to be dropped during append
1688+
left.insert(2, D);
1689+
right.insert(1, D);
1690+
right.insert(2, D);
1691+
1692+
catch_unwind(move || left.append(&mut right)).unwrap_err();
1693+
1694+
assert_eq!(DROPS.load(Ordering::SeqCst), 4); // Rust issue #47949 ate one little piggy
1695+
}
1696+
16701697
fn rand_data(len: usize) -> Vec<(u32, u32)> {
16711698
assert!(len * 2 <= 70029); // from that point on numbers repeat
16721699
let mut rng = DeterministicRng::new();

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

+22-20
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,43 @@ use core::cmp::Ordering;
22
use core::fmt::{self, Debug};
33
use core::iter::FusedIterator;
44

5-
/// Core of an iterator that merges the output of two ascending iterators,
5+
/// Core of an iterator that merges the output of two strictly ascending iterators,
66
/// for instance a union or a symmetric difference.
7-
pub struct MergeIterInner<I>
8-
where
9-
I: Iterator,
10-
{
7+
pub struct MergeIterInner<I: Iterator> {
118
a: I,
129
b: I,
1310
peeked: Option<Peeked<I>>,
1411
}
1512

16-
/// Benchmarks faster than wrapping both iterators in a Peekable.
13+
/// Benchmarks faster than wrapping both iterators in a Peekable,
14+
/// probably because we can afford to impose a FusedIterator bound.
1715
#[derive(Clone, Debug)]
1816
enum Peeked<I: Iterator> {
1917
A(I::Item),
2018
B(I::Item),
2119
}
2220

23-
impl<I> Clone for MergeIterInner<I>
21+
impl<I: Iterator> Clone for MergeIterInner<I>
2422
where
25-
I: Clone + Iterator,
23+
I: Clone,
2624
I::Item: Clone,
2725
{
2826
fn clone(&self) -> Self {
2927
Self { a: self.a.clone(), b: self.b.clone(), peeked: self.peeked.clone() }
3028
}
3129
}
3230

33-
impl<I> Debug for MergeIterInner<I>
31+
impl<I: Iterator> Debug for MergeIterInner<I>
3432
where
35-
I: Iterator + Debug,
33+
I: Debug,
3634
I::Item: Debug,
3735
{
3836
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39-
f.debug_tuple("MergeIterInner").field(&self.a).field(&self.b).finish()
37+
f.debug_tuple("MergeIterInner").field(&self.a).field(&self.b).field(&self.peeked).finish()
4038
}
4139
}
4240

43-
impl<I> MergeIterInner<I>
44-
where
45-
I: ExactSizeIterator + FusedIterator,
46-
{
41+
impl<I: Iterator> MergeIterInner<I> {
4742
/// Creates a new core for an iterator merging a pair of sources.
4843
pub fn new(a: I, b: I) -> Self {
4944
MergeIterInner { a, b, peeked: None }
@@ -52,13 +47,17 @@ where
5247
/// Returns the next pair of items stemming from the pair of sources
5348
/// being merged. If both returned options contain a value, that value
5449
/// is equal and occurs in both sources. If one of the returned options
55-
/// contains a value, that value doesn't occur in the other source.
56-
/// If neither returned option contains a value, iteration has finished
57-
/// and subsequent calls will return the same empty pair.
50+
/// contains a value, that value doesn't occur in the other source (or
51+
/// the sources are not strictly ascending). If neither returned option
52+
/// contains a value, iteration has finished and subsequent calls will
53+
/// return the same empty pair.
5854
pub fn nexts<Cmp: Fn(&I::Item, &I::Item) -> Ordering>(
5955
&mut self,
6056
cmp: Cmp,
61-
) -> (Option<I::Item>, Option<I::Item>) {
57+
) -> (Option<I::Item>, Option<I::Item>)
58+
where
59+
I: FusedIterator,
60+
{
6261
let mut a_next;
6362
let mut b_next;
6463
match self.peeked.take() {
@@ -86,7 +85,10 @@ where
8685
}
8786

8887
/// Returns a pair of upper bounds for the `size_hint` of the final iterator.
89-
pub fn lens(&self) -> (usize, usize) {
88+
pub fn lens(&self) -> (usize, usize)
89+
where
90+
I: ExactSizeIterator,
91+
{
9092
match self.peeked {
9193
Some(Peeked::A(_)) => (1 + self.a.len(), self.b.len()),
9294
Some(Peeked::B(_)) => (self.a.len(), 1 + self.b.len()),

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

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod append;
12
mod borrow;
23
pub mod map;
34
mod mem;

0 commit comments

Comments
 (0)