diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2021-11-03 14:46:11 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2021-11-03 14:46:11 +0100 |
commit | a3c77e3fff771b168b53bd9b3a69c31a6775857b (patch) | |
tree | 3432802f102b435c9b5740a65c5bb73734dc7d87 /buffered-reader | |
parent | bb4d049aab46ba0303d7e7d683f836f4ea9d5aa6 (diff) |
buffered-reader: Recycle buffers.
- Previously, we spent a considerable amount of time callocing new
buffers.
Diffstat (limited to 'buffered-reader')
-rw-r--r-- | buffered-reader/src/generic.rs | 16 | ||||
-rw-r--r-- | buffered-reader/src/lib.rs | 9 |
2 files changed, 21 insertions, 4 deletions
diff --git a/buffered-reader/src/generic.rs b/buffered-reader/src/generic.rs index eed96d5e..f54fe6b2 100644 --- a/buffered-reader/src/generic.rs +++ b/buffered-reader/src/generic.rs @@ -12,9 +12,11 @@ use super::*; /// [`Memory`]. Both are more efficient than `Generic`. /// pub struct Generic<T: io::Read + Send + Sync, C: fmt::Debug + Sync + Send> { - buffer: Option<Box<[u8]>>, + buffer: Option<Vec<u8>>, // The next byte to read in the buffer. cursor: usize, + /// Currently unused buffer. + unused_buffer: Option<Vec<u8>>, // The preferred chunk size. This is just a hint. preferred_chunk_size: usize, // The wrapped reader. @@ -71,6 +73,7 @@ impl<T: io::Read + Send + Sync, C: fmt::Debug + Sync + Send> Generic<T, C> { Generic { buffer: None, cursor: 0, + unused_buffer: None, preferred_chunk_size: if let Some(s) = preferred_chunk_size { s } else { DEFAULT_BUF_SIZE }, @@ -135,7 +138,12 @@ impl<T: io::Read + Send + Sync, C: fmt::Debug + Sync + Send> Generic<T, C> { DEFAULT_BUF_SIZE, 2 * self.preferred_chunk_size), amount); - let mut buffer_new : Vec<u8> = vec![0u8; capacity]; + let mut buffer_new = self.unused_buffer.take() + .map(|mut v| { + vec_resize(&mut v, capacity); + v + }) + .unwrap_or_else(|| vec![0u8; capacity]); let mut amount_read = 0; while amount_buffered + amount_read < amount { @@ -170,9 +178,9 @@ impl<T: io::Read + Send + Sync, C: fmt::Debug + Sync + Send> Generic<T, C> { } vec_truncate(&mut buffer_new, amount_buffered + amount_read); - buffer_new.shrink_to_fit(); - self.buffer = Some(buffer_new.into_boxed_slice()); + self.unused_buffer = self.buffer.take(); + self.buffer = Some(buffer_new); self.cursor = 0; } } diff --git a/buffered-reader/src/lib.rs b/buffered-reader/src/lib.rs index 89b897ea..e973af4e 100644 --- a/buffered-reader/src/lib.rs +++ b/buffered-reader/src/lib.rs @@ -301,6 +301,15 @@ fn vec_truncate(v: &mut Vec<u8>, len: usize) { } } +/// Like `Vec<u8>::resize`, but fast in debug builds. +fn vec_resize(v: &mut Vec<u8>, new_size: usize) { + if v.len() < new_size { + v.resize(new_size, 0); + } else { + vec_truncate(v, new_size); + } +} + /// The generic `BufferReader` interface. pub trait BufferedReader<C> : io::Read + fmt::Debug + fmt::Display + Send + Sync where C: fmt::Debug + Send + Sync |