insertion works

This commit is contained in:
nora 2021-12-22 20:41:31 +01:00
parent eebea36b1d
commit 29cfe9d3e2
3 changed files with 30 additions and 38 deletions

View file

@ -98,8 +98,8 @@ impl<T: ?Sized> Vechonk<T> {
/// Insert an element at an index. /// Insert an element at an index.
/// * If the insertion was successful, the old element is returned. /// * If the insertion was successful, the old element is returned.
/// * If the new element doesn't fit the gap or can't be aligned, it is returned. /// * If the new element doesn't fit the gap or can't be aligned, it is returned.
pub fn insert(&mut self, index: usize, element: Box<T>) -> Result<Box<T>, Box<T>> { pub fn try_insert(&mut self, index: usize, element: Box<T>) -> Result<Box<T>, Box<T>> {
self.raw.insert_elem(element, index) self.raw.try_insert_elem(element, index)
} }
/// An iterator over the elements yielding shared references /// An iterator over the elements yielding shared references
@ -178,8 +178,8 @@ impl<T: ?Sized> MutGuard<T> {
/// Write a new element to the location. /// Write a new element to the location.
/// * If the element fits in the space, the old element is returned /// * If the element fits in the space, the old element is returned
/// * If the element does not fit in the space, the new element is returned again /// * If the element does not fit in the space, the new element is returned again
pub fn write(&mut self, element: Box<T>) -> Result<Box<T>, Box<T>> { pub fn try_write(&mut self, element: Box<T>) -> Result<Box<T>, Box<T>> {
self.raw.insert_elem(element, self.index) self.raw.try_insert_elem(element, self.index)
} }
} }

View file

@ -77,7 +77,6 @@ impl<T: ?Sized> RawVechonk<T> {
let elem_align = mem::align_of_val(element.as_ref()); let elem_align = mem::align_of_val(element.as_ref());
let elem_ptr = Box::into_raw(element); let elem_ptr = Box::into_raw(element);
let meta = ptr::metadata(elem_ptr);
let data_size = mem::size_of::<PtrData<T>>(); let data_size = mem::size_of::<PtrData<T>>();
let elem_offset = self.elem_size; let elem_offset = self.elem_size;
@ -105,11 +104,6 @@ impl<T: ?Sized> RawVechonk<T> {
let dest_align_offset = dest_ptr.align_offset(elem_align); let dest_align_offset = dest_ptr.align_offset(elem_align);
let dest_ptr = unsafe { dest_ptr.add(dest_align_offset) }; let dest_ptr = unsafe { dest_ptr.add(dest_align_offset) };
let data = PtrData {
offset: elem_offset + dest_align_offset,
meta,
};
// SAFETY: `elem_ptr` comes from `Box`, and is therefore valid to read from for the size // SAFETY: `elem_ptr` comes from `Box`, and is therefore valid to read from for the size
// We have made sure above that we have more than `elem_size` bytes free // We have made sure above that we have more than `elem_size` bytes free
// The two allocations cannot overlap, since the `Box` owned its contents, and so do we // The two allocations cannot overlap, since the `Box` owned its contents, and so do we
@ -118,17 +112,8 @@ impl<T: ?Sized> RawVechonk<T> {
ptr::copy_nonoverlapping::<u8>(elem_ptr as _, dest_ptr, elem_size); ptr::copy_nonoverlapping::<u8>(elem_ptr as _, dest_ptr, elem_size);
} }
let data_offset = self.offset_for_data(self.len); // SAFETY: We've made sure that there's enough space for another data
unsafe { self.write_meta_data(elem_ptr, elem_offset + dest_align_offset, self.len) };
// SAFETY: The offset will always be less than `self.cap`, because we can't have more than `self.len` `PtrData`
let data_ptr = unsafe { self.ptr.as_ptr().add(data_offset) };
let data_ptr = data_ptr as *mut PtrData<T>;
// SAFETY: The pointer is aligned, because `self.ptr` and `self.cap` are
// It's not out of bounds for our allocation, see above
unsafe {
*data_ptr = data;
}
self.elem_size += elem_size; self.elem_size += elem_size;
self.len += 1; self.len += 1;
@ -142,7 +127,7 @@ impl<T: ?Sized> RawVechonk<T> {
/// Insert an element at an index. /// Insert an element at an index.
/// * If the insertion was successful, the old element is returned. /// * If the insertion was successful, the old element is returned.
/// * If the new element doesn't fit the gap or can't be aligned, it is returned. /// * If the new element doesn't fit the gap or can't be aligned, it is returned.
pub fn insert_elem(&mut self, element: Box<T>, index: usize) -> Result<Box<T>, Box<T>> { pub fn try_insert_elem(&mut self, element: Box<T>, index: usize) -> Result<Box<T>, Box<T>> {
if index >= self.len { if index >= self.len {
// out of bounds // out of bounds
return Err(element); return Err(element);
@ -161,7 +146,7 @@ impl<T: ?Sized> RawVechonk<T> {
// this is where the free space, including padding, where we could place the element starts // this is where the free space, including padding, where we could place the element starts
// since there might be padding for the previous element, this is sometimes before `elem_offset` // since there might be padding for the previous element, this is sometimes before `elem_offset`
let free_space_start_offset = if index == 0 { let free_space_start_offset = if index == 0 {
self.cap 0
} else { } else {
// SAFETY: `index` is not 0 // SAFETY: `index` is not 0
unsafe { unsafe {
@ -215,17 +200,7 @@ impl<T: ?Sized> RawVechonk<T> {
}; };
// SAFETY: `index` is not out of bounds, and we are overwriting the element afterwards // SAFETY: `index` is not out of bounds, and we are overwriting the element afterwards
let data_ptr = unsafe { self.get_data_ptr(index) }; unsafe { self.write_meta_data(elem_ptr, new_elem_starting_offset, index) };
let meta = ptr::metadata(elem_ptr);
let new_data: PtrData<T> = PtrData {
offset: new_elem_starting_offset,
meta,
};
// SAFETY: We can assume that `get_data_ptr` returns valid pointers to `PtrData<T>`
unsafe { *data_ptr = new_data };
// SAFETY: `elem_ptr` comes from the box // SAFETY: `elem_ptr` comes from the box
unsafe { dealloc_box(elem_ptr) }; unsafe { dealloc_box(elem_ptr) };
@ -374,6 +349,21 @@ impl<T: ?Sized> RawVechonk<T> {
self.cap = size.get(); self.cap = size.get();
} }
/// Writes the metadata of the `ptr` and the `offset` to a `PtrData<T>` at `index`
/// # Safety
/// `index` must be in bounds, or only so much out of bounds as to not overwrite element data
unsafe fn write_meta_data(&mut self, ptr: *mut T, offset: usize, index: usize) {
// SAFETY: `index` is not out of bounds, and we are overwriting the element afterwards
let data_ptr = unsafe { self.get_data_ptr(index) };
let meta = ptr::metadata::<T>(ptr);
let new_data: PtrData<T> = PtrData { offset, meta };
// SAFETY: We can assume that `get_data_ptr` returns valid pointers to `PtrData<T>`
unsafe { *data_ptr = new_data };
}
/// Get the data for the index /// Get the data for the index
/// # Safety /// # Safety
/// `index` must not be out of bounds /// `index` must not be out of bounds
@ -405,7 +395,7 @@ impl<T: ?Sized> RawVechonk<T> {
} }
/// # Safety /// # Safety
/// `index` must not be out of bounds /// `index` must be in bounds, or only so much out of bounds to not overwrite element data
unsafe fn get_data_ptr(&self, index: usize) -> *mut PtrData<T> { unsafe fn get_data_ptr(&self, index: usize) -> *mut PtrData<T> {
let data_offset = self.offset_for_data(index); let data_offset = self.offset_for_data(index);

View file

@ -250,8 +250,10 @@ fn get_mut_mutating() {
let mut hello = chonk1.get_mut(0).unwrap(); let mut hello = chonk1.get_mut(0).unwrap();
hello.write("owo".into()).unwrap(); hello.try_write("owo".into()).unwrap();
hello.write("hi, I'm wayyyyy too long".into()).unwrap_err(); hello
.try_write("hi, I'm wayyyyy too long".into())
.unwrap_err();
assert_eq!(&*hello, "owo"); assert_eq!(&*hello, "owo");
} }
@ -260,7 +262,7 @@ fn get_mut_mutating() {
fn insert() { fn insert() {
let mut chonk: Vechonk<str> = vechonk!["hello".into(), "uwu".into()]; let mut chonk: Vechonk<str> = vechonk!["hello".into(), "uwu".into()];
chonk.insert(0, "owo".into()).unwrap(); chonk.try_insert(0, "owo".into()).unwrap();
assert_eq!(&chonk[0], "owo"); assert_eq!(&chonk[0], "owo");
} }