wc: improve the perf of '-m'

This commit is contained in:
Sylvestre Ledru
2025-09-20 19:28:10 +02:00
parent cb594452d9
commit ab7c2fd087
4 changed files with 60 additions and 5 deletions
Generated
+1
View File
@@ -4112,6 +4112,7 @@ dependencies = [
"divan",
"fluent",
"libc",
"memchr",
"nix",
"tempfile",
"thiserror 2.0.16",
+1 -5
View File
@@ -1631,6 +1631,7 @@ dependencies = [
"clap",
"fluent",
"libc",
"memchr",
"nix",
"thiserror",
"unicode-width",
@@ -1710,7 +1711,6 @@ version = "0.2.2"
dependencies = [
"proc-macro2",
"quote",
"uuhelp_parser",
]
[[package]]
@@ -1725,10 +1725,6 @@ dependencies = [
"uucore",
]
[[package]]
name = "uuhelp_parser"
version = "0.2.2"
[[package]]
name = "version_check"
version = "0.9.5"
+1
View File
@@ -21,6 +21,7 @@ path = "src/wc.rs"
clap = { workspace = true }
uucore = { workspace = true, features = ["parser", "pipes", "quoting-style"] }
bytecount = { workspace = true, features = ["runtime-dispatch-simd"] }
memchr = { workspace = true }
thiserror = { workspace = true }
unicode-width = { workspace = true }
fluent = { workspace = true }
+57
View File
@@ -229,6 +229,63 @@ pub(crate) fn count_bytes_chars_and_lines_fast<
const COUNT_LINES: bool,
>(
handle: &mut R,
) -> (WordCount, Option<io::Error>) {
// Use specialized implementations for common cases
match (COUNT_BYTES, COUNT_CHARS, COUNT_LINES) {
// Lines only - use memchr for fastest line counting
(false, false, true) => count_lines_only_fast(handle),
// Bytes + Lines - optimize using bytecount and avoid double counting
(true, false, true) => count_bytes_and_lines_fast(handle),
// Default implementation for other cases
_ => {
count_bytes_chars_and_lines_generic::<R, COUNT_BYTES, COUNT_CHARS, COUNT_LINES>(handle)
}
}
}
/// Specialized fast line counting using memchr
fn count_lines_only_fast<R: Read>(handle: &mut R) -> (WordCount, Option<io::Error>) {
let mut total = WordCount::default();
let buf: &mut [u8] = &mut AlignedBuffer::default().data;
loop {
match handle.read(buf) {
Ok(0) => return (total, None),
Ok(n) => {
total.lines += memchr::memchr_iter(b'\n', &buf[..n]).count();
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => (),
Err(e) => return (total, Some(e)),
}
}
}
/// Specialized fast byte and line counting using bytecount
fn count_bytes_and_lines_fast<R: Read>(handle: &mut R) -> (WordCount, Option<io::Error>) {
let mut total = WordCount::default();
let buf: &mut [u8] = &mut AlignedBuffer::default().data;
loop {
match handle.read(buf) {
Ok(0) => return (total, None),
Ok(n) => {
total.bytes += n;
total.lines += bytecount::count(&buf[..n], b'\n');
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => (),
Err(e) => return (total, Some(e)),
}
}
}
/// Generic implementation for mixed counting
fn count_bytes_chars_and_lines_generic<
R: Read,
const COUNT_BYTES: bool,
const COUNT_CHARS: bool,
const COUNT_LINES: bool,
>(
handle: &mut R,
) -> (WordCount, Option<io::Error>) {
let mut total = WordCount::default();
let buf: &mut [u8] = &mut AlignedBuffer::default().data;