From 300eb041b38e313208e3197538a922095a99b723 Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Thu, 1 Feb 2024 07:02:11 -0500 Subject: [PATCH] Copy only unread bytes in BytesMut::reserve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When reserving extra space in the Vec representation, there may not be enough space to efficiently reuse the buffer. Currently, the entire buffer is copied, including bytes that have already been read. Instead, this change copies only the unread bytes to the beginning of the new buffer. As a result, fewer bytes are copied and there is more unused capacity. It's important to note that the size of the new buffer will still be double the size of the current buffer, including bytes already read. That has not changed. Before this change: ``` read unused capacity │ │ ─┴─ ──┴── old buffer: ░░░████████░░░░░ new buffer: ░░░████████░░░░░░░░░░░░░░░░░░░░░ ─┬─ ──┬────────────────── │ │ read unused capacity ``` After this change: ``` read unused capacity │ │ ─┴─ ──┴── old buffer: ░░░████████░░░░░ new buffer: ████████░░░░░░░░░░░░░░░░░░░░░░░░ ──┬───────────────────── │ unused capacity ``` --- src/bytes_mut.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/bytes_mut.rs b/src/bytes_mut.rs index 8783ae7f3..31c51e347 100644 --- a/src/bytes_mut.rs +++ b/src/bytes_mut.rs @@ -629,14 +629,21 @@ impl BytesMut { } else { // Not enough space, or reusing might be too much overhead: // allocate more space! - let mut v = - ManuallyDrop::new(rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off)); - v.reserve(additional); - - // Update the info - self.ptr = vptr(v.as_mut_ptr().add(off)); - self.len = v.len() - off; - self.cap = v.capacity() - off; + let request = len.checked_add(additional).expect("overflow"); + + // New capacity should be at least double the buffer size + let new_cap = (self.cap + off) + .checked_shl(1) + .map(|x| cmp::max(x, request)) + .unwrap_or(request); + + // Copy the current buffer into a new Vec with the desired capacity. + let mut new = ManuallyDrop::new(Vec::with_capacity(new_cap)); + ptr::copy_nonoverlapping(self.ptr.as_ptr(), new.as_mut_ptr(), self.len); + drop(rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off)); + self.ptr = vptr(new.as_mut_ptr()); + self.cap = new.capacity(); + self.set_vec_pos(0, prev); } return;