about summary refs log tree commit diff
path: root/library/std/src/io/buffered/bufreader/buffer.rs
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2022-10-06 20:09:54 -0400
committerBen Kimock <kimockb@gmail.com>2022-10-06 23:31:57 -0400
commit95ae993bd86b97aff9a27498f2187fef431cab58 (patch)
tree17e7425d97da5eb8d9ff232b72031c36cea103ec /library/std/src/io/buffered/bufreader/buffer.rs
parent0ca356586fed56002b10920fd21ddf6fb12de797 (diff)
downloadrust-95ae993bd86b97aff9a27498f2187fef431cab58.tar.gz
rust-95ae993bd86b97aff9a27498f2187fef431cab58.zip
Avoid defensive re-initialization of the BufReader buffer
Diffstat (limited to 'library/std/src/io/buffered/bufreader/buffer.rs')
-rw-r--r--library/std/src/io/buffered/bufreader/buffer.rs19
1 files changed, 16 insertions, 3 deletions
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
index 867c22c6041..e9e29d60ca2 100644
--- a/library/std/src/io/buffered/bufreader/buffer.rs
+++ b/library/std/src/io/buffered/bufreader/buffer.rs
@@ -20,13 +20,19 @@ pub struct Buffer {
     // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
     // initialized with bytes from a read.
     filled: usize,
+    // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we
+    // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its
+    // defensive initialization as possible. Note that while this often the same as `filled`, it
+    // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and
+    // omitting this is a huge perf regression for `Read` impls that do not.
+    initialized: usize,
 }
 
 impl Buffer {
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
         let buf = Box::new_uninit_slice(capacity);
-        Self { buf, pos: 0, filled: 0 }
+        Self { buf, pos: 0, filled: 0, initialized: 0 }
     }
 
     #[inline]
@@ -51,6 +57,12 @@ impl Buffer {
         self.pos
     }
 
+    // This is only used by a test which asserts that the initialization-tracking is correct.
+    #[cfg(test)]
+    pub fn initialized(&self) -> usize {
+        self.initialized
+    }
+
     #[inline]
     pub fn discard_buffer(&mut self) {
         self.pos = 0;
@@ -96,13 +108,14 @@ impl Buffer {
             let mut buf = BorrowedBuf::from(&mut *self.buf);
             // SAFETY: `self.filled` bytes will always have been initialized.
             unsafe {
-                buf.set_init(self.filled);
+                buf.set_init(self.initialized);
             }
 
             reader.read_buf(buf.unfilled())?;
 
-            self.filled = buf.len();
             self.pos = 0;
+            self.filled = buf.len();
+            self.initialized = buf.init_len();
         }
         Ok(self.buffer())
     }