File tree Expand file tree Collapse file tree 3 files changed +47
-17
lines changed Expand file tree Collapse file tree 3 files changed +47
-17
lines changed Original file line number Diff line number Diff line change @@ -271,6 +271,20 @@ impl<R: Read> Read for BufReader<R> {
271271 Ok ( nread)
272272 }
273273
274+ // Small read_exacts from a BufReader are extremely common when used with a deserializer.
275+ // The default implementation calls read in a loop, which results in surprisingly poor code
276+ // generation for the common path where the buffer has enough bytes to fill the passed-in
277+ // buffer.
278+ fn read_exact ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < ( ) > {
279+ if self . buffer ( ) . len ( ) >= buf. len ( ) {
280+ buf. copy_from_slice ( & self . buffer ( ) [ ..buf. len ( ) ] ) ;
281+ self . consume ( buf. len ( ) ) ;
282+ return Ok ( ( ) ) ;
283+ }
284+
285+ crate :: io:: default_read_exact ( self , buf)
286+ }
287+
274288 fn read_vectored ( & mut self , bufs : & mut [ IoSliceMut < ' _ > ] ) -> io:: Result < usize > {
275289 let total_len = bufs. iter ( ) . map ( |b| b. len ( ) ) . sum :: < usize > ( ) ;
276290 if self . pos == self . cap && total_len >= self . buf . len ( ) {
Original file line number Diff line number Diff line change @@ -443,6 +443,18 @@ fn bench_buffered_reader(b: &mut test::Bencher) {
443443 b. iter ( || BufReader :: new ( io:: empty ( ) ) ) ;
444444}
445445
446+ #[ bench]
447+ fn bench_buffered_reader_small_reads ( b : & mut test:: Bencher ) {
448+ let data = ( 0 ..u8:: MAX ) . cycle ( ) . take ( 1024 * 4 ) . collect :: < Vec < _ > > ( ) ;
449+ b. iter ( || {
450+ let mut reader = BufReader :: new ( & data[ ..] ) ;
451+ let mut buf = [ 0u8 ; 4 ] ;
452+ for _ in 0 ..1024 {
453+ reader. read_exact ( & mut buf) . unwrap ( ) ;
454+ }
455+ } ) ;
456+ }
457+
446458#[ bench]
447459fn bench_buffered_writer ( b : & mut test:: Bencher ) {
448460 b. iter ( || BufWriter :: new ( io:: sink ( ) ) ) ;
Original file line number Diff line number Diff line change @@ -416,6 +416,25 @@ where
416416 write ( buf)
417417}
418418
419+ pub ( crate ) fn default_read_exact < R : Read + ?Sized > ( this : & mut R , mut buf : & mut [ u8 ] ) -> Result < ( ) > {
420+ while !buf. is_empty ( ) {
421+ match this. read ( buf) {
422+ Ok ( 0 ) => break ,
423+ Ok ( n) => {
424+ let tmp = buf;
425+ buf = & mut tmp[ n..] ;
426+ }
427+ Err ( ref e) if e. kind ( ) == ErrorKind :: Interrupted => { }
428+ Err ( e) => return Err ( e) ,
429+ }
430+ }
431+ if !buf. is_empty ( ) {
432+ Err ( Error :: new ( ErrorKind :: UnexpectedEof , "failed to fill whole buffer" ) )
433+ } else {
434+ Ok ( ( ) )
435+ }
436+ }
437+
419438/// The `Read` trait allows for reading bytes from a source.
420439///
421440/// Implementors of the `Read` trait are called 'readers'.
@@ -766,23 +785,8 @@ pub trait Read {
766785 /// }
767786 /// ```
768787 #[ stable( feature = "read_exact" , since = "1.6.0" ) ]
769- fn read_exact ( & mut self , mut buf : & mut [ u8 ] ) -> Result < ( ) > {
770- while !buf. is_empty ( ) {
771- match self . read ( buf) {
772- Ok ( 0 ) => break ,
773- Ok ( n) => {
774- let tmp = buf;
775- buf = & mut tmp[ n..] ;
776- }
777- Err ( ref e) if e. kind ( ) == ErrorKind :: Interrupted => { }
778- Err ( e) => return Err ( e) ,
779- }
780- }
781- if !buf. is_empty ( ) {
782- Err ( Error :: new ( ErrorKind :: UnexpectedEof , "failed to fill whole buffer" ) )
783- } else {
784- Ok ( ( ) )
785- }
788+ fn read_exact ( & mut self , buf : & mut [ u8 ] ) -> Result < ( ) > {
789+ default_read_exact ( self , buf)
786790 }
787791
788792 /// Creates a "by reference" adaptor for this instance of `Read`.
You can’t perform that action at this time.
0 commit comments