Skip to content

Commit

Permalink
10% speedup
Browse files Browse the repository at this point in the history
By avoiding some copying / memory allocations in a hot path.
  • Loading branch information
walles committed Aug 13, 2023
1 parent 968d0f0 commit 0fb44b8
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 17 deletions.
32 changes: 21 additions & 11 deletions src/ansi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,26 @@ impl AnsiStyle {
}
}

pub fn without_ansi_escape_codes(input: &[u8]) -> Vec<u8> {
// Modifies the input so that all ANSI escape codes are removed
pub fn remove_ansi_escape_codes(line: &mut Vec<u8>) {
enum State {
Normal,
Escape,
EscapeBracket,
}

let mut return_me = Vec::with_capacity(input.len());
let mut state = State::Normal;
let mut next_index_without_ansi = 0usize;

for byte in input {
let byte = byte.to_owned();
for index in 0..line.len() {
let byte = line[index];
match state {
State::Normal => {
if byte == b'\x1b' {
state = State::Escape;
} else {
return_me.push(byte);
line[next_index_without_ansi] = byte;
next_index_without_ansi += 1;
}
}
State::Escape => {
Expand All @@ -98,8 +100,10 @@ pub fn without_ansi_escape_codes(input: &[u8]) -> Vec<u8> {

// Push the characters that we thought were the escape
// sequence's opening
return_me.push(b'\x1b');
return_me.push(byte);
line[next_index_without_ansi] = b'\x1b';
next_index_without_ansi += 1;
line[next_index_without_ansi] = byte;
next_index_without_ansi += 1;
}
}
State::EscapeBracket => {
Expand All @@ -111,7 +115,7 @@ pub fn without_ansi_escape_codes(input: &[u8]) -> Vec<u8> {
}
}

return return_me;
line.truncate(next_index_without_ansi);
}

#[cfg(test)]
Expand All @@ -123,16 +127,22 @@ mod tests {

#[test]
fn test_non_sgr() {
assert_eq!(without_ansi_escape_codes(b"hel\x1b[0Klo"), b"hello");
let mut line = b"hel\x1b[0Klo".to_vec();
remove_ansi_escape_codes(&mut line);
assert_eq!(line, b"hello");
}

#[test]
fn test_sgr() {
assert_eq!(without_ansi_escape_codes(b"hel\x1b[33mlo"), b"hello");
let mut line = b"hel\x1b[33mlo".to_vec();
remove_ansi_escape_codes(&mut line);
assert_eq!(line, b"hello");
}

#[test]
fn test_multi_sgr() {
assert_eq!(without_ansi_escape_codes(b"hel\x1b[33;34mlo"), b"hello");
let mut line = b"hel\x1b[33;34mlo".to_vec();
remove_ansi_escape_codes(&mut line);
assert_eq!(line, b"hello");
}
}
8 changes: 4 additions & 4 deletions src/line_collector.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ansi::without_ansi_escape_codes;
use crate::ansi::remove_ansi_escape_codes;
use crate::commit_line::format_commit_line;
use crate::io::ErrorKind;
use crate::refiner::to_highlighted_tokens;
Expand Down Expand Up @@ -391,11 +391,11 @@ impl LineCollector {
}

/// The line parameter is expected *not* to end in a newline
pub fn consume_line(&mut self, line: &[u8]) {
pub fn consume_line(&mut self, line: &mut Vec<u8>) {
// Strip out incoming ANSI formatting. This enables us to highlight
// already-colored input.
let line = without_ansi_escape_codes(line);
let line = String::from_utf8_lossy(&line);
remove_ansi_escape_codes(line);
let line = String::from_utf8_lossy(line);

if line.starts_with("diff") {
self.diff_seen = true;
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn highlight_diff<W: io::Write + Send + 'static>(input: &mut dyn io::Read, outpu
// End of stream
if !line.is_empty() {
// Stuff found on the last line without a trailing newline
line_collector.consume_line(&line);
line_collector.consume_line(&mut line);
}
break;
}
Expand All @@ -103,7 +103,7 @@ fn highlight_diff<W: io::Write + Send + 'static>(input: &mut dyn io::Read, outpu
}

// Line finished, consume it!
line_collector.consume_line(&line);
line_collector.consume_line(&mut line);
line.clear();
continue;
}
Expand Down

0 comments on commit 0fb44b8

Please sign in to comment.