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.
This commit is contained in:
parent
cc705b8012
commit
181ce63183
@ -2,7 +2,8 @@ mod buffer;
|
|||||||
|
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::io::{
|
use crate::io::{
|
||||||
self, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
|
self, uninlined_slow_read_byte, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom,
|
||||||
|
SizeHint, SpecReadByte, DEFAULT_BUF_SIZE,
|
||||||
};
|
};
|
||||||
use buffer::Buffer;
|
use buffer::Buffer;
|
||||||
|
|
||||||
@ -259,6 +260,22 @@ impl<R: ?Sized + Seek> BufReader<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R> SpecReadByte for BufReader<R>
|
||||||
|
where
|
||||||
|
Self: Read,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn spec_read_byte(&mut self) -> Option<io::Result<u8>> {
|
||||||
|
let mut byte = 0;
|
||||||
|
if self.buf.consume_with(1, |claimed| byte = claimed[0]) {
|
||||||
|
return Some(Ok(byte));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback case, only reached once per buffer refill.
|
||||||
|
uninlined_slow_read_byte(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<R: ?Sized + Read> Read for BufReader<R> {
|
impl<R: ?Sized + Read> Read for BufReader<R> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
@ -269,10 +286,8 @@ impl<R: ?Sized + Read> Read for BufReader<R> {
|
|||||||
self.discard_buffer();
|
self.discard_buffer();
|
||||||
return self.inner.read(buf);
|
return self.inner.read(buf);
|
||||||
}
|
}
|
||||||
let nread = {
|
let mut rem = self.fill_buf()?;
|
||||||
let mut rem = self.fill_buf()?;
|
let nread = rem.read(buf)?;
|
||||||
rem.read(buf)?
|
|
||||||
};
|
|
||||||
self.consume(nread);
|
self.consume(nread);
|
||||||
Ok(nread)
|
Ok(nread)
|
||||||
}
|
}
|
||||||
|
@ -2777,17 +2777,10 @@ pub struct Bytes<R> {
|
|||||||
impl<R: Read> Iterator for Bytes<R> {
|
impl<R: Read> Iterator for Bytes<R> {
|
||||||
type Item = Result<u8>;
|
type Item = Result<u8>;
|
||||||
|
|
||||||
#[inline]
|
// Not `#[inline]`. This function gets inlined even without it, but having
|
||||||
|
// the inline annotation can result in worse code generation. See #116785.
|
||||||
fn next(&mut self) -> Option<Result<u8>> {
|
fn next(&mut self) -> Option<Result<u8>> {
|
||||||
let mut byte = 0;
|
SpecReadByte::spec_read_byte(&mut self.inner)
|
||||||
loop {
|
|
||||||
return match self.inner.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)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -2796,6 +2789,43 @@ impl<R: Read> Iterator for Bytes<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For the specialization of `Bytes::next`.
|
||||||
|
trait SpecReadByte {
|
||||||
|
fn spec_read_byte(&mut self) -> Option<Result<u8>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> SpecReadByte for R
|
||||||
|
where
|
||||||
|
Self: Read,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
default fn spec_read_byte(&mut self) -> Option<Result<u8>> {
|
||||||
|
inlined_slow_read_byte(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a single byte in a slow, generic way. This is used by the default
|
||||||
|
/// `spec_read_byte`.
|
||||||
|
#[inline]
|
||||||
|
fn inlined_slow_read_byte<R: Read>(reader: &mut R) -> Option<Result<u8>> {
|
||||||
|
let mut byte = 0;
|
||||||
|
loop {
|
||||||
|
return match reader.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)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by `BufReader::spec_read_byte`, for which the `inline(ever)` is
|
||||||
|
// important.
|
||||||
|
#[inline(never)]
|
||||||
|
fn uninlined_slow_read_byte<R: Read>(reader: &mut R) -> Option<Result<u8>> {
|
||||||
|
inlined_slow_read_byte(reader)
|
||||||
|
}
|
||||||
|
|
||||||
trait SizeHint {
|
trait SizeHint {
|
||||||
fn lower_bound(&self) -> usize;
|
fn lower_bound(&self) -> usize;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user