diff --git a/src/conversions.rs b/src/conversions.rs index fd6a41f2..6d3915e9 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -150,14 +150,16 @@ impl From< as Like>::Type> if vec.capacity() <= INLINE { vec.reserve(INLINE + 1 - length); } - let cap = vec.capacity(); // SAFETY: vec.capacity is not `0` (checked above), so the pointer // can not dangle and thus specifically cannot be null. - let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) }; - Self { length: LocatedLength::new(length, true), - raw: RawSmallVec::heap(ptr, cap), + raw: RawSmallVec { + heap: NonNull::slice_from_raw_parts( + unsafe { NonNull::new_unchecked(vec.as_mut_ptr()).cast() }, + vec.capacity() + ) + }, allocator: Global } } @@ -191,8 +193,12 @@ impl From as Like>::Type::from_raw_parts(ptr.as_ptr(), length, cap) + let pointer = this.raw.heap; + as Like>::Type::from_raw_parts( + pointer.cast().as_ptr(), + length, + pointer.len() + ) } } } diff --git a/src/iterators/intoiter.rs b/src/iterators/intoiter.rs index ec08ec90..9d9ee0f5 100644 --- a/src/iterators/intoiter.rs +++ b/src/iterators/intoiter.rs @@ -171,7 +171,7 @@ impl Drop for IntoIter(), diff --git a/src/lib.rs b/src/lib.rs index 8ace2d93..3003e041 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,7 +228,9 @@ impl SmallVec { // SAFETY: all the members in 0..S are initialized Self { length: LocatedLength::new(S, false), - raw: RawSmallVec::inline(buf), + raw: RawSmallVec { + inline: ManuallyDrop::new(buf) + }, allocator: Global } } @@ -240,7 +242,9 @@ impl SmallVec { // SAFETY: all the members in 0..length are initialized let mut vec = Self { length: LocatedLength::new(length, false), - raw: RawSmallVec::inline(buf.map(MaybeUninit::new)), + raw: RawSmallVec { + inline: ManuallyDrop::new(buf.map(MaybeUninit::new)) + }, allocator: Global }; // Deallocate the remaining elements so no memory is leaked. @@ -288,7 +292,9 @@ impl SmallVec { debug_assert!(length <= INLINE); Self { length: LocatedLength::new(length, false), - raw: RawSmallVec::inline(buf), + raw: RawSmallVec { + inline: ManuallyDrop::new(buf) + }, allocator: Global } } @@ -365,7 +371,11 @@ impl SmallVec { #[inline] pub const fn inline_size() -> usize { - RawSmallVec::::INLINE_CAP + if size_of::() == 0 { + usize::MAX + } else { + INLINE + } } #[inline] @@ -660,15 +670,20 @@ impl SmallVec { if on_heap { unsafe { // SAFETY: heap member is active - let (ptr, old_cap) = self.raw.heap; + let pointer = self.raw.heap; + // inline member is now active // SAFETY: length <= new_capacity <= Self::inline_size() // so the copy is within bounds of the inline member - copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), length); + copy_nonoverlapping( + pointer.as_ptr().cast(), + self.raw.as_mut_ptr_inline(), + length + ); drop(DropDealloc { - ptr: ptr.cast(), - size_bytes: old_cap * size_of::(), + ptr: pointer.cast(), + size_bytes: pointer.len() * size_of::(), align: align_of::(), allocator: &self.allocator }); @@ -738,14 +753,18 @@ impl SmallVec { if length <= Self::inline_size() { // SAFETY: on_heap is true, so we're on the heap unsafe { - let (ptr, capacity) = self.raw.heap; - copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), length); + let pointer = self.raw.heap; + copy_nonoverlapping( + pointer.as_ptr().cast(), + self.raw.as_mut_ptr_inline(), + length + ); self.length.set_location::(); Allocator::deallocate( &self.allocator, - ptr.cast(), + pointer.cast(), Layout::from_size_align_unchecked( - capacity * size_of::(), + pointer.len() * size_of::(), align_of::() ) ); @@ -770,20 +789,24 @@ impl SmallVec { return; } // SAFETY: the vector is on the heap - let capacity = unsafe { self.raw.heap.1 }; + let capacity = unsafe { self.raw.heap.len() }; if capacity > min_capacity { let target = length.max(min_capacity); if target <= Self::inline_size() { // SAFETY: on_heap is true, so we're on the heap unsafe { - let (ptr, capacity) = self.raw.heap; - copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), length); + let pointer = self.raw.heap; + copy_nonoverlapping( + pointer.as_ptr().cast(), + self.raw.as_mut_ptr_inline(), + length + ); self.length.set_location::(); Allocator::deallocate( &self.allocator, - ptr.cast(), + pointer.cast(), Layout::from_size_align_unchecked( - capacity * size_of::(), + pointer.len() * size_of::(), align_of::() ) ); @@ -1472,7 +1495,7 @@ impl<#[cfg_attr(feature = "may-dangle", may_dangle)] Item, const INLINE: usize, // SAFETY: see above unsafe { let _drop_dealloc = if on_heap { - let capacity = self.raw.heap.1; + let capacity = self.raw.heap.len(); Some(DropDealloc { ptr: NonNull::new_unchecked(ptr as *mut u8), size_bytes: capacity * size_of::(), diff --git a/src/rawsmallvec.rs b/src/rawsmallvec.rs index 7c8d8f8e..492633d1 100644 --- a/src/rawsmallvec.rs +++ b/src/rawsmallvec.rs @@ -20,29 +20,14 @@ use { #[repr(C)] pub union RawSmallVec { pub inline: ManuallyDrop<[MaybeUninit; INLINE]>, - pub heap: (NonNull, usize) + pub heap: NonNull<[MaybeUninit]> } impl RawSmallVec { - pub const INLINE_CAP: usize = if Self::IS_ZST { usize::MAX } else { INLINE }; - const IS_ZST: bool = size_of::() == 0; - #[inline] pub const fn new() -> Self { - Self::inline([const { MaybeUninit::uninit() }; INLINE]) - } - - #[inline] - pub const fn inline(inline: [MaybeUninit; INLINE]) -> Self { - Self { - inline: ManuallyDrop::new(inline) - } - } - - #[inline] - pub const fn heap(ptr: NonNull, capacity: usize) -> Self { Self { - heap: (ptr, capacity) + inline: ManuallyDrop::new([const { MaybeUninit::uninit() }; INLINE]) } } @@ -68,7 +53,7 @@ impl RawSmallVec { #[inline(always)] pub const unsafe fn as_ptr(&self, on_heap: bool) -> *const Item { if on_heap { - unsafe { self.heap.0.as_ptr() } + unsafe { self.heap.as_ptr().cast_const().cast() } } else { self.as_ptr_inline() } @@ -80,7 +65,7 @@ impl RawSmallVec { #[inline(always)] pub const unsafe fn as_mut_ptr(&mut self, on_heap: bool) -> *mut Item { if on_heap { - unsafe { self.heap.0.as_ptr() } + unsafe { self.heap.as_ptr().cast() } } else { self.as_mut_ptr_inline() } @@ -92,9 +77,11 @@ impl RawSmallVec { #[inline(always)] pub const unsafe fn capacity(&self, on_heap: bool) -> usize { if on_heap { - unsafe { self.heap.1 } + unsafe { self.heap.len() } + } else if size_of::() == 0 { + usize::MAX } else { - Self::INLINE_CAP + INLINE } } @@ -111,7 +98,7 @@ impl RawSmallVec { allocator: &Heap ) -> Result<(), SmallVecError> { let (length, was_on_heap) = length.parts(); - debug_assert!(!Self::IS_ZST); + debug_assert!(size_of::() != 0); debug_assert!(new_capacity > 0 && new_capacity >= length); // SAFETY: the tag tells which member is active @@ -138,7 +125,7 @@ impl RawSmallVec { // layout during the previous allocation let old_layout = unsafe { Layout::from_size_align_unchecked( - self.heap.1 * size_of::(), + self.heap.len() * size_of::(), align_of::() ) }; @@ -150,7 +137,7 @@ impl RawSmallVec { // alignment. since it was constructed // with Layout::array unsafe { - (if self.heap.1 < new_capacity { + (if self.heap.len() < new_capacity { ::grow } else { ::shrink @@ -164,7 +151,7 @@ impl RawSmallVec { .ok_or(SmallVecError::AllocationError(new_layout))? .cast() }; - self.heap = (new_ptr, new_capacity); + self.heap = NonNull::slice_from_raw_parts(new_ptr.cast(), new_capacity); Ok(()) } } diff --git a/tests/parts.rs b/tests/parts.rs index 24e50784..1bc0fe01 100644 --- a/tests/parts.rs +++ b/tests/parts.rs @@ -13,13 +13,13 @@ fn into_from_parts_spilled() { assert_eq!(length.len(), 3); // SAFETY: `length` says on heap, so `heap` is the active member. - let (ptr, cap) = unsafe { raw.heap }; - assert!(cap > 1); + let pointer = unsafe { raw.heap }; + assert!(pointer.len() > 1); // SAFETY: parts come straight from `into_parts`. let rebuilt = unsafe { SmallVec::::from_parts(raw, length) }; assert_eq!(rebuilt, [-1, 0, 1]); - assert_eq!(rebuilt.as_ptr(), ptr.as_ptr() as *const i32); + assert_eq!(rebuilt.as_ptr(), pointer.as_ptr() as *const i32); } #[test]