Add Rope::rebalance()

This commit is contained in:
Matthew Gordon 2024-10-19 21:17:02 -03:00
parent b2ef8cc284
commit 511f56872a
1 changed files with 40 additions and 18 deletions

View File

@ -1,4 +1,4 @@
use std::rc::Rc; use {super::fibbonacci::fibbonacci, std::rc::Rc};
/// [Rope](https://en.wikipedia.org/wiki/Rope_(data_structure)) data structure /// [Rope](https://en.wikipedia.org/wiki/Rope_(data_structure)) data structure
/// implementation. /// implementation.
@ -43,6 +43,21 @@ impl Rope {
Rc::new(Rope::Leaf { text }) Rc::new(Rope::Leaf { text })
} }
/// Concatenate two Ropes without rebalancing.
///
/// Combines to ropes by creating a new parent node and adding `left` and
/// `right` as children. If `right` is [None] then the resulting node will
/// only have one child.
fn join(left: Rc<Rope>, right: Option<Rc<Rope>>) -> Rc<Self> {
Rc::new(Rope::Branch {
bytes_weight: left.total_bytes(),
chars_weight: left.total_chars(),
lines_weight: left.total_lines(),
left,
right,
})
}
/// Return the total number of bytes in the text. /// Return the total number of bytes in the text.
pub fn total_bytes(&self) -> usize { pub fn total_bytes(&self) -> usize {
match self { match self {
@ -94,21 +109,6 @@ impl Rope {
} }
} }
/// Concatenate two Ropes without rebalancing.
///
/// Combines to ropes by creating a new parent node and adding `left` and
/// `right` as children. If `right` is [None] then the resulting node will
/// only have one child.
fn join(left: Rc<Rope>, right: Option<Rc<Rope>>) -> Rc<Self> {
Rc::new(Rope::Branch {
bytes_weight: left.total_bytes(),
chars_weight: left.total_chars(),
lines_weight: left.total_lines(),
left,
right,
})
}
/// Split the rope in two at character `index`. /// Split the rope in two at character `index`.
/// ///
/// The result is two Ropes—one containing the first 'i' characters of the /// The result is two Ropes—one containing the first 'i' characters of the
@ -152,9 +152,19 @@ impl Rope {
} }
} }
fn is_balanced(&self) -> bool {
match self {
Rope::Branch { bytes_weight, .. } => fibbonacci(self.depth() + 2) <= *bytes_weight,
Rope::Leaf { .. } => true,
}
}
fn rebalance(self: Rc<Rope>) -> Rc<Rope> { fn rebalance(self: Rc<Rope>) -> Rc<Rope> {
// TODO if self.is_balanced() {
self return self;
}
let leaf_nodes: Vec<_> = self.iter_nodes().collect();
merge(&leaf_nodes)
} }
/// Number of steps between this node and it's most distance descendant /// Number of steps between this node and it's most distance descendant
@ -191,6 +201,18 @@ impl Rope {
} }
} }
fn merge(leaf_nodes: &[Rc<Rope>]) -> Rc<Rope> {
match leaf_nodes.len() {
0 => panic!("Attempt to merge empty list"),
1 => leaf_nodes[0].clone(),
2 => Rope::join(leaf_nodes[0].clone(), Some(leaf_nodes[1].clone())),
3.. => {
let mid = leaf_nodes.len() / 2;
Rope::join(merge(&leaf_nodes[..mid]), Some(merge(&leaf_nodes[mid..])))
}
}
}
struct NodeIterator { struct NodeIterator {
stack: Vec<Rc<Rope>>, stack: Vec<Rc<Rope>>,
} }