Skip to content

Commit

Permalink
Specialize Bytes<R>::next when R is a BufReader.
Browse files Browse the repository at this point in the history
This reduces the runtime for a simple program using `Bytes::next` to
iterate through a file from 220ms to 70ms on my Linux box.
  • Loading branch information
nnethercote committed Oct 16, 2023
1 parent 99592fd commit b02eb6e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 8 deletions.
31 changes: 27 additions & 4 deletions library/std/src/io/buffered/bufreader.rs
Expand Up @@ -259,6 +259,31 @@ impl<R: ?Sized + Seek> BufReader<R> {
}
}

impl<R> BufReader<R>
where
Self: Read,
{
#[inline]
pub(crate) fn read_byte(&mut self) -> Option<io::Result<u8>> {
#[cold]
fn slow_path<R>(this: &mut BufReader<R>) -> Option<io::Result<u8>>
where
BufReader<R>: Read,
{
use crate::io::SpecReadByte;

this.slow_read_byte()
}

let mut byte = 0;
if self.buf.consume_with(1, |claimed| byte = claimed[0]) {
return Some(Ok(byte));
}

slow_path(self)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<R: ?Sized + Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
Expand All @@ -269,10 +294,8 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
self.discard_buffer();
return self.inner.read(buf);
}
let nread = {
let mut rem = self.fill_buf()?;
rem.read(buf)?
};
let mut rem = self.fill_buf()?;
let nread = rem.read(buf)?;
self.consume(nread);
Ok(nread)
}
Expand Down
35 changes: 31 additions & 4 deletions library/std/src/io/mod.rs
Expand Up @@ -2777,22 +2777,49 @@ pub struct Bytes<R> {
impl<R: Read> Iterator for Bytes<R> {
type Item = Result<u8>;

#[inline]
fn next(&mut self) -> Option<Result<u8>> {
SpecReadByte::spec_read_byte(&mut self.inner)
}

fn size_hint(&self) -> (usize, Option<usize>) {
SizeHint::size_hint(&self.inner)
}
}

trait SpecReadByte {
fn spec_read_byte(&mut self) -> Option<Result<u8>>;
fn slow_read_byte(&mut self) -> Option<Result<u8>>;
}

impl<R> SpecReadByte for R
where
Self: Read,
{
default fn spec_read_byte(&mut self) -> Option<Result<u8>> {
self.slow_read_byte()
}

#[inline]
fn slow_read_byte(&mut self) -> Option<Result<u8>> {
let mut byte = 0;
loop {
return match self.inner.read(slice::from_mut(&mut byte)) {
return match self.read(slice::from_mut(&mut byte)) {
Ok(0) => None,
Ok(..) => Some(Ok(byte)),
Err(ref e) if e.is_interrupted() => continue,
Err(e) => Some(Err(e)),
};
}
}
}

impl<R> SpecReadByte for BufReader<R>
where
Self: Read,
{
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
SizeHint::size_hint(&self.inner)
fn spec_read_byte(&mut self) -> Option<Result<u8>> {
self.read_byte()
}
}

Expand Down

0 comments on commit b02eb6e

Please sign in to comment.