Skip to content

Commit af27562

Browse files
authored
Merge pull request #8815 from sylvestre/perf-unexpand
unexpand: improve performances (1.50 faster than GNU)
2 parents 788bf92 + 687716c commit af27562

File tree

1 file changed

+41
-1
lines changed

1 file changed

+41
-1
lines changed

src/uu/unexpand/src/unexpand.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,12 +313,52 @@ fn unexpand_line(
313313
lastcol: usize,
314314
ts: &[usize],
315315
) -> UResult<()> {
316+
// Fast path: if we're not converting all spaces (-a flag not set)
317+
// and the line doesn't start with spaces, just write it directly
318+
if !options.aflag && !buf.is_empty() && buf[0] != b' ' && buf[0] != b'\t' {
319+
output.write_all(buf)?;
320+
buf.truncate(0);
321+
return Ok(());
322+
}
323+
316324
let mut byte = 0; // offset into the buffer
317325
let mut col = 0; // the current column
318326
let mut scol = 0; // the start col for the current span, i.e., the already-printed width
319327
let mut init = true; // are we at the start of the line?
320328
let mut pctype = CharType::Other;
321329

330+
// Fast path for leading spaces in non-UTF8 mode: count consecutive spaces/tabs at start
331+
if !options.uflag && init && !options.aflag {
332+
// In default mode (not -a), we only convert leading spaces
333+
// So we can batch process them and then copy the rest
334+
while byte < buf.len() {
335+
match buf[byte] {
336+
b' ' => {
337+
col += 1;
338+
byte += 1;
339+
}
340+
b'\t' => {
341+
col += next_tabstop(ts, col).unwrap_or(1);
342+
byte += 1;
343+
pctype = CharType::Tab;
344+
}
345+
_ => break,
346+
}
347+
}
348+
349+
// If we found spaces/tabs, write them as tabs
350+
if byte > 0 {
351+
write_tabs(output, ts, 0, col, pctype == CharType::Tab, true, true)?;
352+
}
353+
354+
// Write the rest of the line directly (no more tab conversion needed)
355+
if byte < buf.len() {
356+
output.write_all(&buf[byte..])?;
357+
}
358+
buf.truncate(0);
359+
return Ok(());
360+
}
361+
322362
while byte < buf.len() {
323363
// when we have a finite number of columns, never convert past the last column
324364
if lastcol > 0 && col >= lastcol {
@@ -379,7 +419,6 @@ fn unexpand_line(
379419

380420
// write out anything remaining
381421
write_tabs(output, ts, scol, col, pctype == CharType::Tab, init, true)?;
382-
output.flush()?;
383422
buf.truncate(0); // clear out the buffer
384423

385424
Ok(())
@@ -407,6 +446,7 @@ fn unexpand(options: &Options) -> UResult<()> {
407446
unexpand_line(&mut buf, &mut output, options, lastcol, ts)?;
408447
}
409448
}
449+
output.flush()?;
410450
Ok(())
411451
}
412452

0 commit comments

Comments
 (0)