Skip to content

Commit 06788fd

Browse files
committed
add <[[T; N]]>::flatten, <[[T; N]]>::flatten_mut, and Vec::<[T; N]>::into_flattened
1 parent 297a801 commit 06788fd

File tree

7 files changed

+153
-0
lines changed

7 files changed

+153
-0
lines changed

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
#![feature(trusted_len)]
132132
#![feature(trusted_random_access)]
133133
#![feature(try_trait_v2)]
134+
#![feature(unchecked_math)]
134135
#![feature(unicode_internals)]
135136
#![feature(unsize)]
136137
//

library/alloc/src/vec/mod.rs

+45
Original file line numberDiff line numberDiff line change
@@ -2274,6 +2274,51 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
22742274
}
22752275
}
22762276

2277+
impl<T, A: Allocator, const N: usize> Vec<[T; N], A> {
2278+
/// Takes a `Vec<[T; N]>` and flattens it into a `Vec<T>`.
2279+
///
2280+
/// # Panics
2281+
///
2282+
/// Panics if the length of the resulting vector would overflow a `usize`.
2283+
///
2284+
/// This is only possible when flattening a vector of arrays of zero-sized
2285+
/// types, and thus tends to be irrelevant in practice. If
2286+
/// `size_of::<T>() > 0`, this will never panic.
2287+
///
2288+
/// # Examples
2289+
///
2290+
/// ```
2291+
/// #![feature(slice_flatten)]
2292+
///
2293+
/// let mut vec = vec![[1, 2, 3], [4, 5, 6], [7, 8, 9]];
2294+
/// assert_eq!(vec.pop(), Some([7, 8, 9]));
2295+
///
2296+
/// let mut flattened = vec.into_flattened();
2297+
/// assert_eq!(flattened.pop(), Some(6));
2298+
/// ```
2299+
#[unstable(feature = "slice_flatten", issue = "95629")]
2300+
pub fn into_flattened(self) -> Vec<T, A> {
2301+
let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc();
2302+
let (new_len, new_cap) = if mem::size_of::<T>() == 0 {
2303+
(len.checked_mul(N).expect("vec len overflow"), usize::MAX)
2304+
} else {
2305+
// SAFETY:
2306+
// - `cap * N` cannot overflow because the allocation is already in
2307+
// the address space.
2308+
// - Each `[T; N]` has `N` valid elements, so there are `len * N`
2309+
// valid elements in the allocation.
2310+
unsafe { (len.unchecked_mul(N), cap.unchecked_mul(N)) }
2311+
};
2312+
// SAFETY:
2313+
// - `ptr` was allocated by `self`
2314+
// - `ptr` is well-aligned because `[T; N]` has the same alignment as `T`.
2315+
// - `new_cap` refers to the same sized allocation as `cap` because
2316+
// `new_cap * size_of::<T>()` == `cap * size_of::<[T; N]>()`
2317+
// - `len` <= `cap`, so `len * N` <= `cap * N`.
2318+
unsafe { Vec::<T, A>::from_raw_parts_in(ptr.cast(), new_len, new_cap, alloc) }
2319+
}
2320+
}
2321+
22772322
// This code generalizes `extend_with_{element,default}`.
22782323
trait ExtendWith<T> {
22792324
fn next(&mut self) -> T;

library/alloc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#![feature(const_str_from_utf8)]
3939
#![feature(nonnull_slice_from_raw_parts)]
4040
#![feature(panic_update_hook)]
41+
#![feature(slice_flatten)]
4142

4243
use std::collections::hash_map::DefaultHasher;
4344
use std::hash::{Hash, Hasher};

library/alloc/tests/vec.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2408,3 +2408,10 @@ fn test_extend_from_within_panicing_clone() {
24082408

24092409
assert_eq!(count.load(Ordering::SeqCst), 4);
24102410
}
2411+
2412+
#[test]
2413+
#[should_panic = "vec len overflow"]
2414+
fn test_into_flattened_size_overflow() {
2415+
let v = vec![[(); usize::MAX]; 2];
2416+
let _ = v.into_flattened();
2417+
}

library/core/src/slice/mod.rs

+82
Original file line numberDiff line numberDiff line change
@@ -3994,6 +3994,88 @@ impl<T> [T] {
39943994
}
39953995
}
39963996

