mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-25 14:05:41 -05:00
Optimize Row::reset
Now, only cells that have been used are cleared. This is achieved by using a "occupied" memo on the Row itself. The value, `occ`, is updated wherever the Row is accessed mutably, and it's cleared to zero in Row::reset. The tests for grid scroll_up and scroll_down were updated to include a test on the value `occ` and slightly refactored, but are otherwise equivalent to the previous implementation of those tests. Because of the change to the `Row` struct, the ref tests were updated so Deserialization keeps working as expected.
This commit is contained in:
parent
4b1a3b1e92
commit
c61a912f62
24 changed files with 145 additions and 104 deletions
|
@ -3,18 +3,31 @@
|
||||||
require 'json'
|
require 'json'
|
||||||
|
|
||||||
Dir.glob('./tests/ref/**/grid.json').each do |path|
|
Dir.glob('./tests/ref/**/grid.json').each do |path|
|
||||||
|
puts "Migrating #{path}"
|
||||||
|
|
||||||
# Read contents
|
# Read contents
|
||||||
s = File.open(path) { |f| f.read }
|
s = File.open(path) { |f| f.read }
|
||||||
|
|
||||||
# Parse
|
# Parse
|
||||||
grid = JSON.parse(s)
|
grid = JSON.parse(s)
|
||||||
|
|
||||||
# Check if it's already migrated / make this migration idempotent
|
# Normalize Storage serialization
|
||||||
next if grid['raw'][0][0].is_a? Array
|
if grid['raw'].is_a? Array
|
||||||
|
grid['raw'] = {
|
||||||
|
'inner' => grid['raw'][0],
|
||||||
|
'zero' => grid['raw'][1],
|
||||||
|
'visible_lines' => grid['raw'][2]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
# Transform
|
# Migrate Row serialization
|
||||||
grid['raw'].reverse!
|
grid['raw']['inner'].map! do |row|
|
||||||
grid['raw'] = [grid['raw'], 0, grid['lines'] - 1]
|
if row.is_a? Hash
|
||||||
|
row
|
||||||
|
else
|
||||||
|
{ inner: row, occ: row.length }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Write updated grid
|
# Write updated grid
|
||||||
File.open(path, 'w') { |f| f << JSON.generate(grid) }
|
File.open(path, 'w') { |f| f << JSON.generate(grid) }
|
||||||
|
|
|
@ -14,43 +14,78 @@
|
||||||
|
|
||||||
//! Defines the Row type which makes up lines in the grid
|
//! Defines the Row type which makes up lines in the grid
|
||||||
|
|
||||||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use std::ops::{Range, RangeTo, RangeFrom, RangeFull};
|
use std::ops::{Range, RangeTo, RangeFrom, RangeFull};
|
||||||
|
use std::cmp::{max, min};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
use index::Column;
|
use index::Column;
|
||||||
|
|
||||||
/// A row in the grid
|
/// A row in the grid
|
||||||
#[derive(Default, Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Row<T>(Vec<T>);
|
pub struct Row<T> {
|
||||||
|
inner: Vec<T>,
|
||||||
|
|
||||||
|
/// occupied entries
|
||||||
|
///
|
||||||
|
/// Semantically, this value can be understood as the **end** of an
|
||||||
|
/// Exclusive Range. Thus,
|
||||||
|
///
|
||||||
|
/// - Zero means there are no occupied entries
|
||||||
|
/// - 1 means there is a value at index zero, but nowhere else
|
||||||
|
/// - `occ == inner.len` means every value is occupied
|
||||||
|
pub(crate) occ: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq> PartialEq for Row<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.inner == other.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Copy + Clone> Row<T> {
|
impl<T: Copy + Clone> Row<T> {
|
||||||
pub fn new(columns: Column, template: &T) -> Row<T> {
|
pub fn new(columns: Column, template: &T) -> Row<T> {
|
||||||
Row(vec![*template; *columns])
|
Row {
|
||||||
|
inner: vec![*template; *columns],
|
||||||
|
occ: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grow(&mut self, cols: Column, template: &T) {
|
pub fn grow(&mut self, cols: Column, template: &T) {
|
||||||
assert!(self.len() < * cols);
|
assert!(self.len() < * cols);
|
||||||
|
|
||||||
while self.len() != *cols {
|
while self.len() != *cols {
|
||||||
self.0.push(*template);
|
self.inner.push(*template);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets contents to the contents of `other`
|
/// Resets contents to the contents of `other`
|
||||||
#[inline]
|
#[inline(never)]
|
||||||
pub fn reset(&mut self, other: &T) {
|
pub fn reset(&mut self, other: &T) {
|
||||||
for item in &mut self.0 {
|
let occ = self.occ;
|
||||||
|
for item in &mut self.inner[..occ] {
|
||||||
*item = *other;
|
*item = *other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.occ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Row<T> {
|
impl<T> Row<T> {
|
||||||
pub fn shrink(&mut self, cols: Column) {
|
pub fn shrink(&mut self, cols: Column) {
|
||||||
while self.len() != *cols {
|
while self.len() != *cols {
|
||||||
self.pop();
|
self.inner.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.occ = min(self.occ, *cols);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.inner.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter<'a>(&'a self) -> slice::Iter<'a, T> {
|
||||||
|
self.inner.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,24 +106,8 @@ impl<'a, T> IntoIterator for &'a mut Row<T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_iter(self) -> slice::IterMut<'a, T> {
|
fn into_iter(self) -> slice::IterMut<'a, T> {
|
||||||
self.iter_mut()
|
self.occ = self.len();
|
||||||
}
|
self.inner.iter_mut()
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Deref for Row<T> {
|
|
||||||
type Target = Vec<T>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl<T> DerefMut for Row<T> {
|
|
||||||
#[inline]
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,14 +116,15 @@ impl<T> Index<Column> for Row<T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: Column) -> &T {
|
fn index(&self, index: Column) -> &T {
|
||||||
&self.0[index.0]
|
&self.inner[index.0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IndexMut<Column> for Row<T> {
|
impl<T> IndexMut<Column> for Row<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: Column) -> &mut T {
|
fn index_mut(&mut self, index: Column) -> &mut T {
|
||||||
&mut self.0[index.0]
|
self.occ = max(self.occ, *index + 1);
|
||||||
|
&mut self.inner[index.0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,14 +137,15 @@ impl<T> Index<Range<Column>> for Row<T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: Range<Column>) -> &[T] {
|
fn index(&self, index: Range<Column>) -> &[T] {
|
||||||
&self.0[(index.start.0)..(index.end.0)]
|
&self.inner[(index.start.0)..(index.end.0)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IndexMut<Range<Column>> for Row<T> {
|
impl<T> IndexMut<Range<Column>> for Row<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: Range<Column>) -> &mut [T] {
|
fn index_mut(&mut self, index: Range<Column>) -> &mut [T] {
|
||||||
&mut self.0[(index.start.0)..(index.end.0)]
|
self.occ = max(self.occ, *index.end);
|
||||||
|
&mut self.inner[(index.start.0)..(index.end.0)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,14 +154,15 @@ impl<T> Index<RangeTo<Column>> for Row<T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: RangeTo<Column>) -> &[T] {
|
fn index(&self, index: RangeTo<Column>) -> &[T] {
|
||||||
&self.0[..(index.end.0)]
|
&self.inner[..(index.end.0)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IndexMut<RangeTo<Column>> for Row<T> {
|
impl<T> IndexMut<RangeTo<Column>> for Row<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: RangeTo<Column>) -> &mut [T] {
|
fn index_mut(&mut self, index: RangeTo<Column>) -> &mut [T] {
|
||||||
&mut self.0[..(index.end.0)]
|
self.occ = max(self.occ, *index.end);
|
||||||
|
&mut self.inner[..(index.end.0)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,14 +171,15 @@ impl<T> Index<RangeFrom<Column>> for Row<T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: RangeFrom<Column>) -> &[T] {
|
fn index(&self, index: RangeFrom<Column>) -> &[T] {
|
||||||
&self.0[(index.start.0)..]
|
&self.inner[(index.start.0)..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IndexMut<RangeFrom<Column>> for Row<T> {
|
impl<T> IndexMut<RangeFrom<Column>> for Row<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: RangeFrom<Column>) -> &mut [T] {
|
fn index_mut(&mut self, index: RangeFrom<Column>) -> &mut [T] {
|
||||||
&mut self.0[(index.start.0)..]
|
self.occ = self.len();
|
||||||
|
&mut self.inner[(index.start.0)..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,13 +188,14 @@ impl<T> Index<RangeFull> for Row<T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, _: RangeFull) -> &[T] {
|
fn index(&self, _: RangeFull) -> &[T] {
|
||||||
&self.0[..]
|
&self.inner[..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IndexMut<RangeFull> for Row<T> {
|
impl<T> IndexMut<RangeFull> for Row<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, _: RangeFull) -> &mut [T] {
|
fn index_mut(&mut self, _: RangeFull) -> &mut [T] {
|
||||||
&mut self.0[..]
|
self.occ = self.len();
|
||||||
|
&mut self.inner[..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,73 +20,77 @@ use index::{Point, Line, Column};
|
||||||
// Scroll up moves lines upwards
|
// Scroll up moves lines upwards
|
||||||
#[test]
|
#[test]
|
||||||
fn scroll_up() {
|
fn scroll_up() {
|
||||||
info!("");
|
println!("");
|
||||||
|
|
||||||
let mut grid = Grid::new(Line(10), Column(1), 0, 0);
|
let mut grid = Grid::new(Line(10), Column(1), 0, 0);
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
grid[Line(i)][Column(0)] = i;
|
grid[Line(i)][Column(0)] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("grid: {:?}", grid);
|
println!("grid: {:?}", grid);
|
||||||
|
|
||||||
grid.scroll_up(&(Line(0)..Line(10)), Line(2), &0);
|
grid.scroll_up(&(Line(0)..Line(10)), Line(2), &0);
|
||||||
|
|
||||||
info!("grid: {:?}", grid);
|
println!("grid: {:?}", grid);
|
||||||
|
|
||||||
let mut other = Grid::new(Line(10), Column(1), 0, 9);
|
assert_eq!(grid[Line(0)][Column(0)], 2);
|
||||||
|
assert_eq!(grid[Line(0)].occ, 1);
|
||||||
other[Line(0)][Column(0)] = 2;
|
assert_eq!(grid[Line(1)][Column(0)], 3);
|
||||||
other[Line(1)][Column(0)] = 3;
|
assert_eq!(grid[Line(1)].occ, 1);
|
||||||
other[Line(2)][Column(0)] = 4;
|
assert_eq!(grid[Line(2)][Column(0)], 4);
|
||||||
other[Line(3)][Column(0)] = 5;
|
assert_eq!(grid[Line(2)].occ, 1);
|
||||||
other[Line(4)][Column(0)] = 6;
|
assert_eq!(grid[Line(3)][Column(0)], 5);
|
||||||
other[Line(5)][Column(0)] = 7;
|
assert_eq!(grid[Line(3)].occ, 1);
|
||||||
other[Line(6)][Column(0)] = 8;
|
assert_eq!(grid[Line(4)][Column(0)], 6);
|
||||||
other[Line(7)][Column(0)] = 9;
|
assert_eq!(grid[Line(4)].occ, 1);
|
||||||
other[Line(8)][Column(0)] = 0; // should be cleared on scroll; was 0
|
assert_eq!(grid[Line(5)][Column(0)], 7);
|
||||||
other[Line(9)][Column(0)] = 0; // should be cleared on scroll; was 1
|
assert_eq!(grid[Line(5)].occ, 1);
|
||||||
|
assert_eq!(grid[Line(6)][Column(0)], 8);
|
||||||
for i in 0..10 {
|
assert_eq!(grid[Line(6)].occ, 1);
|
||||||
assert_eq!(grid[Line(i)][Column(0)], other[Line(i)][Column(0)],
|
assert_eq!(grid[Line(7)][Column(0)], 9);
|
||||||
"index={}; actual: {:?}, expected: {:?}",
|
assert_eq!(grid[Line(7)].occ, 1);
|
||||||
Line(i), grid[Line(i)][Column(0)], other[Line(i)][Column(0)]);
|
assert_eq!(grid[Line(8)][Column(0)], 0); // was 0
|
||||||
}
|
assert_eq!(grid[Line(8)].occ, 0);
|
||||||
|
assert_eq!(grid[Line(9)][Column(0)], 0); // was 1
|
||||||
|
assert_eq!(grid[Line(9)].occ, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll down moves lines downwards
|
// Scroll down moves lines downwards
|
||||||
#[test]
|
#[test]
|
||||||
fn scroll_down() {
|
fn scroll_down() {
|
||||||
info!("");
|
println!("");
|
||||||
|
|
||||||
let mut grid = Grid::new(Line(10), Column(1), 0, 0);
|
let mut grid = Grid::new(Line(10), Column(1), 0, 0);
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
grid[Line(i)][Column(0)] = i;
|
grid[Line(i)][Column(0)] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("grid: {:?}", grid);
|
println!("grid: {:?}", grid);
|
||||||
|
|
||||||
grid.scroll_down(&(Line(0)..Line(10)), Line(2), &0);
|
grid.scroll_down(&(Line(0)..Line(10)), Line(2), &0);
|
||||||
|
|
||||||
info!("grid: {:?}", grid);
|
println!("grid: {:?}", grid);
|
||||||
|
|
||||||
let mut other = Grid::new(Line(10), Column(1), 0, 9);
|
assert_eq!(grid[Line(0)][Column(0)], 0); // was 8
|
||||||
|
assert_eq!(grid[Line(0)].occ, 0);
|
||||||
other[Line(0)][Column(0)] = 0; // Should be cleared upon recycle; was 8
|
assert_eq!(grid[Line(1)][Column(0)], 0); // was 9
|
||||||
other[Line(1)][Column(0)] = 0; // Should be cleared upon recycle; was 9
|
assert_eq!(grid[Line(1)].occ, 0);
|
||||||
other[Line(2)][Column(0)] = 0;
|
assert_eq!(grid[Line(2)][Column(0)], 0);
|
||||||
other[Line(3)][Column(0)] = 1;
|
assert_eq!(grid[Line(2)].occ, 1);
|
||||||
other[Line(4)][Column(0)] = 2;
|
assert_eq!(grid[Line(3)][Column(0)], 1);
|
||||||
other[Line(5)][Column(0)] = 3;
|
assert_eq!(grid[Line(3)].occ, 1);
|
||||||
other[Line(6)][Column(0)] = 4;
|
assert_eq!(grid[Line(4)][Column(0)], 2);
|
||||||
other[Line(7)][Column(0)] = 5;
|
assert_eq!(grid[Line(4)].occ, 1);
|
||||||
other[Line(8)][Column(0)] = 6;
|
assert_eq!(grid[Line(5)][Column(0)], 3);
|
||||||
other[Line(9)][Column(0)] = 7;
|
assert_eq!(grid[Line(5)].occ, 1);
|
||||||
|
assert_eq!(grid[Line(6)][Column(0)], 4);
|
||||||
for i in 0..10 {
|
assert_eq!(grid[Line(6)].occ, 1);
|
||||||
assert_eq!(grid[Line(i)][Column(0)], other[Line(i)][Column(0)],
|
assert_eq!(grid[Line(7)][Column(0)], 5);
|
||||||
"index={}; actual: {:?}, expected: {:?}",
|
assert_eq!(grid[Line(7)].occ, 1);
|
||||||
Line(i), grid[Line(i)][Column(0)], other[Line(i)][Column(0)]);
|
assert_eq!(grid[Line(8)][Column(0)], 6);
|
||||||
}
|
assert_eq!(grid[Line(8)].occ, 1);
|
||||||
|
assert_eq!(grid[Line(9)][Column(0)], 7);
|
||||||
|
assert_eq!(grid[Line(9)].occ, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that GridIterator works
|
// Test that GridIterator works
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue