mirror of
https://github.com/Noratrieb/vechonk.git
synced 2026-03-14 21:26:06 +01:00
fix alignment
This commit is contained in:
parent
9c0cbf6a9c
commit
00f1ba7193
3 changed files with 26 additions and 80 deletions
17
src/iter.rs
17
src/iter.rs
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{RawVechonk, Vechonk};
|
||||
use alloc::boxed::Box;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::mem::ManuallyDrop;
|
||||
|
||||
/// An iterator over the elements of a [`Vechonk`]
|
||||
pub struct Iter<'a, T: ?Sized> {
|
||||
|
|
@ -105,18 +105,21 @@ pub struct IntoIter<T: ?Sized> {
|
|||
}
|
||||
|
||||
impl<'a, T: ?Sized> IntoIter<T> {
|
||||
pub(super) fn new(chonk: Vechonk<T>) -> IntoIter<T> {
|
||||
let raw = chonk.raw.copy();
|
||||
|
||||
// We don't want to free the memory!
|
||||
mem::forget(chonk);
|
||||
|
||||
pub(crate) fn from_raw(raw: RawVechonk<T>) -> Self {
|
||||
Self {
|
||||
raw,
|
||||
current_index: 0,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(chonk: Vechonk<T>) -> IntoIter<T> {
|
||||
// We don't want to free the memory yet!
|
||||
let chonk = ManuallyDrop::new(chonk);
|
||||
let raw = chonk.raw.copy();
|
||||
|
||||
Self::from_raw(raw)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Iterator for IntoIter<T> {
|
||||
|
|
|
|||
13
src/lib.rs
13
src/lib.rs
|
|
@ -94,6 +94,7 @@ impl<T: ?Sized> Vechonk<T> {
|
|||
self.raw.pop()
|
||||
}
|
||||
|
||||
#[cfg(any())]
|
||||
pub fn insert(&mut self, _index: usize, _element: Box<T>) {
|
||||
todo!()
|
||||
}
|
||||
|
|
@ -103,6 +104,7 @@ impl<T: ?Sized> Vechonk<T> {
|
|||
/// Even worse, after all the copying, it might realloc anyways because it couldn't fit in the space.
|
||||
///
|
||||
/// Returns the old element at that
|
||||
#[cfg(any())]
|
||||
pub fn replace(&mut self, _index: usize, _element: Box<T>) -> Box<T> {
|
||||
todo!()
|
||||
}
|
||||
|
|
@ -163,17 +165,6 @@ impl<T: ?Sized> Vechonk<T> {
|
|||
// The pointer is aligned, because it has been aligned manually in `Self::push`
|
||||
unsafe { &*self.raw.get_unchecked_ptr(index) }
|
||||
}
|
||||
|
||||
/// used for debugging memory layout
|
||||
/// safety: cap must be 96
|
||||
#[allow(dead_code)]
|
||||
#[doc(hidden)]
|
||||
#[cfg(debug_assertions)]
|
||||
pub unsafe fn debug_chonk(&self) {
|
||||
let array = unsafe { *(self.raw.ptr.as_ptr() as *mut [u8; 96]) };
|
||||
|
||||
panic!("{:?}", array)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Index<usize> for Vechonk<T> {
|
||||
|
|
|
|||
76
src/raw.rs
76
src/raw.rs
|
|
@ -65,10 +65,7 @@ impl<T: ?Sized> RawVechonk<T> {
|
|||
return vechonk;
|
||||
}
|
||||
|
||||
// SAFETY: capacity has been checked to not be 0 and the len is 0
|
||||
unsafe {
|
||||
vechonk.realloc(NonZeroUsize::new_unchecked(capacity));
|
||||
}
|
||||
vechonk.reset_alloc(NonZeroUsize::new(capacity).unwrap());
|
||||
vechonk
|
||||
}
|
||||
|
||||
|
|
@ -290,71 +287,26 @@ impl<T: ?Sized> RawVechonk<T> {
|
|||
}
|
||||
|
||||
fn regrow(&mut self, min_size: NonZeroUsize) {
|
||||
// new_cap must be properly "aligned" for `PtrData<T>`
|
||||
// We just create a new one and copy all elements over.
|
||||
// This is because it's almost impossible to copy around the alignment properly,
|
||||
// as we need to dynamically align each element, and the alignment of our allocation
|
||||
// might have decreased after the realloc.
|
||||
|
||||
let new_cap = force_align(min_size.get() * 2, Self::data_align());
|
||||
|
||||
let old_ptr = self.ptr.as_ptr();
|
||||
let old_cap = self.cap;
|
||||
|
||||
let last_data_index = self.len.saturating_sub(1);
|
||||
let old_data_offset = self.offset_for_data(last_data_index);
|
||||
|
||||
// SAFETY: `min_size` was already non-zero
|
||||
// We will copy the elements over
|
||||
unsafe {
|
||||
self.realloc(NonZeroUsize::new_unchecked(new_cap));
|
||||
}
|
||||
|
||||
// copy the elements first
|
||||
// SAFETY: both pointers point to the start of allocations smaller than `self.elem_size` and own them
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping::<u8>(old_ptr, self.ptr.as_ptr(), self.elem_size);
|
||||
}
|
||||
|
||||
// then copy the data
|
||||
// SAFETY: both pointers have been offset by less than `self.cap`, and the `data_section_size` fills the allocation perfectly
|
||||
unsafe {
|
||||
let new_data_ptr = self.ptr.as_ptr().add(self.offset_for_data(last_data_index));
|
||||
|
||||
ptr::copy_nonoverlapping::<u8>(
|
||||
old_ptr.add(old_data_offset),
|
||||
new_data_ptr,
|
||||
self.data_section_size(),
|
||||
)
|
||||
}
|
||||
|
||||
// now free the old data
|
||||
// SAFETY: This was previously allocated and is not used anymore
|
||||
unsafe {
|
||||
Self::dealloc(old_cap, old_ptr);
|
||||
}
|
||||
let new = RawVechonk::with_capacity(new_cap);
|
||||
let old = mem::replace(self, new);
|
||||
crate::IntoIter::from_raw(old).for_each(|e| {
|
||||
self.push(e);
|
||||
});
|
||||
}
|
||||
|
||||
/// Reallocs the `Vechonk`, setting its capacity to `size`. This will not copy any elements. This will put the `Vechonk`
|
||||
/// into an invalid state, since the `len` is still the length of the elements in the old allocation.
|
||||
///
|
||||
/// This doesn't free any memory
|
||||
///
|
||||
/// # Safety
|
||||
/// The caller must either set the `len` to zero, or copy the elements to the new allocation by saving
|
||||
/// `self.ptr` before calling this function.
|
||||
unsafe fn realloc(&mut self, size: NonZeroUsize) {
|
||||
// TODO this is *not* sound, since the alignment of some big elements might be wrong now
|
||||
|
||||
/// Allocates the `Vechonk`, setting its capacity to `size`.
|
||||
fn reset_alloc(&mut self, size: NonZeroUsize) {
|
||||
let layout = Layout::from_size_align(size.get(), Self::data_align()).unwrap();
|
||||
|
||||
// SAFETY: layout is guaranteed to have a non-zero size
|
||||
let alloced_ptr;
|
||||
|
||||
// we only care about it being zeroed for debugging since it makes it easier
|
||||
#[cfg(debug_assertions)]
|
||||
unsafe {
|
||||
alloced_ptr = alloc::alloc::alloc_zeroed(layout)
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
unsafe {
|
||||
alloced_ptr = alloc::alloc::alloc(layout)
|
||||
}
|
||||
let alloced_ptr = unsafe { alloc::alloc::alloc(layout) };
|
||||
|
||||
self.ptr =
|
||||
NonNull::new(alloced_ptr).unwrap_or_else(|| alloc::alloc::handle_alloc_error(layout));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue