First attempt at self-balancing rope. Totally broken, though.

This commit is contained in:
Nathan Vegdahl 2014-12-16 23:40:28 -08:00
parent ab992301fd
commit 4f987ffa16
2 changed files with 130 additions and 2 deletions

View File

@ -1,6 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::cmp::min; use std::cmp::{min, max};
use std::mem; use std::mem;
use std::fmt; use std::fmt;
use std; use std;
@ -161,6 +161,7 @@ impl fmt::Show for TextBlock {
// TODO: record number of graphines as well, to support utf8 properly // TODO: record number of graphines as well, to support utf8 properly
pub struct TextNode { pub struct TextNode {
pub data: TextNodeData, pub data: TextNodeData,
pub tree_height: uint,
pub char_count: uint, pub char_count: uint,
pub newline_count: uint, pub newline_count: uint,
} }
@ -178,6 +179,7 @@ impl TextNode {
pub fn new() -> TextNode { pub fn new() -> TextNode {
TextNode { TextNode {
data: TextNodeData::Leaf(TextBlock::new()), data: TextNodeData::Leaf(TextBlock::new()),
tree_height: 1,
char_count: 0, char_count: 0,
newline_count: 0, newline_count: 0,
} }
@ -186,10 +188,120 @@ impl TextNode {
pub fn new_from_str(text: &str) -> TextNode { pub fn new_from_str(text: &str) -> TextNode {
TextNode { TextNode {
data: TextNodeData::Leaf(TextBlock::new_from_str(text)), data: TextNodeData::Leaf(TextBlock::new_from_str(text)),
tree_height: 1,
char_count: char_count(text), char_count: char_count(text),
newline_count: newline_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, /// Recursively splits a leaf node into roughly equal-sized children,
/// being no larger than 'max_size'. /// being no larger than 'max_size'.
@ -214,7 +326,11 @@ impl TextNode {
// Swap the old and new data // Swap the old and new data
let mut new_data = TextNodeData::Branch(tn1, tn2); let mut new_data = TextNodeData::Branch(tn1, tn2);
mem::swap(&mut self.data, &mut new_data); 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 /// 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.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.newline_count = left.newline_count + right.newline_count;
} }
} }
self.rebalance();
self.update_height();
} }
/// Remove the text between byte positions 'pos_a' and 'pos_b'. /// 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 { if self.char_count < MIN_LEAF_SIZE {
self.merge(); self.merge();
self.rebalance();
self.update_height();
} }
} }
} }
@ -337,7 +463,7 @@ impl fmt::Show for TextNode {
/// A text buffer /// A text buffer
pub struct TextBuffer { pub struct TextBuffer {
root: TextNode pub root: TextNode
} }
impl TextBuffer { impl TextBuffer {

View File

@ -102,4 +102,6 @@ fn main() {
} }
} }
rustbox::shutdown(); rustbox::shutdown();
println!("{}", tb.root.tree_height);
} }