Skip to content

Commit f37f0e4

Browse files
authored
Unrolled build for rust-lang#120355
Rollup merge of rust-lang#120355 - the8472:doc-vec-fromiter, r=cuviper document `FromIterator for Vec` allocation behaviors [t-libs discussion](https://rust-lang.zulipchat.com/#narrow/stream/259402-t-libs.2Fmeetings/topic/Meeting.202024-01-24/near/417686526) about rust-lang#120091 didn't reach a strong consensus, but it was agreed that if we keep the current behavior it should at least be documented even though it is an implementation detail. The language is intentionally non-committal. The previous (non-existent) documentation permits a lot of implementation leeway and we want retain that. In some cases we even must retain it to be able to rip out some code paths that rely on unstable features.
2 parents cdaa12e + 39dc315 commit f37f0e4

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

library/alloc/src/vec/mod.rs

+44
Original file line numberDiff line numberDiff line change
@@ -2784,6 +2784,50 @@ impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
27842784
}
27852785
}
27862786

2787+
/// Collects an iterator into a Vec, commonly called via [`Iterator::collect()`]
2788+
///
2789+
/// # Allocation behavior
2790+
///
2791+
/// In general `Vec` does not guarantee any particular growth or allocation strategy.
2792+
/// That also applies to this trait impl.
2793+
///
2794+
/// **Note:** This section covers implementation details and is therefore exempt from
2795+
/// stability guarantees.
2796+
///
2797+
/// Vec may use any or none of the following strategies,
2798+
/// depending on the supplied iterator:
2799+
///
2800+
/// * preallocate based on [`Iterator::size_hint()`]
2801+
/// * and panic if the number of items is outside the provided lower/upper bounds
2802+
/// * use an amortized growth strategy similar to `pushing` one item at a time
2803+
/// * perform the iteration in-place on the original allocation backing the iterator
2804+
///
2805+
/// The last case warrants some attention. It is an optimization that in many cases reduces peak memory
2806+
/// consumption and improves cache locality. But when big, short-lived allocations are created,
2807+
/// only a small fraction of their items get collected, no further use is made of the spare capacity
2808+
/// and the resulting `Vec` is moved into a longer-lived structure, then this can lead to the large
2809+
/// allocations having their lifetimes unnecessarily extended which can result in increased memory
2810+
/// footprint.
2811+
///
2812+
/// In cases where this is an issue, the excess capacity can be discarded with [`Vec::shrink_to()`],
2813+
/// [`Vec::shrink_to_fit()`] or by collecting into [`Box<[T]>`][owned slice] instead, which additionally reduces
2814+
/// the size of the long-lived struct.
2815+
///
2816+
/// [owned slice]: Box
2817+
///
2818+
/// ```rust
2819+
/// # use std::sync::Mutex;
2820+
/// static LONG_LIVED: Mutex<Vec<Vec<u16>>> = Mutex::new(Vec::new());
2821+
///
2822+
/// for i in 0..10 {
2823+
/// let big_temporary: Vec<u16> = (0..1024).collect();
2824+
/// // discard most items
2825+
/// let mut result: Vec<_> = big_temporary.into_iter().filter(|i| i % 100 == 0).collect();
2826+
/// // without this a lot of unused capacity might be moved into the global
2827+
/// result.shrink_to_fit();
2828+
/// LONG_LIVED.lock().unwrap().push(result);
2829+
/// }
2830+
/// ```
27872831
#[cfg(not(no_global_oom_handling))]
27882832
#[stable(feature = "rust1", since = "1.0.0")]
27892833
impl<T> FromIterator<T> for Vec<T> {

0 commit comments

Comments
 (0)