Skip to content

Commit 8e6c148

Browse files
committed
CapacityHolder WIP
1 parent 1b3a329 commit 8e6c148

File tree

2 files changed

+50
-37
lines changed

2 files changed

+50
-37
lines changed

library/alloc/src/raw_vec.rs

+47-27
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,33 @@ enum AllocInit {
3333
Zeroed,
3434
}
3535

36+
pub trait CapacityHolder: Copy {
37+
fn as_usize<T>(self) -> usize {
38+
if T::IS_ZST {
39+
usize::MAX
40+
} else {
41+
Self::as_usize_raw(self)
42+
}
43+
}
44+
fn as_usize_raw(c: Self) -> usize;
45+
}
46+
47+
#[derive(Copy, Clone)]
48+
pub struct FixedCapacity<const N: usize>;
49+
impl<const N: usize> CapacityHolder for FixedCapacity<N> {
50+
fn as_usize_raw(_: Self) -> usize { N }
51+
}
52+
3653
#[repr(transparent)]
54+
#[derive(Copy, Clone)]
3755
#[cfg_attr(target_pointer_width = "16", rustc_layout_scalar_valid_range_end(0x7fff))]
3856
#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0x7fff_ffff))]
3957
#[cfg_attr(target_pointer_width = "64", rustc_layout_scalar_valid_range_end(0x7fff_ffff_ffff_ffff))]
40-
struct Cap(usize);
58+
pub(crate) struct Cap(usize);
59+
60+
impl CapacityHolder for Cap {
61+
fn as_usize_raw(c: Self) -> usize { c.0 }
62+
}
4163

4264
impl Cap {
4365
const ZERO: Cap = unsafe { Cap(0) };
@@ -66,14 +88,9 @@ impl Cap {
6688
/// `usize::MAX`. This means that you need to be careful when round-tripping this type with a
6789
/// `Box<[T]>`, since `capacity()` won't yield the length.
6890
#[allow(missing_debug_implementations)]
69-
pub(crate) struct RawVec<T, A: Allocator = Global> {
91+
pub(crate) struct RawVec<T, A: Allocator = Global, C: CapacityHolder = Cap> {
7092
ptr: Unique<T>,
71-
/// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
72-
///
73-
/// # Safety
74-
///
75-
/// `cap` must be in the `0..=isize::MAX` range.
76-
cap: Cap,
93+
cap: C,
7794
alloc: A,
7895
}
7996

@@ -129,6 +146,27 @@ impl<T> RawVec<T, Global> {
129146
}
130147
}
131148

149+
impl<T, A: Allocator, C: CapacityHolder> RawVec<T, A, C> {
150+
fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
151+
let cap = self.cap.as_usize::<T>();
152+
if T::IS_ZST || cap == 0 {
153+
None
154+
} else {
155+
// We could use Layout::array here which ensures the absence of isize and usize overflows
156+
// and could hypothetically handle differences between stride and size, but this memory
157+
// has already been allocated so we know it can't overflow and currently Rust does not
158+
// support such types. So we can do better by skipping some checks and avoid an unwrap.
159+
const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
160+
unsafe {
161+
let align = mem::align_of::<T>();
162+
let size = mem::size_of::<T>().unchecked_mul(cap);
163+
let layout = Layout::from_size_align_unchecked(size, align);
164+
Some((self.ptr.cast().into(), layout))
165+
}
166+
}
167+
}
168+
}
169+
132170
impl<T, A: Allocator> RawVec<T, A> {
133171
// Tiny Vecs are dumb. Skip to:
134172
// - 8 if the element size is 1, because any heap allocators is likely
@@ -296,24 +334,6 @@ impl<T, A: Allocator> RawVec<T, A> {
296334
&self.alloc
297335
}
298336

299-
fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
300-
if T::IS_ZST || self.cap.0 == 0 {
301-
None
302-
} else {
303-
// We could use Layout::array here which ensures the absence of isize and usize overflows
304-
// and could hypothetically handle differences between stride and size, but this memory
305-
// has already been allocated so we know it can't overflow and currently Rust does not
306-
// support such types. So we can do better by skipping some checks and avoid an unwrap.
307-
const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
308-
unsafe {
309-
let align = mem::align_of::<T>();
310-
let size = mem::size_of::<T>().unchecked_mul(self.cap.0);
311-
let layout = Layout::from_size_align_unchecked(size, align);
312-
Some((self.ptr.cast().into(), layout))
313-
}
314-
}
315-
}
316-
317337
/// Ensures that the buffer contains at least enough space to hold `len +
318338
/// additional` elements. If it doesn't already have enough capacity, will
319339
/// reallocate enough space plus comfortable slack space to get amortized
@@ -576,7 +596,7 @@ where
576596
memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into())
577597
}
578598

579-
unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
599+
unsafe impl<#[may_dangle] T, A: Allocator, C: CapacityHolder> Drop for RawVec<T, A, C> {
580600
/// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
581601
fn drop(&mut self) {
582602
if let Some((ptr, layout)) = self.current_memory() {

library/alloc/src/vec/into_iter.rs

+3-10
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,7 @@ pub struct IntoIter<
4646
T,
4747
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
4848
> {
49-
pub(super) buf: NonNull<T>,
50-
pub(super) phantom: PhantomData<T>,
51-
pub(super) cap: usize,
52-
// the drop impl reconstructs a RawVec from buf, cap and alloc
53-
// to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
54-
pub(super) alloc: ManuallyDrop<A>,
49+
pub(super) buf: RawVec<T, A>,
5550
pub(super) ptr: NonNull<T>,
5651
/// If T is a ZST, this is actually ptr+len. This encoding is picked so that
5752
/// ptr == end is a quick test for the Iterator being empty, that works
@@ -106,7 +101,7 @@ impl<T, A: Allocator> IntoIter<T, A> {
106101
#[unstable(feature = "allocator_api", issue = "32838")]
107102
#[inline]
108103
pub fn allocator(&self) -> &A {
109-
&self.alloc
104+
self.buf.allocator()
110105
}
111106

112107
fn as_raw_mut_slice(&mut self) -> *mut [T] {
@@ -136,9 +131,7 @@ impl<T, A: Allocator> IntoIter<T, A> {
136131
// struct and then overwriting &mut self.
137132
// this creates less assembly
138133
self.cap = 0;
139-
self.buf = RawVec::NEW.non_null();
140-
self.ptr = self.buf;
141-
self.end = self.buf.as_ptr();
134+
unsafe { self.buf.set_ptr_and_cap(NonNull::dangling(), 0) };
142135

143136
// Dropping the remaining elements can panic, so this needs to be
144137
// done only after updating the other fields.

0 commit comments

Comments
 (0)