diff options
| author | Amogh Shivaram <ashivaram@solesca.com> | 2025-06-06 22:14:30 -0500 | 
|---|---|---|
| committer | Amogh Shivaram <ashivaram@solesca.com> | 2025-06-06 22:14:30 -0500 | 
| commit | 230b55dcf821a25d945e8d0ddec2cea460a46935 (patch) | |
| tree | 854374be45286cfe8183b0bee3b92b8fc93a96c2 /library/alloc/src | |
| parent | 868bf2da31d1c6ead7016d5ee52eacfd2e2fd158 (diff) | |
| download | rust-230b55dcf821a25d945e8d0ddec2cea460a46935.tar.gz rust-230b55dcf821a25d945e8d0ddec2cea460a46935.zip | |
Add `into_chunks`
Diffstat (limited to 'library/alloc/src')
| -rw-r--r-- | library/alloc/src/vec/mod.rs | 52 | 
1 files changed, 52 insertions, 0 deletions
| diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ce7321544b6..71fd5b409ac 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2999,6 +2999,58 @@ impl<T, A: Allocator> Vec<T, A> { (initialized, spare, &mut self.len) } } + + /// Groups every `N` elements in the `Vec<T>` into chunks to produce a `Vec<[T; N]>`, dropping + /// elements in the remainder. `N` must be greater than zero. + /// + /// If the capacity is not a multiple of the chunk size, the buffer will shrink down to the + /// nearest multiple with a reallocation or deallocation. + /// + /// This function can be used to reverse [`Vec::into_flattened`]. + /// + /// # Examples + /// + /// ``` + /// let vec = vec![0, 1, 2, 3, 4, 5, 6, 7]; + /// assert_eq!(vec.into_chunks::<3>(), [[0, 1, 2], [3, 4, 5]]); + /// + /// let vec = vec![0, 1, 2, 3]; + /// let chunks: Vec<[u8; 10]> = vec.into_chunks(); + /// assert!(chunks.is_empty()); + /// + /// let flat = vec![0; 8 * 8 * 8]; + /// let reshaped: Vec<[[[u8; 8]; 8]; 8]> = flat.into_chunks().into_chunks().into_chunks(); + /// assert_eq!(reshaped.len(), 1); + /// ``` + #[unstable(feature = "vec_into_chunks", issue = "142137")] + pub fn into_chunks<const N: usize>(mut self) -> Vec<[T; N], A> { + const { + assert!(N != 0, "chunk size should be greater than zero"); + } + + let (len, cap) = (self.len(), self.capacity()); + + let len_remainder = len % N; + if len_remainder != 0 { + self.truncate(len - len_remainder); + } + + let cap_remainder = cap % N; + if !T::IS_ZST && cap_remainder != 0 { + self.buf.shrink_to_fit(cap - cap_remainder); + } + + let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc(); + + // SAFETY: + // - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()` + // - `[T; N]` has the same alignment as `T` + // - `size_of::<[T; N]>() * cap / N == size_of::<T>() * cap` + // - `len / N <= cap / N` because `len <= cap` + // - the allocated memory consists of `len / N` valid values of type `[T; N]` + // - `cap / N` fits the size of the allocated memory after shrinking + unsafe { Vec::from_raw_parts_in(ptr.cast(), len / N, cap / N, alloc) } + } } impl<T: Clone, A: Allocator> Vec<T, A> { | 
