Add try_shrink_to and try_shrink_to_fit to Vec

* Add try_shrink_to and try_shrink_to_fit to Vec

Both functions are required to support shrinking a vector in
environments without global OOM handling.
* Format the try_shrink functions
* Remove excess "```" from doc
* Remove `cfg(not(no_global_oom_handling))` from rawvecinner::shrink
* Fix import cmp even if no_global_oom_handling is defined
This commit is contained in:
BitSyndicate1
2026-02-23 01:20:41 +00:00
parent 286fbe5d84
commit 1f076d2f93
2 changed files with 97 additions and 5 deletions
+29 -2
View File
@@ -399,6 +399,21 @@ pub(crate) fn shrink_to_fit(&mut self, cap: usize) {
// SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout
unsafe { self.inner.shrink_to_fit(cap, T::LAYOUT) }
}
/// Shrinks the buffer down to the specified capacity. If the given amount
/// is 0, actually completely deallocates.
///
/// # Errors
///
/// This function returns an error if the allocator cannot shrink the allocation.
///
/// # Panics
///
/// Panics if the given amount is *larger* than the current capacity.
#[inline]
pub(crate) fn try_shrink_to_fit(&mut self, cap: usize) -> Result<(), TryReserveError> {
unsafe { self.inner.try_shrink_to_fit(cap, T::LAYOUT) }
}
}
unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
@@ -731,6 +746,20 @@ unsafe fn shrink_to_fit(&mut self, cap: usize, elem_layout: Layout) {
}
}
/// # Safety
///
/// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
/// initially construct `self`
/// - `elem_layout`'s size must be a multiple of its alignment
/// - `cap` must be less than or equal to `self.capacity(elem_layout.size())`
unsafe fn try_shrink_to_fit(
&mut self,
cap: usize,
elem_layout: Layout,
) -> Result<(), TryReserveError> {
unsafe { self.shrink(cap, elem_layout) }
}
#[inline]
const fn needs_to_grow(&self, len: usize, additional: usize, elem_layout: Layout) -> bool {
additional > self.capacity(elem_layout.size()).wrapping_sub(len)
@@ -778,7 +807,6 @@ unsafe fn grow_exact(
/// initially construct `self`
/// - `elem_layout`'s size must be a multiple of its alignment
/// - `cap` must be less than or equal to `self.capacity(elem_layout.size())`
#[cfg(not(no_global_oom_handling))]
#[inline]
unsafe fn shrink(&mut self, cap: usize, elem_layout: Layout) -> Result<(), TryReserveError> {
assert!(cap <= self.capacity(elem_layout.size()), "Tried to shrink to a larger capacity");
@@ -796,7 +824,6 @@ unsafe fn shrink(&mut self, cap: usize, elem_layout: Layout) -> Result<(), TryRe
///
/// # Safety
/// `cap <= self.capacity()`
#[cfg(not(no_global_oom_handling))]
unsafe fn shrink_unchecked(
&mut self,
cap: usize,
+68 -3
View File
@@ -75,8 +75,6 @@
#[cfg(not(no_global_oom_handling))]
use core::clone::TrivialClone;
#[cfg(not(no_global_oom_handling))]
use core::cmp;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
#[cfg(not(no_global_oom_handling))]
@@ -88,7 +86,7 @@
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
use core::ptr::{self, NonNull};
use core::slice::{self, SliceIndex};
use core::{fmt, hint, intrinsics, ub_checks};
use core::{cmp, fmt, hint, intrinsics, ub_checks};
#[stable(feature = "extract_if", since = "1.87.0")]
pub use self::extract_if::ExtractIf;
@@ -1613,6 +1611,73 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
}
}
/// Tries to shrink the capacity of the vector as much as possible
///
/// The behavior of this method depends on the allocator, which may either shrink the vector
/// in-place or reallocate. The resulting vector might still have some excess capacity, just as
/// is the case for [`with_capacity`]. See [`Allocator::shrink`] for more details.
///
/// [`with_capacity`]: Vec::with_capacity
///
/// # Errors
///
/// This function returns an error if the allocator fails to shrink the allocation,
/// the vector thereafter is still safe to use, the capacity remains unchanged
/// however. See [`Allocator::shrink`].
///
/// # Examples
///
/// ```
/// #![feature(vec_fallible_shrink)]
///
/// let mut vec = Vec::with_capacity(10);
/// vec.extend([1, 2, 3]);
/// assert!(vec.capacity() >= 10);
/// vec.try_shrink_to_fit().expect("why is the test harness failing to shrink to 12 bytes");
/// assert!(vec.capacity() >= 3);
/// ```
#[unstable(feature = "vec_fallible_shrink", issue = "152350")]
#[inline]
pub fn try_shrink_to_fit(&mut self) -> Result<(), TryReserveError> {
if self.capacity() > self.len { self.buf.try_shrink_to_fit(self.len) } else { Ok(()) }
}
/// Shrinks the capacity of the vector with a lower bound.
///
/// The capacity will remain at least as large as both the length
/// and the supplied value.
///
/// If the current capacity is less than the lower limit, this is a no-op.
///
/// # Errors
///
/// This function returns an error if the allocator fails to shrink the allocation,
/// the vector thereafter is still safe to use, the capacity remains unchanged
/// however. See [`Allocator::shrink`].
///
/// # Examples
///
/// ```
/// #![feature(vec_fallible_shrink)]
///
/// let mut vec = Vec::with_capacity(10);
/// vec.extend([1, 2, 3]);
/// assert!(vec.capacity() >= 10);
/// vec.try_shrink_to(4).expect("why is the test harness failing to shrink to 12 bytes");
/// assert!(vec.capacity() >= 4);
/// vec.try_shrink_to(0).expect("this is a no-op and thus the allocator isn't involved.");
/// assert!(vec.capacity() >= 3);
/// ```
#[unstable(feature = "vec_fallible_shrink", issue = "152350")]
#[inline]
pub fn try_shrink_to(&mut self, min_capacity: usize) -> Result<(), TryReserveError> {
if self.capacity() > min_capacity {
self.buf.try_shrink_to_fit(cmp::max(self.len, min_capacity))
} else {
Ok(())
}
}
/// Converts the vector into [`Box<[T]>`][owned slice].
///
/// Before doing the conversion, this method discards excess capacity like [`shrink_to_fit`].