Skip to content

Commit b02eb6e

Browse files
committed
Specialize Bytes<R>::next when R is a BufReader.
This reduces the runtime for a simple program using `Bytes::next` to iterate through a file from 220ms to 70ms on my Linux box.
1 parent 99592fd commit b02eb6e

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

library/std/src/io/buffered/bufreader.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,31 @@ impl<R: ?Sized + Seek> BufReader<R> {
259259
}
260260
}
261261

262+
impl<R> BufReader<R>
263+
where
264+
Self: Read,
265+
{
266+
#[inline]
267+
pub(crate) fn read_byte(&mut self) -> Option<io::Result<u8>> {
268+
#[cold]
269+
fn slow_path<R>(this: &mut BufReader<R>) -> Option<io::Result<u8>>
270+
where
271+
BufReader<R>: Read,
272+
{
273+
use crate::io::SpecReadByte;
274+
275+
this.slow_read_byte()
276+
}
277+
278+
let mut byte = 0;
279+
if self.buf.consume_with(1, |claimed| byte = claimed[0]) {
280+
return Some(Ok(byte));
281+
}
282+
283+
slow_path(self)
284+
}
285+
}
286+
262287
#[stable(feature = "rust1", since = "1.0.0")]
263288
impl<R: ?Sized + Read> Read for BufReader<R> {
264289
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@@ -269,10 +294,8 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
269294
self.discard_buffer();
270295
return self.inner.read(buf);
271296
}
272-
let nread = {
273-
let mut rem = self.fill_buf()?;
274-
rem.read(buf)?
275-
};
297+
let mut rem = self.fill_buf()?;
298+
let nread = rem.read(buf)?;
276299
self.consume(nread);
277300
Ok(nread)
278301
}

library/std/src/io/mod.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,22 +2777,49 @@ pub struct Bytes<R> {
27772777
impl<R: Read> Iterator for Bytes<R> {
27782778
type Item = Result<u8>;
27792779

2780-
#[inline]
27812780
fn next(&mut self) -> Option<Result<u8>> {
2781+
SpecReadByte::spec_read_byte(&mut self.inner)
2782+
}
2783+
2784+
fn size_hint(&self) -> (usize, Option<usize>) {
2785+
SizeHint::size_hint(&self.inner)
2786+
}
2787+
}
2788+
2789+
trait SpecReadByte {
2790+
fn spec_read_byte(&mut self) -> Option<Result<u8>>;
2791+
fn slow_read_byte(&mut self) -> Option<Result<u8>>;
2792+
}
2793+
2794+
impl<R> SpecReadByte for R
2795+
where
2796+
Self: Read,
2797+
{
2798+
default fn spec_read_byte(&mut self) -> Option<Result<u8>> {
2799+
self.slow_read_byte()
2800+
}
2801+
2802+
#[inline]
2803+
fn slow_read_byte(&mut self) -> Option<Result<u8>> {
27822804
let mut byte = 0;
27832805
loop {
2784-
return match self.inner.read(slice::from_mut(&mut byte)) {
2806+
return match self.read(slice::from_mut(&mut byte)) {
27852807
Ok(0) => None,
27862808
Ok(..) => Some(Ok(byte)),
27872809
Err(ref e) if e.is_interrupted() => continue,
27882810
Err(e) => Some(Err(e)),
27892811
};
27902812
}
27912813
}
2814+
}
27922815

2816+
impl<R> SpecReadByte for BufReader<R>
2817+
where
2818+
Self: Read,
2819+
{
27932820
#[inline]
2794-
fn size_hint(&self) -> (usize, Option<usize>) {
2795-
SizeHint::size_hint(&self.inner)
2821+
fn spec_read_byte(&mut self) -> Option<Result<u8>> {
2822+
self.read_byte()
27962823
}
27972824
}
27982825

0 commit comments

Comments
 (0)