Skip to content

Commit 4aedc00

Browse files
authored
Rollup merge of rust-lang#142138 - ashivaram23:vec_into_chunks, r=scottmcm
Add `Vec::into_chunks` Tracking issue rust-lang#142137
2 parents fd147cd + c1d32d8 commit 4aedc00

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,6 +3031,61 @@ impl<T, A: Allocator> Vec<T, A> {
30313031
(initialized, spare, &mut self.len)
30323032
}
30333033
}
3034+
3035+
/// Groups every `N` elements in the `Vec<T>` into chunks to produce a `Vec<[T; N]>`, dropping
3036+
/// elements in the remainder. `N` must be greater than zero.
3037+
///
3038+
/// If the capacity is not a multiple of the chunk size, the buffer will shrink down to the
3039+
/// nearest multiple with a reallocation or deallocation.
3040+
///
3041+
/// This function can be used to reverse [`Vec::into_flattened`].
3042+
///
3043+
/// # Examples
3044+
///
3045+
/// ```
3046+
/// #![feature(vec_into_chunks)]
3047+
///
3048+
/// let vec = vec![0, 1, 2, 3, 4, 5, 6, 7];
3049+
/// assert_eq!(vec.into_chunks::<3>(), [[0, 1, 2], [3, 4, 5]]);
3050+
///
3051+
/// let vec = vec![0, 1, 2, 3];
3052+
/// let chunks: Vec<[u8; 10]> = vec.into_chunks();
3053+
/// assert!(chunks.is_empty());
3054+
///
3055+
/// let flat = vec![0; 8 * 8 * 8];
3056+
/// let reshaped: Vec<[[[u8; 8]; 8]; 8]> = flat.into_chunks().into_chunks().into_chunks();
3057+
/// assert_eq!(reshaped.len(), 1);
3058+
/// ```
3059+
#[cfg(not(no_global_oom_handling))]
3060+
#[unstable(feature = "vec_into_chunks", issue = "142137")]
3061+
pub fn into_chunks<const N: usize>(mut self) -> Vec<[T; N], A> {
3062+
const {
3063+
assert!(N != 0, "chunk size must be greater than zero");
3064+
}
3065+
3066+
let (len, cap) = (self.len(), self.capacity());
3067+
3068+
let len_remainder = len % N;
3069+
if len_remainder != 0 {
3070+
self.truncate(len - len_remainder);
3071+
}
3072+
3073+
let cap_remainder = cap % N;
3074+
if !T::IS_ZST && cap_remainder != 0 {
3075+
self.buf.shrink_to_fit(cap - cap_remainder);
3076+
}
3077+
3078+
let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc();
3079+
3080+
// SAFETY:
3081+
// - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()`
3082+
// - `[T; N]` has the same alignment as `T`
3083+
// - `size_of::<[T; N]>() * cap / N == size_of::<T>() * cap`
3084+
// - `len / N <= cap / N` because `len <= cap`
3085+
// - the allocated memory consists of `len / N` valid values of type `[T; N]`
3086+
// - `cap / N` fits the size of the allocated memory after shrinking
3087+
unsafe { Vec::from_raw_parts_in(ptr.cast(), len / N, cap / N, alloc) }
3088+
}
30343089
}
30353090

30363091
impl<T: Clone, A: Allocator> Vec<T, A> {

0 commit comments

Comments
 (0)