@@ -4,6 +4,7 @@ use crate::io::{
4
4
self , Error , ErrorKind , IntoInnerError , IoSlice , Seek , SeekFrom , Write , DEFAULT_BUF_SIZE ,
5
5
} ;
6
6
use crate :: mem;
7
+ use crate :: ptr;
7
8
8
9
/// Wraps a writer and buffers its output.
9
10
///
@@ -68,6 +69,10 @@ use crate::mem;
68
69
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
69
70
pub struct BufWriter < W : Write > {
70
71
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).
71
76
buf : Vec < u8 > ,
72
77
// #30888: If the inner writer panics in a call to write, we don't want to
73
78
// write the buffered data a second time in BufWriter's destructor. This
@@ -150,7 +155,11 @@ impl<W: Write> BufWriter<W> {
150
155
impl Drop for BufGuard < ' _ > {
151
156
fn drop ( & mut self ) {
152
157
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
+ }
154
163
}
155
164
}
156
165
}
@@ -183,7 +192,12 @@ impl<W: Write> BufWriter<W> {
183
192
pub ( super ) fn write_to_buf ( & mut self , buf : & [ u8 ] ) -> usize {
184
193
let available = self . buf . capacity ( ) - self . buf . len ( ) ;
185
194
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
+
187
201
amt_to_buffer
188
202
}
189
203
@@ -348,7 +362,13 @@ impl<W: Write> BufWriter<W> {
348
362
self . panicked = false ;
349
363
r
350
364
} 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
+
352
372
Ok ( buf. len ( ) )
353
373
}
354
374
}
@@ -373,10 +393,29 @@ impl<W: Write> BufWriter<W> {
373
393
self . panicked = false ;
374
394
r
375
395
} 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
+
377
403
Ok ( ( ) )
378
404
}
379
405
}
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
+ }
380
419
}
381
420
382
421
#[ unstable( feature = "bufwriter_into_raw_parts" , issue = "80690" ) ]
@@ -456,7 +495,11 @@ impl<W: Write> Write for BufWriter<W> {
456
495
// prevents pathological cases for other clients which *always* make writes of this size.
457
496
// See #72919 and #79930 for more info and a breadcrumb trail.
458
497
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
+
460
503
Ok ( buf. len ( ) )
461
504
} else {
462
505
self . flush_and_write ( buf)
@@ -471,7 +514,11 @@ impl<W: Write> Write for BufWriter<W> {
471
514
// prevents pathological cases for other clients which *always* make writes of this size.
472
515
// See #72919 and #79930 for more info and a breadcrumb trail.
473
516
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
+
475
522
Ok ( ( ) )
476
523
} else {
477
524
self . flush_and_write_all ( buf)
@@ -492,7 +539,13 @@ impl<W: Write> Write for BufWriter<W> {
492
539
self . panicked = false ;
493
540
r
494
541
} 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
+
496
549
Ok ( total_len)
497
550
}
498
551
} else {
@@ -511,19 +564,29 @@ impl<W: Write> Write for BufWriter<W> {
511
564
self . panicked = false ;
512
565
return r;
513
566
} 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
+
515
574
buf. len ( )
516
575
}
517
576
} else {
518
577
return Ok ( 0 ) ;
519
578
} ;
520
579
debug_assert ! ( total_written != 0 ) ;
521
580
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
+
526
587
total_written += buf. len ( ) ;
588
+ } else {
589
+ break ;
527
590
}
528
591
}
529
592
Ok ( total_written)
0 commit comments