From 29cfe9d3e271f70e03f0f309e08c132ece372427 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 22 Dec 2021 20:41:31 +0100 Subject: [PATCH] insertion works --- src/lib.rs | 8 ++++---- src/raw.rs | 52 +++++++++++++++++++++------------------------------- src/test.rs | 8 +++++--- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1b8e81a..133b236 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,8 +98,8 @@ impl Vechonk { /// Insert an element at an index. /// * 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. - pub fn insert(&mut self, index: usize, element: Box) -> Result, Box> { - self.raw.insert_elem(element, index) + pub fn try_insert(&mut self, index: usize, element: Box) -> Result, Box> { + self.raw.try_insert_elem(element, index) } /// An iterator over the elements yielding shared references @@ -178,8 +178,8 @@ impl MutGuard { /// Write a new element to the location. /// * 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 - pub fn write(&mut self, element: Box) -> Result, Box> { - self.raw.insert_elem(element, self.index) + pub fn try_write(&mut self, element: Box) -> Result, Box> { + self.raw.try_insert_elem(element, self.index) } } diff --git a/src/raw.rs b/src/raw.rs index ad19945..2c57426 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -77,7 +77,6 @@ impl RawVechonk { let elem_align = mem::align_of_val(element.as_ref()); let elem_ptr = Box::into_raw(element); - let meta = ptr::metadata(elem_ptr); let data_size = mem::size_of::>(); let elem_offset = self.elem_size; @@ -105,11 +104,6 @@ impl RawVechonk { let dest_align_offset = dest_ptr.align_offset(elem_align); 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 // 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 @@ -118,17 +112,8 @@ impl RawVechonk { ptr::copy_nonoverlapping::(elem_ptr as _, dest_ptr, elem_size); } - let data_offset = self.offset_for_data(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; - - // 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; - } + // 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) }; self.elem_size += elem_size; self.len += 1; @@ -142,7 +127,7 @@ impl RawVechonk { /// Insert an element at an index. /// * 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. - pub fn insert_elem(&mut self, element: Box, index: usize) -> Result, Box> { + pub fn try_insert_elem(&mut self, element: Box, index: usize) -> Result, Box> { if index >= self.len { // out of bounds return Err(element); @@ -161,7 +146,7 @@ impl RawVechonk { // 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` let free_space_start_offset = if index == 0 { - self.cap + 0 } else { // SAFETY: `index` is not 0 unsafe { @@ -215,17 +200,7 @@ impl RawVechonk { }; // 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(elem_ptr); - - let new_data: PtrData = PtrData { - offset: new_elem_starting_offset, - meta, - }; - - // SAFETY: We can assume that `get_data_ptr` returns valid pointers to `PtrData` - unsafe { *data_ptr = new_data }; + unsafe { self.write_meta_data(elem_ptr, new_elem_starting_offset, index) }; // SAFETY: `elem_ptr` comes from the box unsafe { dealloc_box(elem_ptr) }; @@ -374,6 +349,21 @@ impl RawVechonk { self.cap = size.get(); } + /// Writes the metadata of the `ptr` and the `offset` to a `PtrData` 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::(ptr); + + let new_data: PtrData = PtrData { offset, meta }; + + // SAFETY: We can assume that `get_data_ptr` returns valid pointers to `PtrData` + unsafe { *data_ptr = new_data }; + } + /// Get the data for the index /// # Safety /// `index` must not be out of bounds @@ -405,7 +395,7 @@ impl RawVechonk { } /// # 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 { let data_offset = self.offset_for_data(index); diff --git a/src/test.rs b/src/test.rs index 04326ef..5b3cc75 100644 --- a/src/test.rs +++ b/src/test.rs @@ -250,8 +250,10 @@ fn get_mut_mutating() { let mut hello = chonk1.get_mut(0).unwrap(); - hello.write("owo".into()).unwrap(); - hello.write("hi, I'm wayyyyy too long".into()).unwrap_err(); + hello.try_write("owo".into()).unwrap(); + hello + .try_write("hi, I'm wayyyyy too long".into()) + .unwrap_err(); assert_eq!(&*hello, "owo"); } @@ -260,7 +262,7 @@ fn get_mut_mutating() { fn insert() { let mut chonk: Vechonk = vechonk!["hello".into(), "uwu".into()]; - chonk.insert(0, "owo".into()).unwrap(); + chonk.try_insert(0, "owo".into()).unwrap(); assert_eq!(&chonk[0], "owo"); }