Improved Rope::append()
Append no longer depends on a performant rebalance() operation in any cases. Append is guaranteed O(log N) now.
This commit is contained in:
parent
d95161b88f
commit
de668c5ddf
|
@ -202,18 +202,16 @@ impl Rope {
|
||||||
|
|
||||||
/// Appends another rope to the end of this one, consuming the other rope.
|
/// Appends another rope to the end of this one, consuming the other rope.
|
||||||
pub fn append(&mut self, rope: Rope) {
|
pub fn append(&mut self, rope: Rope) {
|
||||||
if self.tree_height <= rope.tree_height || self.is_leaf() {
|
if self.tree_height > rope.tree_height {
|
||||||
let mut temp_rope = Box::new(Rope::new());
|
self.append_right(rope);
|
||||||
mem::swap(self, &mut (*temp_rope));
|
|
||||||
self.data = RopeData::Branch(temp_rope, Box::new(rope));
|
|
||||||
}
|
}
|
||||||
else if let RopeData::Branch(_, ref mut right) = self.data {
|
else {
|
||||||
right.append(rope);
|
let mut rope = rope;
|
||||||
|
mem::swap(self, &mut rope);
|
||||||
|
self.append_left(rope);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
self.update_stats();
|
|
||||||
self.rebalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a copy of the rope as a string
|
/// Makes a copy of the rope as a string
|
||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
|
@ -324,6 +322,36 @@ impl Rope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn append_right(&mut self, rope: Rope) {
|
||||||
|
if self.tree_height <= rope.tree_height || self.is_leaf() {
|
||||||
|
let mut temp_rope = Box::new(Rope::new());
|
||||||
|
mem::swap(self, &mut (*temp_rope));
|
||||||
|
self.data = RopeData::Branch(temp_rope, Box::new(rope));
|
||||||
|
}
|
||||||
|
else if let RopeData::Branch(_, ref mut right) = self.data {
|
||||||
|
right.append_right(rope);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update_stats();
|
||||||
|
self.rebalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn append_left(&mut self, rope: Rope) {
|
||||||
|
if self.tree_height <= rope.tree_height || self.is_leaf() {
|
||||||
|
let mut temp_rope = Box::new(Rope::new());
|
||||||
|
mem::swap(self, &mut (*temp_rope));
|
||||||
|
self.data = RopeData::Branch(Box::new(rope), temp_rope);
|
||||||
|
}
|
||||||
|
else if let RopeData::Branch(ref mut left, _) = self.data {
|
||||||
|
left.append_left(rope);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update_stats();
|
||||||
|
self.rebalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Splits a leaf node into pieces if it's too large
|
/// Splits a leaf node into pieces if it's too large
|
||||||
|
@ -452,6 +480,9 @@ impl Rope {
|
||||||
|
|
||||||
/// Balances the tree under this node. Assumes that both the left and
|
/// Balances the tree under this node. Assumes that both the left and
|
||||||
/// right sub-trees are themselves aleady balanced.
|
/// right sub-trees are themselves aleady balanced.
|
||||||
|
/// Runs in time linear to the difference in height between the two
|
||||||
|
/// sub-trees. Thus worst-case is O(log N) time, and best-case is O(1)
|
||||||
|
/// time.
|
||||||
fn rebalance(&mut self) {
|
fn rebalance(&mut self) {
|
||||||
let mut rot: isize = 0;
|
let mut rot: isize = 0;
|
||||||
|
|
||||||
|
@ -765,6 +796,28 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn append_4() {
|
||||||
|
let mut rope1 = Rope::new_from_str("1234567890-=qwertyuiop{}asdfghjkl;'zxcvbnm,.Hello World! Let's make this a long string for kicks and giggles. Who knows when it will end? No one! Well, except for the person writing it. And... eh... later, the person reading it. Because they'll get to the end. And then they'll know.");
|
||||||
|
let mut rope2 = Rope::new_from_str("Z");
|
||||||
|
|
||||||
|
rope1.append(rope2);
|
||||||
|
|
||||||
|
assert_eq!(rope1.to_string(), "1234567890-=qwertyuiop{}asdfghjkl;'zxcvbnm,.Hello World! Let's make this a long string for kicks and giggles. Who knows when it will end? No one! Well, except for the person writing it. And... eh... later, the person reading it. Because they'll get to the end. And then they'll know.Z");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn append_5() {
|
||||||
|
let mut rope1 = Rope::new_from_str("Z");
|
||||||
|
let mut rope2 = Rope::new_from_str("1234567890-=qwertyuiop{}asdfghjkl;'zxcvbnm,.Hello World! Let's make this a long string for kicks and giggles. Who knows when it will end? No one! Well, except for the person writing it. And... eh... later, the person reading it. Because they'll get to the end. And then they'll know.");
|
||||||
|
|
||||||
|
rope1.append(rope2);
|
||||||
|
|
||||||
|
assert_eq!(rope1.to_string(), "Z1234567890-=qwertyuiop{}asdfghjkl;'zxcvbnm,.Hello World! Let's make this a long string for kicks and giggles. Who knows when it will end? No one! Well, except for the person writing it. And... eh... later, the person reading it. Because they'll get to the end. And then they'll know.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn insert_text() {
|
fn insert_text() {
|
||||||
let mut rope = Rope::new();
|
let mut rope = Rope::new();
|
||||||
|
@ -1283,13 +1336,22 @@ mod tests {
|
||||||
let mut rope2 = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1025]).unwrap().as_slice());
|
let mut rope2 = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1025]).unwrap().as_slice());
|
||||||
|
|
||||||
assert_eq!(rope1.tree_height, rope2.tree_height);
|
assert_eq!(rope1.tree_height, rope2.tree_height);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rebalance_2() {
|
fn rebalance_2() {
|
||||||
|
let mut rope1 = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 2]).unwrap().as_slice());
|
||||||
|
rope1.insert_text_at_grapheme_index(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1024]).unwrap().as_slice(), MAX_NODE_SIZE);
|
||||||
|
|
||||||
|
let mut rope2 = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1026]).unwrap().as_slice());
|
||||||
|
|
||||||
|
assert_eq!(rope1.tree_height, rope2.tree_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rebalance_3() {
|
||||||
let mut rope1 = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1024]).unwrap().as_slice());
|
let mut rope1 = Rope::new_from_str(String::from_utf8(vec!['c' as u8; MAX_NODE_SIZE * 1024]).unwrap().as_slice());
|
||||||
rope1.remove_text_between_grapheme_indices(MAX_NODE_SIZE*7, MAX_NODE_SIZE*(7+959));
|
rope1.remove_text_between_grapheme_indices(MAX_NODE_SIZE*7, MAX_NODE_SIZE*(7+959));
|
||||||
|
|
||||||
|
@ -1353,7 +1415,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
||||||
#[bench]
|
#[bench]
|
||||||
fn new_from_str_4(b: &mut Bencher) {
|
fn new_from_str_4(b: &mut Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let rope = Rope::new_from_str("
|
let _ = Rope::new_from_str("
|
||||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
|
Loading…
Reference in New Issue
Block a user