Auto merge of #81361 - ssomers:btree_drainy_refactor_7, r=Mark-Simulacrum
BTreeMap: lightly refactor the split_off implementation r? `@Mark-Simulacrum`
This commit is contained in:
commit
a2704448c1
@ -20,6 +20,14 @@
|
|||||||
/// We might temporarily have fewer elements during methods.
|
/// We might temporarily have fewer elements during methods.
|
||||||
pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
|
pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
|
||||||
|
|
||||||
|
// A tree in a `BTreeMap` is a tree in the `node` module with addtional invariants:
|
||||||
|
// - Keys must appear in ascending order (according to the key's type).
|
||||||
|
// - If the root node is internal, it must contain at least 1 element.
|
||||||
|
// - Every non-root node contains at least MIN_LEN elements.
|
||||||
|
//
|
||||||
|
// An empty map may be represented both by the absense of a root node or by a
|
||||||
|
// root node that is an empty leaf.
|
||||||
|
|
||||||
/// A map based on a B-Tree.
|
/// A map based on a B-Tree.
|
||||||
///
|
///
|
||||||
/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing
|
/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing
|
||||||
@ -1131,20 +1139,12 @@ pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self
|
|||||||
let total_num = self.len();
|
let total_num = self.len();
|
||||||
let left_root = self.root.as_mut().unwrap(); // unwrap succeeds because not empty
|
let left_root = self.root.as_mut().unwrap(); // unwrap succeeds because not empty
|
||||||
|
|
||||||
let mut right = Self::new();
|
let right_root = left_root.split_off(key);
|
||||||
let right_root = Self::ensure_is_owned(&mut right.root);
|
|
||||||
|
|
||||||
left_root.split_off(right_root, key);
|
let (new_left_len, right_len) = Root::calc_split_length(total_num, &left_root, &right_root);
|
||||||
|
self.length = new_left_len;
|
||||||
|
|
||||||
if left_root.height() < right_root.height() {
|
BTreeMap { root: Some(right_root), length: right_len }
|
||||||
self.length = left_root.reborrow().calc_length();
|
|
||||||
right.length = total_num - self.len();
|
|
||||||
} else {
|
|
||||||
right.length = right_root.reborrow().calc_length();
|
|
||||||
self.length = total_num - right.len();
|
|
||||||
}
|
|
||||||
|
|
||||||
right
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an iterator that visits all elements (key-value pairs) in
|
/// Creates an iterator that visits all elements (key-value pairs) in
|
||||||
|
@ -4,46 +4,71 @@
|
|||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
impl<K, V> Root<K, V> {
|
impl<K, V> Root<K, V> {
|
||||||
pub fn split_off<Q: ?Sized + Ord>(&mut self, right_root: &mut Self, key: &Q)
|
/// Calculates the length of both trees that result from splitting up
|
||||||
|
/// a given number of distinct key-value pairs.
|
||||||
|
pub fn calc_split_length(
|
||||||
|
total_num: usize,
|
||||||
|
root_a: &Root<K, V>,
|
||||||
|
root_b: &Root<K, V>,
|
||||||
|
) -> (usize, usize) {
|
||||||
|
let (length_a, length_b);
|
||||||
|
if root_a.height() < root_b.height() {
|
||||||
|
length_a = root_a.reborrow().calc_length();
|
||||||
|
length_b = total_num - length_a;
|
||||||
|
debug_assert_eq!(length_b, root_b.reborrow().calc_length());
|
||||||
|
} else {
|
||||||
|
length_b = root_b.reborrow().calc_length();
|
||||||
|
length_a = total_num - length_b;
|
||||||
|
debug_assert_eq!(length_a, root_a.reborrow().calc_length());
|
||||||
|
}
|
||||||
|
(length_a, length_b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Split off a tree with key-value pairs at and after the given key.
|
||||||
|
/// The result is meaningful only if the tree is ordered by key,
|
||||||
|
/// and if the ordering of `Q` corresponds to that of `K`.
|
||||||
|
/// If `self` respects all `BTreeMap` tree invariants, then both
|
||||||
|
/// `self` and the returned tree will respect those invariants.
|
||||||
|
pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self
|
||||||
where
|
where
|
||||||
K: Borrow<Q>,
|
K: Borrow<Q>,
|
||||||
{
|
{
|
||||||
debug_assert!(right_root.height() == 0);
|
|
||||||
debug_assert!(right_root.len() == 0);
|
|
||||||
|
|
||||||
let left_root = self;
|
let left_root = self;
|
||||||
for _ in 0..left_root.height() {
|
let mut right_root = Root::new_pillar(left_root.height());
|
||||||
right_root.push_internal_level();
|
let mut left_node = left_root.borrow_mut();
|
||||||
}
|
let mut right_node = right_root.borrow_mut();
|
||||||
|
|
||||||
{
|
loop {
|
||||||
let mut left_node = left_root.borrow_mut();
|
let mut split_edge = match left_node.search_node(key) {
|
||||||
let mut right_node = right_root.borrow_mut();
|
// key is going to the right tree
|
||||||
|
Found(kv) => kv.left_edge(),
|
||||||
|
GoDown(edge) => edge,
|
||||||
|
};
|
||||||
|
|
||||||
loop {
|
split_edge.move_suffix(&mut right_node);
|
||||||
let mut split_edge = match left_node.search_node(key) {
|
|
||||||
// key is going to the right tree
|
|
||||||
Found(kv) => kv.left_edge(),
|
|
||||||
GoDown(edge) => edge,
|
|
||||||
};
|
|
||||||
|
|
||||||
split_edge.move_suffix(&mut right_node);
|
match (split_edge.force(), right_node.force()) {
|
||||||
|
(Internal(edge), Internal(node)) => {
|
||||||
match (split_edge.force(), right_node.force()) {
|
left_node = edge.descend();
|
||||||
(Internal(edge), Internal(node)) => {
|
right_node = node.first_edge().descend();
|
||||||
left_node = edge.descend();
|
|
||||||
right_node = node.first_edge().descend();
|
|
||||||
}
|
|
||||||
(Leaf(_), Leaf(_)) => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
|
(Leaf(_), Leaf(_)) => break,
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
left_root.fix_right_border();
|
left_root.fix_right_border();
|
||||||
right_root.fix_left_border();
|
right_root.fix_left_border();
|
||||||
|
right_root
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a tree consisting of empty nodes.
|
||||||
|
fn new_pillar(height: usize) -> Self {
|
||||||
|
let mut root = Root::new();
|
||||||
|
for _ in 0..height {
|
||||||
|
root.push_internal_level();
|
||||||
|
}
|
||||||
|
root
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty.
|
/// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty.
|
||||||
|
Loading…
Reference in New Issue
Block a user