@@ -4,6 +4,7 @@ use crate::io::{
44 self , Error , ErrorKind , IntoInnerError , IoSlice , Seek , SeekFrom , Write , DEFAULT_BUF_SIZE ,
55} ;
66use crate :: mem;
7+ use crate :: ptr;
78
89/// Wraps a writer and buffers its output.
910///
@@ -68,6 +69,10 @@ use crate::mem;
6869#[ stable( feature = "rust1" , since = "1.0.0" ) ]
6970pub struct BufWriter < W : Write > {
7071 inner : Option < W > ,
72+ // The buffer. Avoid using this like a normal `Vec` in common code paths.
73+ // That is, don't use `buf.push`, `buf.extend_from_slice`, or any other
74+ // methods that require bounds checking or the like. This makes an enormous
75+ // difference to performance (we may want to stop using a `Vec` entirely).
7176 buf : Vec < u8 > ,
7277 // #30888: If the inner writer panics in a call to write, we don't want to
7378 // write the buffered data a second time in BufWriter's destructor. This
@@ -150,7 +155,11 @@ impl<W: Write> BufWriter<W> {
150155 impl Drop for BufGuard < ' _ > {
151156 fn drop ( & mut self ) {
152157 if self . written > 0 {
153- self . buffer . drain ( ..self . written ) ;
158+ if self . done ( ) {
159+ self . buffer . clear ( ) ;
160+ } else {
161+ self . buffer . drain ( ..self . written ) ;
162+ }
154163 }
155164 }
156165 }
@@ -183,7 +192,12 @@ impl<W: Write> BufWriter<W> {
183192 pub ( super ) fn write_to_buf ( & mut self , buf : & [ u8 ] ) -> usize {
184193 let available = self . buf . capacity ( ) - self . buf . len ( ) ;
185194 let amt_to_buffer = available. min ( buf. len ( ) ) ;
186- self . buf . extend_from_slice ( & buf[ ..amt_to_buffer] ) ;
195+
196+ // SAFETY: `amt_to_buffer` is <= buffer's spare capacity by construction.
197+ unsafe {
198+ self . write_to_buffer_unchecked ( & buf[ ..amt_to_buffer] ) ;
199+ }
200+
187201 amt_to_buffer
188202 }
189203
@@ -348,7 +362,13 @@ impl<W: Write> BufWriter<W> {
348362 self . panicked = false ;
349363 r
350364 } else {
351- self . buf . extend_from_slice ( buf) ;
365+ // SAFETY: We just called `self.flush_buf()`, so `self.buf.len()` is 0, and
366+ // we entered this else block because `buf.len() < self.buf.capacity()`.
367+ // Therefore, `self.buf.len() + buf.len() <= self.buf.capacity()`.
368+ unsafe {
369+ self . write_to_buffer_unchecked ( buf) ;
370+ }
371+
352372 Ok ( buf. len ( ) )
353373 }
354374 }
@@ -373,10 +393,29 @@ impl<W: Write> BufWriter<W> {
373393 self . panicked = false ;
374394 r
375395 } else {
376- self . buf . extend_from_slice ( buf) ;
396+ // SAFETY: We just called `self.flush_buf()`, so `self.buf.len()` is 0, and
397+ // we entered this else block because `buf.len() < self.buf.capacity()`.
398+ // Therefore, `self.buf.len() + buf.len() <= self.buf.capacity()`.
399+ unsafe {
400+ self . write_to_buffer_unchecked ( buf) ;
401+ }
402+
377403 Ok ( ( ) )
378404 }
379405 }
406+
407+ // SAFETY: Requires `self.buf.len() + buf.len() <= self.buf.capacity()`,
408+ // i.e., that input buffer length is less than or equal to spare capacity.
409+ #[ inline( always) ]
410+ unsafe fn write_to_buffer_unchecked ( & mut self , buf : & [ u8 ] ) {
411+ debug_assert ! ( self . buf. len( ) + buf. len( ) <= self . buf. capacity( ) ) ;
412+ let old_len = self . buf . len ( ) ;
413+ let buf_len = buf. len ( ) ;
414+ let src = buf. as_ptr ( ) ;
415+ let dst = self . buf . as_mut_ptr ( ) . add ( old_len) ;
416+ ptr:: copy_nonoverlapping ( src, dst, buf_len) ;
417+ self . buf . set_len ( old_len + buf_len) ;
418+ }
380419}
381420
382421#[ unstable( feature = "bufwriter_into_raw_parts" , issue = "80690" ) ]
@@ -456,7 +495,11 @@ impl<W: Write> Write for BufWriter<W> {
456495 // prevents pathological cases for other clients which *always* make writes of this size.
457496 // See #72919 and #79930 for more info and a breadcrumb trail.
458497 if self . buf . len ( ) + buf. len ( ) <= self . buf . capacity ( ) && buf. len ( ) != self . buf . capacity ( ) {
459- self . buf . extend_from_slice ( buf) ;
498+ // SAFETY: safe by above conditional.
499+ unsafe {
500+ self . write_to_buffer_unchecked ( buf) ;
501+ }
502+
460503 Ok ( buf. len ( ) )
461504 } else {
462505 self . flush_and_write ( buf)
@@ -471,7 +514,11 @@ impl<W: Write> Write for BufWriter<W> {
471514 // prevents pathological cases for other clients which *always* make writes of this size.
472515 // See #72919 and #79930 for more info and a breadcrumb trail.
473516 if self . buf . len ( ) + buf. len ( ) <= self . buf . capacity ( ) && buf. len ( ) != self . buf . capacity ( ) {
474- self . buf . extend_from_slice ( buf) ;
517+ // SAFETY: safe by above conditional.
518+ unsafe {
519+ self . write_to_buffer_unchecked ( buf) ;
520+ }
521+
475522 Ok ( ( ) )
476523 } else {
477524 self . flush_and_write_all ( buf)
@@ -492,7 +539,13 @@ impl<W: Write> Write for BufWriter<W> {
492539 self . panicked = false ;
493540 r
494541 } else {
495- bufs. iter ( ) . for_each ( |b| self . buf . extend_from_slice ( b) ) ;
542+ // SAFETY: We checked whether or not the spare capacity was large enough above. If
543+ // it was, then we're safe already. If it wasn't, we flushed, making sufficient
544+ // room for any input <= the buffer size, which includes this input.
545+ unsafe {
546+ bufs. iter ( ) . for_each ( |b| self . write_to_buffer_unchecked ( b) ) ;
547+ } ;
548+
496549 Ok ( total_len)
497550 }
498551 } else {
@@ -511,19 +564,29 @@ impl<W: Write> Write for BufWriter<W> {
511564 self . panicked = false ;
512565 return r;
513566 } else {
514- self . buf . extend_from_slice ( buf) ;
567+ // SAFETY: We checked whether or not the spare capacity was large enough above.
568+ // If it was, then we're safe already. If it wasn't, we flushed, making
569+ // sufficient room for any input <= the buffer size, which includes this input.
570+ unsafe {
571+ self . write_to_buffer_unchecked ( buf) ;
572+ }
573+
515574 buf. len ( )
516575 }
517576 } else {
518577 return Ok ( 0 ) ;
519578 } ;
520579 debug_assert ! ( total_written != 0 ) ;
521580 for buf in iter {
522- if self . buf . len ( ) + buf. len ( ) > self . buf . capacity ( ) {
523- break ;
524- } else {
525- self . buf . extend_from_slice ( buf) ;
581+ if self . buf . len ( ) + buf. len ( ) <= self . buf . capacity ( ) {
582+ // SAFETY: safe by above conditional.
583+ unsafe {
584+ self . write_to_buffer_unchecked ( buf) ;
585+ }
586+
526587 total_written += buf. len ( ) ;
588+ } else {
589+ break ;
527590 }
528591 }
529592 Ok ( total_written)
0 commit comments