Skip to content

Commit

Permalink
wc: count_fast optimization using seek
Browse files Browse the repository at this point in the history
  • Loading branch information
zhitkoff committed Dec 2, 2023
1 parent ff18f13 commit ba83d43
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/uu/wc/src/count_fast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::WordCountable;

#[cfg(any(target_os = "linux", target_os = "android"))]
use std::fs::OpenOptions;
use std::io::{self, ErrorKind, Read};
use std::io::{self, ErrorKind, Read, Seek, SeekFrom};

#[cfg(unix)]
use libc::{sysconf, S_IFREG, _SC_PAGESIZE};
Expand Down Expand Up @@ -100,7 +100,7 @@ pub(crate) fn count_bytes_fast<T: WordCountable>(handle: &mut T) -> (usize, Opti
// would count up only to a couple of bytes.
// This condition usually occurs for files in pseudo-filesystems like /proc, /sys
// that report `st_size` in the multiples of system page size.
// In such cases - fall back on full read
// In such cases - attempt `seek()` for the end of file
//
// And finally a special case of input redirection in *nix shell:
// `( wc -c ; wc -c ) < file` should return
Expand All @@ -126,6 +126,10 @@ pub(crate) fn count_bytes_fast<T: WordCountable>(handle: &mut T) -> (usize, Opti
// regular file or file from /proc, /sys and similar pseudo-filesystems
// with size that is NOT a multiple of system page size
return (stat.st_size as usize, None);
} else if let Some(file) = handle.inner_file() {
if let Ok(n) = file.seek(SeekFrom::End(0)) {
return (n as usize, None);
}
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
Expand Down
9 changes: 9 additions & 0 deletions src/uu/wc/src/countable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ use std::os::unix::io::AsRawFd;
pub trait WordCountable: AsRawFd + Read {
type Buffered: BufRead;
fn buffered(self) -> Self::Buffered;
fn inner_file(&mut self) -> Option<&mut File>;
}

#[cfg(not(unix))]
pub trait WordCountable: Read {
type Buffered: BufRead;
fn buffered(self) -> Self::Buffered;
fn inner_file(&mut self) -> Option<&mut File>;
}

impl WordCountable for StdinLock<'_> {
Expand All @@ -31,6 +33,9 @@ impl WordCountable for StdinLock<'_> {
fn buffered(self) -> Self::Buffered {
self
}
fn inner_file(&mut self) -> Option<&mut File> {
None
}
}

impl WordCountable for File {
Expand All @@ -39,4 +44,8 @@ impl WordCountable for File {
fn buffered(self) -> Self::Buffered {
BufReader::new(self)
}

fn inner_file(&mut self) -> Option<&mut File> {
Some(self)
}
}

0 comments on commit ba83d43

Please sign in to comment.