Skip to content

Commit ccce985

Browse files
committed
Auto merge of #91246 - nnethercote:faster-layout-array, r=dtolnay
Faster `Layout::array` `Layout::array` is called (indirectly) by `Vec::push()`, which is typically instantiated many times, and so making it smaller can help with compile times because less LLVM IR is generated. r? `@ghost`
2 parents 6d246f0 + dbfb913 commit ccce985

File tree

2 files changed

+98
-4
lines changed

2 files changed

+98
-4
lines changed

library/alloc/src/raw_vec/tests.rs

+84
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,87 @@ fn reserve_does_not_overallocate() {
7777
assert!(v.capacity() >= 12 + 12 / 2);
7878
}
7979
}
80+
81+
struct ZST;
82+
83+
// A `RawVec` holding zero-sized elements should always look like this.
84+
fn zst_sanity<T>(v: &RawVec<T>) {
85+
assert_eq!(v.capacity(), usize::MAX);
86+
assert_eq!(v.ptr(), core::ptr::Unique::<T>::dangling().as_ptr());
87+
assert_eq!(v.current_memory(), None);
88+
}
89+
90+
#[test]
91+
fn zst() {
92+
let cap_err = Err(crate::collections::TryReserveErrorKind::CapacityOverflow.into());
93+
94+
assert_eq!(std::mem::size_of::<ZST>(), 0);
95+
96+
// All these different ways of creating the RawVec produce the same thing.
97+
98+
let v: RawVec<ZST> = RawVec::new();
99+
zst_sanity(&v);
100+
101+
let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
102+
zst_sanity(&v);
103+
104+
let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
105+
zst_sanity(&v);
106+
107+
let v: RawVec<ZST> = RawVec::allocate_in(0, AllocInit::Uninitialized, Global);
108+
zst_sanity(&v);
109+
110+
let v: RawVec<ZST> = RawVec::allocate_in(100, AllocInit::Uninitialized, Global);
111+
zst_sanity(&v);
112+
113+
let mut v: RawVec<ZST> = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global);
114+
zst_sanity(&v);
115+
116+
// Check all these operations work as expected with zero-sized elements.
117+
118+
assert!(!v.needs_to_grow(100, usize::MAX - 100));
119+
assert!(v.needs_to_grow(101, usize::MAX - 100));
120+
zst_sanity(&v);
121+
122+
v.reserve(100, usize::MAX - 100);
123+
//v.reserve(101, usize::MAX - 100); // panics, in `zst_reserve_panic` below
124+
zst_sanity(&v);
125+
126+
v.reserve_exact(100, usize::MAX - 100);
127+
//v.reserve_exact(101, usize::MAX - 100); // panics, in `zst_reserve_exact_panic` below
128+
zst_sanity(&v);
129+
130+
assert_eq!(v.try_reserve(100, usize::MAX - 100), Ok(()));
131+
assert_eq!(v.try_reserve(101, usize::MAX - 100), cap_err);
132+
zst_sanity(&v);
133+
134+
assert_eq!(v.try_reserve_exact(100, usize::MAX - 100), Ok(()));
135+
assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err);
136+
zst_sanity(&v);
137+
138+
assert_eq!(v.grow_amortized(100, usize::MAX - 100), cap_err);
139+
assert_eq!(v.grow_amortized(101, usize::MAX - 100), cap_err);
140+
zst_sanity(&v);
141+
142+
assert_eq!(v.grow_exact(100, usize::MAX - 100), cap_err);
143+
assert_eq!(v.grow_exact(101, usize::MAX - 100), cap_err);
144+
zst_sanity(&v);
145+
}
146+
147+
#[test]
148+
#[should_panic(expected = "capacity overflow")]
149+
fn zst_reserve_panic() {
150+
let mut v: RawVec<ZST> = RawVec::new();
151+
zst_sanity(&v);
152+
153+
v.reserve(101, usize::MAX - 100);
154+
}
155+
156+
#[test]
157+
#[should_panic(expected = "capacity overflow")]
158+
fn zst_reserve_exact_panic() {
159+
let mut v: RawVec<ZST> = RawVec::new();
160+
zst_sanity(&v);
161+
162+
v.reserve_exact(101, usize::MAX - 100);
163+
}

library/core/src/alloc/layout.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@ impl Layout {
281281
// > `usize::MAX`)
282282
let new_size = self.size() + pad;
283283

284-
Layout::from_size_align(new_size, self.align()).unwrap()
284+
// SAFETY: self.align is already known to be valid and new_size has been
285+
// padded already.
286+
unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
285287
}
286288

287289
/// Creates a layout describing the record for `n` instances of
@@ -403,9 +405,17 @@ impl Layout {
403405
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
404406
#[inline]
405407
pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
406-
let (layout, offset) = Layout::new::<T>().repeat(n)?;
407-
debug_assert_eq!(offset, mem::size_of::<T>());
408-
Ok(layout.pad_to_align())
408+
let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
409+
410+
// SAFETY:
411+
// - Size: `array_size` cannot be too big because `size_of::<T>()` must
412+
// be a multiple of `align_of::<T>()`. Therefore, `array_size`
413+
// rounded up to the nearest multiple of `align_of::<T>()` is just
414+
// `array_size`. And `array_size` cannot be too big because it was
415+
// just checked by the `checked_mul()`.
416+
// - Alignment: `align_of::<T>()` will always give an acceptable
417+
// (non-zero, power of two) alignment.
418+
Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) })
409419
}
410420
}
411421

0 commit comments

Comments
 (0)