Skip to content

Commit b7faf86

Browse files
committed
BTree: add split_off_range methods
1 parent d40f24e commit b7faf86

File tree

8 files changed

+1085
-51
lines changed

8 files changed

+1085
-51
lines changed

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

+322-11
Large diffs are not rendered by default.

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

+62
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,68 @@ impl<K, V, A: Allocator> BTreeMap<K, V, A> {
13071307
}
13081308
}
13091309

1310+
/// Splits the collection into two. Returns a new collection with all keys in the given range.
1311+
///
1312+
/// # Panics
1313+
///
1314+
/// Panics if range `start > end`.
1315+
/// Panics if range `start == end` and both bounds are `Excluded`.
1316+
/// May panic if the [`Ord`] implementation of type `T` is ill-defined,
1317+
/// either because it does not form a total order or because it does not
1318+
/// correspond to the [`Ord`] implementation of type `K`.
1319+
///
1320+
/// # Examples
1321+
///
1322+
/// Basic usage:
1323+
///
1324+
/// ```
1325+
/// #![feature(btree_split_off_range)]
1326+
/// use std::collections::BTreeMap;
1327+
///
1328+
/// let mut a = BTreeMap::new();
1329+
/// a.insert(1, "a");
1330+
/// a.insert(2, "b");
1331+
/// a.insert(3, "c");
1332+
/// a.insert(17, "d");
1333+
/// a.insert(41, "e");
1334+
///
1335+
/// let b = a.split_off_range(&3..&33);
1336+
///
1337+
/// assert_eq!(a.len(), 3);
1338+
/// assert_eq!(b.len(), 2);
1339+
///
1340+
/// assert_eq!(a[&1], "a");
1341+
/// assert_eq!(a[&2], "b");
1342+
/// assert_eq!(a[&41], "e");
1343+
///
1344+
/// assert_eq!(b[&3], "c");
1345+
/// assert_eq!(b[&17], "d");
1346+
/// ```
1347+
#[unstable(feature = "btree_split_off_range", issue = "81074")]
1348+
pub fn split_off_range<T: ?Sized, R>(&mut self, range: R) -> Self
1349+
where
1350+
T: Ord,
1351+
K: Borrow<T> + Ord,
1352+
R: RangeBounds<T>,
1353+
A: Clone,
1354+
{
1355+
let alloc = (*self.alloc).clone();
1356+
if self.is_empty() {
1357+
return Self::new_in(alloc);
1358+
}
1359+
1360+
let total_num = self.length;
1361+
let left_root = self.root.as_mut().unwrap(); // unwrap succeeds because not empty
1362+
1363+
let mut right_root = left_root.split_off_range(range, &alloc);
1364+
right_root.fix_both_borders(&alloc);
1365+
1366+
let (new_left_len, right_len) = Root::calc_split_length(total_num, &left_root, &right_root);
1367+
self.length = new_left_len;
1368+
1369+
BTreeMap { root: Some(right_root), length: right_len, alloc: ManuallyDrop::new(alloc) }
1370+
}
1371+
13101372
/// Creates an iterator that visits all elements (key-value pairs) in
13111373
/// ascending key order and uses a closure to determine if an element should
13121374
/// be removed. If the closure returns `true`, the element is removed from

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

+28
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use std::ops::RangeBounds;
1717
use std::panic::{catch_unwind, AssertUnwindSafe};
1818
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
1919

20+
mod split_off_range;
21+
2022
// Minimum number of elements to insert, to guarantee a tree with 2 levels,
2123
// i.e., a tree who's root is an internal node at height 1, with edges to leaf nodes.
2224
// It's not the minimum size: removing an element from such a tree does not always reduce height.
@@ -27,6 +29,12 @@ const MIN_INSERTS_HEIGHT_1: usize = node::CAPACITY + 1;
2729
// It's not the minimum size: removing an element from such a tree does not always reduce height.
2830
const MIN_INSERTS_HEIGHT_2: usize = 89;
2931

32+
// Like MIN_INSERTS_HEIGHT_2, with an additional internal level.
33+
const MIN_INSERTS_HEIGHT_3: usize = 628;
34+
35+
// Like MIN_INSERTS_HEIGHT_3, with an additional internal level.
36+
const MIN_INSERTS_HEIGHT_4: usize = 4401;
37+
3038
// Gathers all references from a mutable iterator and makes sure Miri notices if
3139
// using them is dangerous.
3240
fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {
@@ -174,6 +182,26 @@ fn test_levels() {
174182
// - 5 elements in right child's last grandchild
175183
assert_eq!(map.height(), Some(2));
176184
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_2, "{}", map.dump_keys());
185+
186+
if cfg!(miri) {
187+
// Miri is too slow
188+
return;
189+
}
190+
while map.height() == Some(2) {
191+
let last_key = *map.last_key_value().unwrap().0;
192+
map.insert(last_key + 1, ());
193+
}
194+
map.check();
195+
assert_eq!(map.height(), Some(3));
196+
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_3);
197+
198+
while map.height() == Some(3) {
199+
let last_key = *map.last_key_value().unwrap().0;
200+
map.insert(last_key + 1, ());
201+
}
202+
map.check();
203+
assert_eq!(map.height(), Some(4));
204+
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_4);
177205
}
178206

179207
// Ensures the testing infrastructure usually notices order violations.

0 commit comments

Comments
 (0)