From d7cde9f81b473dad63b7c2803d7740314a3e1407 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 14 May 2021 12:26:21 +0200 Subject: [PATCH] Don't underflow Rope chunks on append --- zed/src/editor/buffer/rope.rs | 40 +++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/zed/src/editor/buffer/rope.rs b/zed/src/editor/buffer/rope.rs index bb441e96d34797d1af5097fce675977453bce457..c866b37389e67d464f62b28ef9c77f23011e9c1f 100644 --- a/zed/src/editor/buffer/rope.rs +++ b/zed/src/editor/buffer/rope.rs @@ -7,7 +7,7 @@ use std::{cmp, ops::Range, str}; const CHUNK_BASE: usize = 2; #[cfg(not(test))] -const CHUNK_BASE: usize = 8; +const CHUNK_BASE: usize = 16; #[derive(Clone, Default, Debug)] pub struct Rope { @@ -20,7 +20,20 @@ impl Rope { } pub fn append(&mut self, rope: Rope) { - self.chunks.push_tree(rope.chunks, &()); + let mut chunks = rope.chunks.cursor::<(), ()>(); + chunks.next(); + + while let Some((last_chunk, first_chunk)) = self.chunks.last().zip(chunks.item()) { + if last_chunk.0.len() < CHUNK_BASE || first_chunk.0.len() < CHUNK_BASE { + self.push(&first_chunk.0); + chunks.next(); + } else { + break; + } + } + + self.chunks.push_tree(chunks.suffix(&()), &()); + self.check_invariants(); } pub fn push(&mut self, mut text: &str) { @@ -48,7 +61,7 @@ impl Rope { let split = chunk.0.split_at(take_len); suffix.push_str(split.1); - chunk.0 = ArrayString::from(split.0).unwrap(); + chunk.0.truncate(take_len); } } }, @@ -68,6 +81,25 @@ impl Rope { chunks.push(Chunk(chunk)); } self.chunks.extend(chunks, &()); + self.check_invariants(); + } + + fn check_invariants(&self) { + #[cfg(test)] + { + let mut chunks = self.chunks.cursor::<(), ()>().peekable(); + chunks.next(); + while let Some(chunk) = chunks.next() { + if chunks.peek().is_some() { + assert!( + chunk.0.len() >= CHUNK_BASE, + "Underflowing chunk: {:?}\nChunks: {:?}", + chunk, + self.chunks.items() + ); + } + } + } } pub fn slice(&self, range: Range) -> Rope { @@ -90,7 +122,7 @@ impl Rope { slice.push(&end_chunk.0[..range.end - cursor.start()]); } } - + slice.check_invariants(); slice }