Double the capacity when BlobVec is full (#11167)

# Objective

- Fixes #10797

## Solution

- Double the capacity of a full `BlobVec` before pushing a new element.
This commit is contained in:
Chia-Hsiang Cheng 2024-01-22 23:05:34 +08:00 committed by GitHub
parent eb07d16871
commit 8ad1b93e63
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -124,6 +124,23 @@ impl BlobVec {
} }
} }
/// Reserves the minimum capacity for at least `additional` more elements to be inserted in the given `BlobVec`.
#[inline]
pub fn reserve(&mut self, additional: usize) {
/// Similar to `reserve_exact`. This method ensures that the capacity will grow at least `self.capacity()` if there is no
/// enough space to hold `additional` more elements.
#[cold]
fn do_reserve(slf: &mut BlobVec, additional: usize) {
let increment = slf.capacity.max(additional - (slf.capacity - slf.len));
let increment = NonZeroUsize::new(increment).unwrap();
slf.grow_exact(increment);
}
if self.capacity - self.len < additional {
do_reserve(self, additional);
}
}
/// Grows the capacity by `increment` elements. /// Grows the capacity by `increment` elements.
/// ///
/// # Panics /// # Panics
@ -241,7 +258,7 @@ impl BlobVec {
/// The `value` must match the [`layout`](`BlobVec::layout`) of the elements in the [`BlobVec`]. /// The `value` must match the [`layout`](`BlobVec::layout`) of the elements in the [`BlobVec`].
#[inline] #[inline]
pub unsafe fn push(&mut self, value: OwningPtr<'_>) { pub unsafe fn push(&mut self, value: OwningPtr<'_>) {
self.reserve_exact(1); self.reserve(1);
let index = self.len; let index = self.len;
self.len += 1; self.len += 1;
self.initialize_unchecked(index, value); self.initialize_unchecked(index, value);
@ -530,7 +547,7 @@ mod tests {
} }
assert_eq!(blob_vec.len(), 1_000); assert_eq!(blob_vec.len(), 1_000);
assert_eq!(blob_vec.capacity(), 1_000); assert_eq!(blob_vec.capacity(), 1_024);
} }
#[derive(Debug, Eq, PartialEq, Clone)] #[derive(Debug, Eq, PartialEq, Clone)]
@ -590,19 +607,19 @@ mod tests {
push(&mut blob_vec, foo3.clone()); push(&mut blob_vec, foo3.clone());
assert_eq!(blob_vec.len(), 3); assert_eq!(blob_vec.len(), 3);
assert_eq!(blob_vec.capacity(), 3); assert_eq!(blob_vec.capacity(), 4);
let last_index = blob_vec.len() - 1; let last_index = blob_vec.len() - 1;
let value = swap_remove::<Foo>(&mut blob_vec, last_index); let value = swap_remove::<Foo>(&mut blob_vec, last_index);
assert_eq!(foo3, value); assert_eq!(foo3, value);
assert_eq!(blob_vec.len(), 2); assert_eq!(blob_vec.len(), 2);
assert_eq!(blob_vec.capacity(), 3); assert_eq!(blob_vec.capacity(), 4);
let value = swap_remove::<Foo>(&mut blob_vec, 0); let value = swap_remove::<Foo>(&mut blob_vec, 0);
assert_eq!(foo1, value); assert_eq!(foo1, value);
assert_eq!(blob_vec.len(), 1); assert_eq!(blob_vec.len(), 1);
assert_eq!(blob_vec.capacity(), 3); assert_eq!(blob_vec.capacity(), 4);
foo2.a = 8; foo2.a = 8;
assert_eq!(get_mut::<Foo>(&mut blob_vec, 0), &foo2); assert_eq!(get_mut::<Foo>(&mut blob_vec, 0), &foo2);