From 8892f744d3da1d93126daa4f0270616861631fd9 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 5 Apr 2023 20:03:29 +0000 Subject: [PATCH 1/2] Fix condition in realloc() implementation of Vec Poolable and Realloc trait method implementations for Vec operate on the vector itself rather than its underlying buffer. This is why Poolable::capacity() implementation calls Vec::len() and Realloc::realloc() implementation uses Vec::resize() rather than Vec::reserve() or Vec::reserve_exact(). However, the condition checking whether the vector should be resized called Vec::len() rather than Vec::capacity(). Apparently it was an attempt to call Poolable::capacity(&self), but by default ambiguous call is resolved to Vec::capacity(). The problem is resolved by calling .len() explicitly. Regression test and assertions failing for byte-pool 0.2.2 are added. --- src/poolable.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/poolable.rs b/src/poolable.rs index 23fd0cc..70e0814 100644 --- a/src/poolable.rs +++ b/src/poolable.rs @@ -41,11 +41,13 @@ impl Realloc for Vec { use std::cmp::Ordering::*; assert!(new_size > 0); - match new_size.cmp(&self.capacity()) { + match new_size.cmp(&self.len()) { Greater => self.resize(new_size, T::default()), Less => { self.truncate(new_size); + debug_assert_eq!(self.len(), new_size); self.shrink_to_fit(); + debug_assert_eq!(self.capacity(), new_size); } Equal => {} } @@ -74,3 +76,25 @@ where } } } + +#[cfg(test)] +mod tests { + use super::*; + + /// Regression test for `Realloc` trait implementation of `Vec`. + /// + /// Previously `Realloc::realloc()` called `self.capacity()` instead + /// of `self.len()` when checking whether the vector should be expanded. + /// As a result, it sometimes attempted to shrink the vector + /// when it should be expanded, and effectively did nothing. + #[test] + fn realloc_vec() { + let mut v: Vec = Poolable::alloc(100); + + for i in 1..100 { + let new_size = Poolable::capacity(&v) + i; + v.realloc(new_size); + assert_eq!(Poolable::capacity(&v), new_size); + } + } +} From 4e053f434a4f9b3be91877f85b89ec3c57e93cd6 Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 6 Apr 2023 10:08:56 +0000 Subject: [PATCH 2/2] Use reserve_exact() to ensure Vec len stays the same as capacity --- src/poolable.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/poolable.rs b/src/poolable.rs index 70e0814..320036f 100644 --- a/src/poolable.rs +++ b/src/poolable.rs @@ -42,7 +42,15 @@ impl Realloc for Vec { assert!(new_size > 0); match new_size.cmp(&self.len()) { - Greater => self.resize(new_size, T::default()), + Greater => { + self.reserve_exact(new_size - self.len()); + debug_assert_eq!(self.capacity(), new_size); + self.resize(new_size, T::default()); + debug_assert_eq!(self.len(), new_size); + + // Check that resize() did not reserve additional space. + debug_assert_eq!(self.capacity(), new_size); + } Less => { self.truncate(new_size); debug_assert_eq!(self.len(), new_size); @@ -95,6 +103,12 @@ mod tests { let new_size = Poolable::capacity(&v) + i; v.realloc(new_size); assert_eq!(Poolable::capacity(&v), new_size); + + // Length of the vectory and underlying buffer + // for poolable vectors should + // be exactly of the requested size. + assert_eq!(v.len(), new_size); + assert_eq!(v.capacity(), new_size); } } }