summaryrefslogtreecommitdiff
path: root/rust/alloc/vec/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/alloc/vec/mod.rs')
-rw-r--r--rust/alloc/vec/mod.rs101
1 files changed, 71 insertions, 30 deletions
diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs
index 220fb9d6f45b..0be27fff4554 100644
--- a/rust/alloc/vec/mod.rs
+++ b/rust/alloc/vec/mod.rs
@@ -360,7 +360,7 @@ mod spec_extend;
///
/// `vec![x; n]`, `vec![a, b, c, d]`, and
/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
-/// with exactly the requested capacity. If <code>[len] == [capacity]</code>,
+/// with at least the requested capacity. If <code>[len] == [capacity]</code>,
/// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
///
@@ -447,7 +447,7 @@ impl<T> Vec<T> {
///
/// # Panics
///
- /// Panics if the new capacity exceeds `isize::MAX` bytes.
+ /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
///
/// # Examples
///
@@ -690,7 +690,7 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// # Panics
///
- /// Panics if the new capacity exceeds `isize::MAX` bytes.
+ /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
///
/// # Examples
///
@@ -1013,7 +1013,7 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// # Panics
///
- /// Panics if the new capacity exceeds `isize::MAX` bytes.
+ /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
///
/// # Examples
///
@@ -1043,7 +1043,7 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// # Panics
///
- /// Panics if the new capacity exceeds `isize::MAX` bytes.
+ /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
///
/// # Examples
///
@@ -1140,8 +1140,11 @@ impl<T, A: Allocator> Vec<T, A> {
/// Shrinks the capacity of the vector as much as possible.
///
- /// It will drop down as close as possible to the length but the allocator
- /// may still inform the vector that there is space for a few more elements.
+ /// 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
///
/// # Examples
///
@@ -1191,10 +1194,10 @@ impl<T, A: Allocator> Vec<T, A> {
/// Converts the vector into [`Box<[T]>`][owned slice].
///
- /// If the vector has excess capacity, its items will be moved into a
- /// newly-allocated buffer with exactly the right capacity.
+ /// Before doing the conversion, this method discards excess capacity like [`shrink_to_fit`].
///
/// [owned slice]: Box
+ /// [`shrink_to_fit`]: Vec::shrink_to_fit
///
/// # Examples
///
@@ -2017,7 +2020,7 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// # Panics
///
- /// Panics if the new capacity exceeds `isize::MAX` bytes.
+ /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
///
/// # Examples
///
@@ -2133,7 +2136,7 @@ impl<T, A: Allocator> Vec<T, A> {
} else {
unsafe {
self.len -= 1;
- core::intrinsics::assume(self.len < self.capacity());
+ core::hint::assert_unchecked(self.len < self.capacity());
Some(ptr::read(self.as_ptr().add(self.len())))
}
}
@@ -2143,7 +2146,7 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// # Panics
///
- /// Panics if the new capacity exceeds `isize::MAX` bytes.
+ /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
///
/// # Examples
///
@@ -2315,6 +2318,12 @@ impl<T, A: Allocator> Vec<T, A> {
/// `[at, len)`. After the call, the original vector will be left containing
/// the elements `[0, at)` with its previous capacity unchanged.
///
+ /// - If you want to take ownership of the entire contents and capacity of
+ /// the vector, see [`mem::take`] or [`mem::replace`].
+ /// - If you don't need the returned vector at all, see [`Vec::truncate`].
+ /// - If you want to take ownership of an arbitrary subslice, or you don't
+ /// necessarily want to store the removed items in a vector, see [`Vec::drain`].
+ ///
/// # Panics
///
/// Panics if `at > len`.
@@ -2346,14 +2355,6 @@ impl<T, A: Allocator> Vec<T, A> {
assert_failed(at, self.len());
}
- if at == 0 {
- // the new vector can take over the original buffer and avoid the copy
- return mem::replace(
- self,
- Vec::with_capacity_in(self.capacity(), self.allocator().clone()),
- );
- }
-
let other_len = self.len - at;
let mut other = Vec::with_capacity_in(other_len, self.allocator().clone());
@@ -3027,6 +3028,50 @@ impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
}
}
+/// Collects an iterator into a Vec, commonly called via [`Iterator::collect()`]
+///
+/// # Allocation behavior
+///
+/// In general `Vec` does not guarantee any particular growth or allocation strategy.
+/// That also applies to this trait impl.
+///
+/// **Note:** This section covers implementation details and is therefore exempt from
+/// stability guarantees.
+///
+/// Vec may use any or none of the following strategies,
+/// depending on the supplied iterator:
+///
+/// * preallocate based on [`Iterator::size_hint()`]
+/// * and panic if the number of items is outside the provided lower/upper bounds
+/// * use an amortized growth strategy similar to `pushing` one item at a time
+/// * perform the iteration in-place on the original allocation backing the iterator
+///
+/// The last case warrants some attention. It is an optimization that in many cases reduces peak memory
+/// consumption and improves cache locality. But when big, short-lived allocations are created,
+/// only a small fraction of their items get collected, no further use is made of the spare capacity
+/// and the resulting `Vec` is moved into a longer-lived structure, then this can lead to the large
+/// allocations having their lifetimes unnecessarily extended which can result in increased memory
+/// footprint.
+///
+/// In cases where this is an issue, the excess capacity can be discarded with [`Vec::shrink_to()`],
+/// [`Vec::shrink_to_fit()`] or by collecting into [`Box<[T]>`][owned slice] instead, which additionally reduces
+/// the size of the long-lived struct.
+///
+/// [owned slice]: Box
+///
+/// ```rust
+/// # use std::sync::Mutex;
+/// static LONG_LIVED: Mutex<Vec<Vec<u16>>> = Mutex::new(Vec::new());
+///
+/// for i in 0..10 {
+/// let big_temporary: Vec<u16> = (0..1024).collect();
+/// // discard most items
+/// let mut result: Vec<_> = big_temporary.into_iter().filter(|i| i % 100 == 0).collect();
+/// // without this a lot of unused capacity might be moved into the global
+/// result.shrink_to_fit();
+/// LONG_LIVED.lock().unwrap().push(result);
+/// }
+/// ```
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> FromIterator<T> for Vec<T> {
@@ -3069,14 +3114,8 @@ impl<T, A: Allocator> IntoIterator for Vec<T, A> {
begin.add(me.len()) as *const T
};
let cap = me.buf.capacity();
- IntoIter {
- buf: NonNull::new_unchecked(begin),
- phantom: PhantomData,
- cap,
- alloc,
- ptr: begin,
- end,
- }
+ let buf = NonNull::new_unchecked(begin);
+ IntoIter { buf, phantom: PhantomData, cap, alloc, ptr: buf, end }
}
}
}
@@ -3598,8 +3637,10 @@ impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
/// Convert a vector into a boxed slice.
///
- /// If `v` has excess capacity, its items will be moved into a
- /// newly-allocated buffer with exactly the right capacity.
+ /// Before doing the conversion, this method discards excess capacity like [`Vec::shrink_to_fit`].
+ ///
+ /// [owned slice]: Box
+ /// [`Vec::shrink_to_fit`]: Vec::shrink_to_fit
///
/// # Examples
///