From 350bb8c800232ce0b27512420e99645ec8b95ef1 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sun, 14 Jan 2018 10:17:08 -0800 Subject: [PATCH] Use memcpy for resetting row contents In addition to a marginal performance improvement, this simplifies some logic in the Term implementation since now the Grid fully handles row recycling. --- src/grid/mod.rs | 117 +++++++++++++++++++++++++++++++----------------- src/grid/row.rs | 12 +++-- src/term/mod.rs | 27 ++--------- 3 files changed, 87 insertions(+), 69 deletions(-) diff --git a/src/grid/mod.rs b/src/grid/mod.rs index 9ca0011a..e790dd41 100644 --- a/src/grid/mod.rs +++ b/src/grid/mod.rs @@ -73,6 +73,15 @@ pub struct Grid { /// /// Invariant: lines is equivalent to raw.len() lines: index::Line, + + /// Template row. + /// + /// This is used to quickly populate new lines and clear recycled lines + /// during scroll wrapping. + template_row: Row, + + /// Template cell for populating template_row + template: T, } pub struct GridIterator<'a, T: 'a> { @@ -80,55 +89,110 @@ pub struct GridIterator<'a, T: 'a> { pub cur: Point, } -impl Grid { - pub fn new(lines: index::Line, cols: index::Column, template: &T) -> Grid { +impl Grid { + pub fn new(lines: index::Line, cols: index::Column, template: T) -> Grid { let mut raw = VecDeque::with_capacity(*lines); + let template_row = Row::new(cols, &template); for _ in IndexRange(index::Line(0)..lines) { - raw.push_back(Row::new(cols, template)); + raw.push_back(template_row.clone()); } Grid { raw, cols, lines, + template_row, + template, } } - pub fn resize(&mut self, lines: index::Line, cols: index::Column, template: &T) { + pub fn resize(&mut self, lines: index::Line, cols: index::Column) { // Check that there's actually work to do and return early if not if lines == self.lines && cols == self.cols { return; } match self.lines.cmp(&lines) { - Ordering::Less => self.grow_lines(lines, template), + Ordering::Less => self.grow_lines(lines), Ordering::Greater => self.shrink_lines(lines), Ordering::Equal => (), } match self.cols.cmp(&cols) { - Ordering::Less => self.grow_cols(cols, template), + Ordering::Less => self.grow_cols(cols), Ordering::Greater => self.shrink_cols(cols), Ordering::Equal => (), } } - fn grow_lines(&mut self, lines: index::Line, template: &T) { + fn grow_lines(&mut self, lines: index::Line) { for _ in IndexRange(self.num_lines()..lines) { - self.raw.push_back(Row::new(self.cols, template)); + self.raw.push_back(self.template_row.clone()); } self.lines = lines; } - fn grow_cols(&mut self, cols: index::Column, template: &T) { + fn grow_cols(&mut self, cols: index::Column) { for row in self.raw.iter_mut() { - row.grow(cols, template); + row.grow(cols, &self.template); } + // Update self cols self.cols = cols; + + // Also update template_row to be the correct length + self.template_row.grow(cols, &self.template); } + #[inline] + pub fn scroll_down(&mut self, region: &Range, positions: index::Line) { + if region.start == Line(0) && region.end == self.num_lines() { + // Full rotation + for _ in 0..positions.0 { + let mut item = self.raw.pop_back().unwrap(); + item.reset(&self.template_row); + self.raw.push_front(item); + } + } else { + // Subregion rotation + for line in IndexRange((region.start + positions)..region.end).rev() { + self.swap_lines(line, line - positions); + } + + let template = &self.template_row; + for i in IndexRange(Line(0)..positions) { + self.raw + .get_mut(*(region.start + i)) + .map(|row| row.reset(template)); + } + } + } + + #[inline] + pub fn scroll_up(&mut self, region: &Range, positions: index::Line) { + if region.start == Line(0) && region.end == self.num_lines() { + // Full rotation + for _ in 0..positions.0 { + let mut item = self.raw.pop_front().unwrap(); + item.reset(&self.template_row); + self.raw.push_back(item); + } + } else { + // Subregion rotation + for line in IndexRange(region.start..(region.end - positions)) { + self.swap_lines(line, line + positions); + } + + // Clear reused lines + let template = &self.template_row; + for i in IndexRange(Line(0)..positions) { + self.raw + .get_mut(*(region.end - i - 1)) + .map(|row| row.reset(template)); + } + } + } } impl Grid { @@ -142,38 +206,6 @@ impl Grid { self.cols } - #[inline] - pub fn scroll_down(&mut self, region: &Range, positions: index::Line) { - if region.start == Line(0) && region.end == self.num_lines() { - // Full rotation - for _ in 0..positions.0 { - let item = self.raw.pop_back().unwrap(); - self.raw.push_front(item); - } - } else { - // Subregion rotation - for line in IndexRange((region.start + positions)..region.end).rev() { - self.swap_lines(line, line - positions); - } - } - } - - #[inline] - pub fn scroll_up(&mut self, region: &Range, positions: index::Line) { - if region.start == Line(0) && region.end == self.num_lines() { - // Full rotation - for _ in 0..positions.0 { - let item = self.raw.pop_front().unwrap(); - self.raw.push_back(item); - } - } else { - // Subregion rotation - for line in IndexRange(region.start..(region.end - positions)) { - self.swap_lines(line, line + positions); - } - } - } - pub fn iter_from(&self, point: Point) -> GridIterator { GridIterator { grid: self, @@ -209,6 +241,7 @@ impl Grid { } self.cols = cols; + self.template_row.shrink(cols); } } diff --git a/src/grid/row.rs b/src/grid/row.rs index 4b355a56..e9cf8dc9 100644 --- a/src/grid/row.rs +++ b/src/grid/row.rs @@ -24,16 +24,22 @@ use index::Column; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] pub struct Row(Vec); -impl Row { +impl Row { pub fn new(columns: Column, template: &T) -> Row { - Row(vec![template.to_owned(); *columns]) + Row(vec![*template; *columns]) } pub fn grow(&mut self, cols: Column, template: &T) { while self.len() != *cols { - self.push(template.to_owned()); + self.push(*template); } } + + /// Resets contents to the contents of `other` + #[inline] + pub fn reset(&mut self, other: &Row) { + self.copy_from_slice(&**other); + } } impl Row { diff --git a/src/term/mod.rs b/src/term/mod.rs index c405490e..efcafc25 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -800,7 +800,7 @@ impl Term { let num_cols = size.cols(); let num_lines = size.lines(); - let grid = Grid::new(num_lines, num_cols, &template); + let grid = Grid::new(num_lines, num_cols, template); let tabspaces = config.tabspaces(); let tabs = IndexRange::from(Column(0)..grid.num_cols()) @@ -1066,9 +1066,8 @@ impl Term { debug!("num_cols, num_lines = {}, {}", num_cols, num_lines); // Resize grids to new size - let template = Cell::default(); - self.grid.resize(num_lines, num_cols, &template); - self.alt_grid.resize(num_lines, num_cols, &template); + self.grid.resize(num_lines, num_cols); + self.alt_grid.resize(num_lines, num_cols); // Reset scrolling region to new size self.scroll_region = Line(0)..self.grid.num_lines(); @@ -1133,17 +1132,6 @@ impl Term { trace!("scroll_down_relative: origin={}, lines={}", origin, lines); let lines = min(lines, self.scroll_region.end - self.scroll_region.start); - // Copy of cell template; can't have it borrowed when calling clear/scroll - let template = self.cursor.template; - - // Clear `lines` lines at bottom of area - { - let start = max(origin, Line(self.scroll_region.end.0.saturating_sub(lines.0))); - self.grid - .region_mut(start..self.scroll_region.end) - .each(|c| c.reset(&template)); - } - // Scroll between origin and bottom self.grid.scroll_down(&(origin..self.scroll_region.end), lines); } @@ -1157,15 +1145,6 @@ impl Term { trace!("scroll_up_relative: origin={}, lines={}", origin, lines); let lines = min(lines, self.scroll_region.end - self.scroll_region.start); - // Copy of cell template; can't have it borrowed when calling clear/scroll - let template = self.cursor.template; - - // Clear `lines` lines starting from origin to origin + lines - { - let end = min(origin + lines, self.scroll_region.end); - self.grid.region_mut(origin..end).each(|c| c.reset(&template)); - } - // Scroll from origin to bottom less number of lines self.grid.scroll_up(&(origin..self.scroll_region.end), lines); }