3997+
#[cfg(not(bootstrap))]
3998+
impl<T, const N: usize> [[T; N]] {
3999+
/// Takes a `&[[T; N]]`, and flattens it to a `&[T]`.
4000+
///
4001+
/// # Panics
4002+
///
4003+
/// This panics if the length of the resulting slice would overflow a `usize`.
4004+
///
4005+
/// This is only possible when flattening a slice of arrays of zero-sized
4006+
/// types, and thus tends to be irrelevant in practice. If
4007+
/// `size_of::<T>() > 0`, this will never panic.
4008+
///
4009+
/// # Examples
4010+
///
4011+
/// ```
4012+
/// #![feature(slice_flatten)]
4013+
///
4014+
/// assert_eq!([[1, 2, 3], [4, 5, 6]].flatten(), &[1, 2, 3, 4, 5, 6]);
4015+
///
4016+
/// assert_eq!(
4017+
/// [[1, 2, 3], [4, 5, 6]].flatten(),
4018+
/// [[1, 2], [3, 4], [5, 6]].flatten(),
4019+
/// );
4020+
///
4021+
/// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
4022+
/// assert!(slice_of_empty_arrays.flatten().is_empty());
4023+
///
4024+
/// let empty_slice_of_arrays: &[[u32; 10]] = &[];
4025+
/// assert!(empty_slice_of_arrays.flatten().is_empty());
4026+
/// ```
4027+
#[unstable(feature = "slice_flatten", issue = "95629")]
4028+
pub fn flatten(&self) -> &[T] {
4029+
let len = if crate::mem::size_of::<T>() == 0 {
4030+
self.len().checked_mul(N).expect("slice len overflow")
4031+
} else {
4032+
// SAFETY: `self.len() * N` cannot overflow because `self` is
4033+
// already in the address space.
4034+
unsafe { self.len().unchecked_mul(N) }
4035+
};
4036+
// SAFETY: `[T]` is layout-identical to `[T; N]`
4037+
unsafe { from_raw_parts(self.as_ptr().cast(), len) }
4038+
}
4039+
4040+
/// Takes a `&mut [[T; N]]`, and flattens it to a `&mut [T]`.
4041+
///
4042+
/// # Panics
4043+
///
4044+
/// This panics if the length of the resulting slice would overflow a `usize`.
4045+
///
4046+
/// This is only possible when flattening a slice of arrays of zero-sized
4047+
/// types, and thus tends to be irrelevant in practice. If
4048+
/// `size_of::<T>() > 0`, this will never panic.
4049+
///
4050+
/// # Examples
4051+
///
4052+
/// ```
4053+
/// #![feature(slice_flatten)]
4054+
///
4055+
/// fn add_5_to_all(slice: &mut [i32]) {
4056+
/// for i in slice {
4057+
/// *i += 5;
4058+
/// }
4059+
/// }
4060+
///
4061+
/// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
4062+
/// add_5_to_all(array.flatten_mut());
4063+
/// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]);
4064+
/// ```
4065+
#[unstable(feature = "slice_flatten", issue = "95629")]
4066+
pub fn flatten_mut(&mut self) -> &mut [T] {
4067+
let len = if crate::mem::size_of::<T>() == 0 {
4068+
self.len().checked_mul(N).expect("slice len overflow")
4069+
} else {
4070+
// SAFETY: `self.len() * N` cannot overflow because `self` is
4071+
// already in the address space.
4072+
unsafe { self.len().unchecked_mul(N) }
4073+
};
4074+
// SAFETY: `[T]` is layout-identical to `[T; N]`
4075+
unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), len) }
4076+
}
4077+
}
4078+
39974079
trait CloneFromSpec<T> {
39984080
fn spec_clone_from(&mut self, src: &[T]);
39994081
}

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
#![feature(const_array_from_ref)]
9494
#![feature(const_slice_from_ref)]
9595
#![feature(waker_getters)]
96+
#![feature(slice_flatten)]
9697
#![deny(unsafe_op_in_unsafe_fn)]
9798

9899
extern crate test;

library/core/tests/slice.rs

+16
Original file line numberDiff line numberDiff line change
@@ -2504,3 +2504,19 @@ fn test_slice_from_ptr_range() {
25042504
assert_eq!(slice::from_ptr_range(range), &arr);
25052505
}
25062506
}
2507+
2508+
#[test]
2509+
#[cfg(not(bootstrap))]
2510+
#[should_panic = "slice len overflow"]
2511+
fn test_flatten_size_overflow() {
2512+
let x = &[[(); usize::MAX]; 2][..];
2513+
let _ = x.flatten();
2514+
}
2515+
2516+
#[test]
2517+
#[cfg(not(bootstrap))]
2518+
#[should_panic = "slice len overflow"]
2519+
fn test_flatten_mut_size_overflow() {
2520+
let x = &mut [[(); usize::MAX]; 2][..];
2521+
let _ = x.flatten_mut();
2522+
}

0 commit comments

Comments
 (0)