summaryrefslogtreecommitdiffstats
path: root/buffered-reader
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2021-11-03 14:46:11 +0100
committerJustus Winter <justus@sequoia-pgp.org>2021-11-03 14:46:11 +0100
commita3c77e3fff771b168b53bd9b3a69c31a6775857b (patch)
tree3432802f102b435c9b5740a65c5bb73734dc7d87 /buffered-reader
parentbb4d049aab46ba0303d7e7d683f836f4ea9d5aa6 (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.rs16
-rw-r--r--buffered-reader/src/lib.rs9
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