diff --git a/src/core/rope.rs b/src/core/rope.rs index 80e7492..3f9e5fb 100644 --- a/src/core/rope.rs +++ b/src/core/rope.rs @@ -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 /// implementation. @@ -43,6 +43,21 @@ impl Rope { 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, right: Option>) -> Rc { + 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. pub fn total_bytes(&self) -> usize { 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, right: Option>) -> Rc { - 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`. /// /// 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) -> Rc { - // TODO - self + if self.is_balanced() { + 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 @@ -191,6 +201,18 @@ impl Rope { } } +fn merge(leaf_nodes: &[Rc]) -> Rc { + 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 { stack: Vec>, }