aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-11-09 10:42:44 -0500
committerJesse Luehrs <doy@tozt.net>2019-11-09 14:58:57 -0500
commit596730bf19f04a97ef835b27466998b50f26e230 (patch)
tree7e30d088e4e09e567cbfb268f31b10f55baa82da
parentdbf02d880407df0667b56e52290decaab752a199 (diff)
downloadvt100-rust-596730bf19f04a97ef835b27466998b50f26e230.tar.gz
vt100-rust-596730bf19f04a97ef835b27466998b50f26e230.zip
use a fixed size buffer for cell data
this dramatically speeds things up
-rw-r--r--src/cell.rs78
-rw-r--r--src/row.rs2
-rw-r--r--tests/text.rs8
3 files changed, 69 insertions, 19 deletions
diff --git a/src/cell.rs b/src/cell.rs
index d0d6f0c..61a3cd3 100644
--- a/src/cell.rs
+++ b/src/cell.rs
@@ -1,33 +1,73 @@
use unicode_normalization::UnicodeNormalization as _;
use unicode_width::UnicodeWidthChar as _;
+const CODEPOINTS_IN_CELL: usize = 6;
+
/// Represents a single terminal cell.
-#[derive(Clone, Debug, Default, Eq, PartialEq)]
+#[derive(Clone, Debug, Default, Eq)]
pub struct Cell {
- contents: String,
+ contents: [char; CODEPOINTS_IN_CELL],
+ len: u8,
attrs: crate::attrs::Attrs,
}
+impl PartialEq<Cell> for Cell {
+ fn eq(&self, other: &Self) -> bool {
+ if self.attrs != other.attrs {
+ return false;
+ }
+ if self.len != other.len {
+ return false;
+ }
+ let len = self.len as usize;
+ self.contents[..len] == other.contents[..len]
+ }
+}
+
impl Cell {
pub(crate) fn set(&mut self, c: char, a: crate::attrs::Attrs) {
- let mut buf = vec![0; 4];
- c.encode_utf8(&mut buf);
- self.contents = unsafe { String::from_utf8_unchecked(buf) };
+ self.contents[0] = c;
+ self.len = 1;
self.attrs = a;
}
pub(crate) fn append(&mut self, c: char) {
- self.contents.push(c);
+ if self.len as usize >= CODEPOINTS_IN_CELL {
+ return;
+ }
+
+ self.contents[self.len as usize] = c;
+ self.len += 1;
+
// some fonts have combined characters but can't render combining
// characters correctly, so try to prefer precombined characters when
// possible
- if !unicode_normalization::is_nfc(&self.contents) {
- self.contents = self.contents.nfc().collect();
+ if unicode_normalization::is_nfc_quick(
+ self.contents.iter().copied().take(CODEPOINTS_IN_CELL),
+ ) == unicode_normalization::IsNormalized::Yes
+ {
+ return;
}
+
+ let mut new_contents = ['\x00'; CODEPOINTS_IN_CELL];
+ let mut new_len = 0;
+ for c in self
+ .contents
+ .iter()
+ .copied()
+ .take(self.len as usize)
+ .nfc()
+ .take(CODEPOINTS_IN_CELL)
+ {
+ new_contents[new_len as usize] = c;
+ new_len += 1;
+ }
+ self.contents = new_contents;
+ self.len = new_len;
}
pub(crate) fn clear(&mut self, bgcolor: crate::attrs::Color) {
- self.contents.clear();
+ self.len = 0;
self.attrs.clear();
self.attrs.bgcolor = bgcolor;
}
@@ -37,13 +77,16 @@ impl Cell {
/// Can include multiple unicode characters if combining characters are
/// used, but will contain at most one character with a non-zero character
/// width.
- pub fn contents(&self) -> &str {
- &self.contents
+ pub fn contents(&self) -> String {
+ self.contents
+ .iter()
+ .take(self.len as usize)
+ .collect::<String>()
}
/// Returns whether the cell contains any text data.
pub fn has_contents(&self) -> bool {
- self.contents != ""
+ self.len > 0
}
/// Returns whether the text data in the cell represents a wide character.
@@ -51,12 +94,11 @@ impl Cell {
// strings in this context should always be an arbitrary character
// followed by zero or more zero-width characters, so we should only
// have to look at the first character
- let width = self
- .contents
- .chars()
- .next()
- .map_or(0, |c| c.width().unwrap_or(0));
- width > 1
+ if self.len == 0 {
+ false
+ } else {
+ self.contents[0].width().unwrap_or(0) > 1
+ }
}
pub(crate) fn attrs(&self) -> &crate::attrs::Attrs {
diff --git a/src/row.rs b/src/row.rs
index 4655f48..4511183 100644
--- a/src/row.rs
+++ b/src/row.rs
@@ -85,7 +85,7 @@ impl Row {
if cell.has_contents() {
// using write! here is significantly slower, for some reason
// write!(contents, "{}", cell.contents()).unwrap();
- contents.push_str(cell.contents());
+ contents.push_str(&cell.contents());
} else {
contents.push(' ');
}
diff --git a/tests/text.rs b/tests/text.rs
index 5c16039..e588a68 100644
--- a/tests/text.rs
+++ b/tests/text.rs
@@ -149,6 +149,14 @@ fn combining() {
parser.process("\r\n\u{0301}".as_bytes());
assert_eq!(parser.screen().cell(9, 79).unwrap().contents(), "a");
assert_eq!(parser.screen().cell(10, 0).unwrap().contents(), "");
+
+ parser.process("\x1bcabcdefg\x1b[1;3H\u{0301}".as_bytes());
+ assert_eq!(parser.screen().contents(), "ab́cdefg");
+ parser.process("\x1b[1;2Hb\x1b[1;8H".as_bytes());
+ assert_eq!(parser.screen().contents(), "abcdefg");
+ let screen = parser.screen().clone();
+ parser.process(b"\x1bcabcdefg");
+ assert_eq!(parser.screen().contents_diff(&screen), b"\x1b[m");
}
#[test]