From 4f987ffa16d97769835944b046f2e04549d2476e Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Tue, 16 Dec 2014 23:40:28 -0800 Subject: [PATCH] First attempt at self-balancing rope. Totally broken, though. --- src/buffer.rs | 130 +++++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 2 + 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index 43be6cd..307134b 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use std::cmp::min; +use std::cmp::{min, max}; use std::mem; use std::fmt; use std; @@ -161,6 +161,7 @@ impl fmt::Show for TextBlock { // TODO: record number of graphines as well, to support utf8 properly pub struct TextNode { pub data: TextNodeData, + pub tree_height: uint, pub char_count: uint, pub newline_count: uint, } @@ -178,6 +179,7 @@ impl TextNode { pub fn new() -> TextNode { TextNode { data: TextNodeData::Leaf(TextBlock::new()), + tree_height: 1, char_count: 0, newline_count: 0, } @@ -186,10 +188,120 @@ impl TextNode { pub fn new_from_str(text: &str) -> TextNode { TextNode { data: TextNodeData::Leaf(TextBlock::new_from_str(text)), + tree_height: 1, char_count: char_count(text), newline_count: newline_count(text), } } + + pub fn update_height(&mut self) { + match self.data { + TextNodeData::Leaf(_) => { + self.tree_height = 1; + }, + + TextNodeData::Branch(ref left, ref right) => { + self.tree_height = max(left.tree_height, right.tree_height) + 1; + } + } + } + + pub fn rotate_left(&mut self) { + let mut temp = TextNode::new(); + + if let TextNodeData::Branch(_, ref mut right) = self.data { + mem::swap(&mut temp, &mut (**right)); + + if let TextNodeData::Branch(ref mut left, _) = temp.data { + mem::swap(left, right); + } + } + + if let TextNodeData::Branch(ref mut left, _) = temp.data { + mem::swap(&mut (**left), self); + left.update_height(); + } + + self.update_height(); + } + + pub fn rotate_right(&mut self) { + let mut temp = TextNode::new(); + + if let TextNodeData::Branch(ref mut left, _) = self.data { + mem::swap(&mut temp, &mut (**left)); + + if let TextNodeData::Branch(_, ref mut right) = temp.data { + mem::swap(right, left); + } + } + + if let TextNodeData::Branch(_, ref mut right) = temp.data { + mem::swap(&mut (**right), self); + right.update_height(); + } + + self.update_height(); + } + + pub fn rebalance(&mut self) { + loop { + let mut rot: int = 0; + + if let TextNodeData::Branch(ref mut left, ref mut right) = self.data { + let height_diff = (left.tree_height as int) - (right.tree_height as int); + + // Left side higher than right side + if height_diff > 1 { + let mut child_rot = false; + if let TextNodeData::Branch(ref lc, ref rc) = left.data { + if lc.tree_height < rc.tree_height { + child_rot = true; + } + } + + if child_rot { + if let TextNodeData::Branch(_, ref mut rc) = right.data { + rc.rotate_right(); + } + } + + rot = 1; + } + // Right side higher then left side + else if height_diff < -1 { + let mut child_rot = false; + if let TextNodeData::Branch(ref lc, ref rc) = right.data { + if lc.tree_height > rc.tree_height { + child_rot = true; + } + } + + if child_rot { + if let TextNodeData::Branch(ref mut lc, _) = right.data { + lc.rotate_right(); + } + } + + rot = -1; + } + // Balanced, stop + else { + break; + } + } + else { + break; + } + + if rot == 1 { + self.rotate_right(); + } + else if rot == 1 { + self.rotate_left(); + } + } + } /// Recursively splits a leaf node into roughly equal-sized children, /// being no larger than 'max_size'. @@ -214,7 +326,11 @@ impl TextNode { // Swap the old and new data let mut new_data = TextNodeData::Branch(tn1, tn2); mem::swap(&mut self.data, &mut new_data); + } + + self.rebalance(); + self.update_height(); } /// Merges the data of a non-leaf node to make it a leaf node @@ -238,6 +354,8 @@ impl TextNode { } self.data = TextNodeData::Leaf(TextBlock::new_from_str(s.as_slice())); + self.rebalance(); + self.update_height(); } } @@ -274,6 +392,9 @@ impl TextNode { self.newline_count = left.newline_count + right.newline_count; } } + + self.rebalance(); + self.update_height(); } /// Remove the text between byte positions 'pos_a' and 'pos_b'. @@ -311,8 +432,13 @@ impl TextNode { } } + self.rebalance(); + self.update_height(); + if self.char_count < MIN_LEAF_SIZE { self.merge(); + self.rebalance(); + self.update_height(); } } } @@ -337,7 +463,7 @@ impl fmt::Show for TextNode { /// A text buffer pub struct TextBuffer { - root: TextNode + pub root: TextNode } impl TextBuffer { diff --git a/src/main.rs b/src/main.rs index 233fca6..7004709 100644 --- a/src/main.rs +++ b/src/main.rs @@ -102,4 +102,6 @@ fn main() { } } rustbox::shutdown(); + + println!("{}", tb.root.tree_height); }