diff --git a/src/grid/mod.rs b/src/grid/mod.rs index ac54f580..13e6cc00 100644 --- a/src/grid/mod.rs +++ b/src/grid/mod.rs @@ -121,7 +121,7 @@ impl Grid { // TODO (jwilm) Allocating each line at this point is expensive and // delays startup. A nice solution might be having `Row` delay // allocation until it's actually used. - for _ in 0..raw.capacity() { + for _ in 0..raw.len() { raw.push(Row::new(cols, &template)); } diff --git a/src/grid/storage.rs b/src/grid/storage.rs index fb66b0c3..63b30831 100644 --- a/src/grid/storage.rs +++ b/src/grid/storage.rs @@ -20,6 +20,8 @@ pub struct Storage { inner: Vec, zero: usize, visible_lines: Line, + #[serde(skip)] + len: usize, } impl ::std::cmp::PartialEq for Storage { @@ -39,58 +41,49 @@ impl Storage { inner: Vec::with_capacity(cap), zero: 0, visible_lines: lines - 1, + len: cap, } } - #[inline] - pub fn capacity(&self) -> usize { - self.inner.capacity() - } - /// Increase the number of lines in the buffer pub fn grow_visible_lines(&mut self, next: Line, template_row: T) where T: Clone, { - // Calculate insert position (before the first line) - let offset = self.zero % self.inner.len(); - - // Insert new template row for every line grown + // Number of lines the buffer needs to grow let lines_to_grow = (next - (self.visible_lines + 1)).0; - for _ in 0..lines_to_grow { - self.inner.insert(offset, template_row.clone()); + + // Only grow if there are not enough lines still hidden + if lines_to_grow > (self.inner.len() - self.len) { + // Lines to grow additionally to invisible lines + let new_lines_to_grow = lines_to_grow - (self.inner.len() - self.len); + + // Get the position of the start of the buffer + let offset = self.zero % self.inner.len(); + + // Split off the beginning of the raw inner buffer + let mut start_buffer = self.inner.split_off(offset); + + // Insert new template rows at the end of the raw inner buffer + let mut new_lines = vec![template_row; new_lines_to_grow]; + self.inner.append(&mut new_lines); + + // Add the start to the raw inner buffer again + self.inner.append(&mut start_buffer); + + // Update the zero to after the lines we just inserted + self.zero = offset + lines_to_grow; } - // Set zero to old zero + lines grown - self.zero = offset + lines_to_grow; - - // Update visible lines + // Update visible lines and raw buffer length + self.len += lines_to_grow; self.visible_lines = next - 1; } /// Decrease the number of lines in the buffer pub fn shrink_visible_lines(&mut self, next: Line) { - // Calculate shrinkage and last line of buffer - let shrinkage = (self.visible_lines + 1 - next).0; - let offset = (self.zero + self.inner.len() - 1) % self.inner.len(); - - // Generate range of lines that have to be deleted before the zero line - let start = offset.saturating_sub(shrinkage - 1); - let shrink_before = start..(offset + 1); - - // Generate range of lines that have to be deleted after the zero line - let shrink_after = (self.inner.len() + offset + 1 - shrinkage)..self.inner.len(); - - // Delete all lines in reverse order - for i in shrink_before.chain(shrink_after).rev() { - self.inner.remove(i); - } - - // Check if zero has moved (not the first line in the buffer) - if self.zero % (self.inner.len() + shrinkage) != 0 { - // Set zero to the first deleted line in the buffer - self.zero = start; - } + // Shrink the size without removing any lines + self.len -= (self.visible_lines - (next - 1)).0; // Update visible lines self.visible_lines = next - 1; @@ -103,17 +96,17 @@ impl Storage { #[inline] pub fn len(&self) -> usize { - self.inner.len() + self.len } /// Compute actual index in underlying storage given the requested index. #[inline] fn compute_index(&self, requested: usize) -> usize { - (requested + self.zero) % self.len() + (requested + self.zero) % self.inner.len() } fn compute_line_index(&self, requested: Line) -> usize { - ((self.len() + self.zero + *self.visible_lines) - *requested) % self.len() + ((self.inner.len() + self.zero + *self.visible_lines) - *requested) % self.inner.len() } pub fn swap_lines(&mut self, a: Line, b: Line) { @@ -127,14 +120,14 @@ impl Storage { } pub fn rotate(&mut self, count: isize) { - let len = self.len(); + let len = self.inner.len(); assert!(count.abs() as usize <= len); self.zero += (count + len as isize) as usize % len; } // Fast path pub fn rotate_up(&mut self, count: usize) { - self.zero = (self.zero + count) % self.len(); + self.zero = (self.zero + count) % self.inner.len(); } } @@ -212,6 +205,7 @@ fn grow_after_zero() { inner: vec!["0", "1", "-"], zero: 0, visible_lines: Line(2), + len: 3, }; // Grow buffer @@ -222,9 +216,11 @@ fn grow_after_zero() { inner: vec!["-", "0", "1", "-"], zero: 1, visible_lines: Line(0), + len: 4, }; assert_eq!(storage.inner, expected.inner); assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); } /// Grow the buffer one line at the start of the buffer @@ -245,6 +241,7 @@ fn grow_before_zero() { inner: vec!["-", "0", "1"], zero: 1, visible_lines: Line(2), + len: 3, }; // Grow buffer @@ -255,9 +252,11 @@ fn grow_before_zero() { inner: vec!["-", "-", "0", "1"], zero: 2, visible_lines: Line(0), + len: 4, }; assert_eq!(storage.inner, expected.inner); assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); } /// Shrink the buffer one line at the start of the buffer @@ -267,6 +266,7 @@ fn grow_before_zero() { /// 1: 0 <- Zero /// 2: 1 /// After: +/// 0: 2 <- Hidden /// 0: 0 <- Zero /// 1: 1 #[test] @@ -276,6 +276,7 @@ fn shrink_before_zero() { inner: vec!["2", "0", "1"], zero: 1, visible_lines: Line(2), + len: 3, }; // Shrink buffer @@ -283,12 +284,14 @@ fn shrink_before_zero() { // Make sure the result is correct let expected = Storage { - inner: vec!["0", "1"], - zero: 0, + inner: vec!["2", "0", "1"], + zero: 1, visible_lines: Line(0), + len: 2, }; assert_eq!(storage.inner, expected.inner); assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); } /// Shrink the buffer one line at the end of the buffer @@ -300,6 +303,7 @@ fn shrink_before_zero() { /// After: /// 0: 0 <- Zero /// 1: 1 +/// 2: 2 <- Hidden #[test] fn shrink_after_zero() { // Setup storage area @@ -307,6 +311,7 @@ fn shrink_after_zero() { inner: vec!["0", "1", "2"], zero: 0, visible_lines: Line(2), + len: 3, }; // Shrink buffer @@ -314,12 +319,14 @@ fn shrink_after_zero() { // Make sure the result is correct let expected = Storage { - inner: vec!["0", "1"], + inner: vec!["0", "1", "2"], zero: 0, visible_lines: Line(0), + len: 2, }; assert_eq!(storage.inner, expected.inner); assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); } /// Shrink the buffer at the start and end of the buffer @@ -332,8 +339,12 @@ fn shrink_after_zero() { /// 4: 2 /// 5: 3 /// After: -/// 0: 0 <- Zero -/// 1: 1 +/// 0: 4 <- Hidden +/// 1: 5 <- Hidden +/// 2: 0 <- Zero +/// 3: 1 +/// 4: 2 <- Hidden +/// 5: 3 <- Hidden #[test] fn shrink_before_and_after_zero() { // Setup storage area @@ -341,6 +352,7 @@ fn shrink_before_and_after_zero() { inner: vec!["4", "5", "0", "1", "2", "3"], zero: 2, visible_lines: Line(5), + len: 6, }; // Shrink buffer @@ -348,10 +360,12 @@ fn shrink_before_and_after_zero() { // Make sure the result is correct let expected = Storage { - inner: vec!["0", "1"], - zero: 0, + inner: vec!["4", "5", "0", "1", "2", "3"], + zero: 2, visible_lines: Line(0), + len: 2, }; assert_eq!(storage.inner, expected.inner); assert_eq!(storage.zero, expected.zero); + assert_eq!(storage.len, expected.len); }