From a861b14abec47c216cdc0fe610e558aa7419479d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Dec 2024 15:47:09 +0100 Subject: [PATCH] Replace `Page` data Vec with boxed fixed array --- src/table.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/table.rs b/src/table.rs index 56a37696..c761ebb7 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,7 +1,9 @@ use std::{ any::{Any, TypeId}, cell::UnsafeCell, + mem::MaybeUninit, panic::RefUnwindSafe, + ptr, slice, }; use append_only_vec::AppendOnlyVec; @@ -60,9 +62,8 @@ pub(crate) struct Page { /// that the data is initialized). allocation_lock: Mutex<()>, - /// Vector with data. This is always created with the capacity/length of `PAGE_LEN` - /// and uninitialized data. As we initialize new entries, we increment `allocated`. - data: Vec>, + /// The potentially uninitialized data of this page. As we initialize new entries, we increment `allocated`. + data: Box<[UnsafeCell>; PAGE_LEN]>, } pub(crate) trait Slot: Any + Send + Sync { @@ -169,15 +170,11 @@ impl Table { impl Page { #[allow(clippy::uninit_vec)] fn new(ingredient: IngredientIndex) -> Self { - let mut data = Vec::with_capacity(PAGE_LEN); - unsafe { - data.set_len(PAGE_LEN); - } Self { ingredient, allocated: Default::default(), allocation_lock: Default::default(), - data, + data: Box::new([const { UnsafeCell::new(MaybeUninit::uninit()) }; PAGE_LEN]), } } @@ -196,7 +193,7 @@ impl Page { /// If slot is out of bounds pub(crate) fn get(&self, slot: SlotIndex) -> &T { self.check_bounds(slot); - unsafe { &*self.data[slot.0].get() } + unsafe { (*self.data[slot.0].get()).assume_init_ref() } } /// Returns a raw pointer to the given slot. @@ -211,7 +208,7 @@ impl Page { /// properly with calls to [`get`](`Self::get`) and [`get_mut`](`Self::get_mut`). pub(crate) fn get_raw(&self, slot: SlotIndex) -> *mut T { self.check_bounds(slot); - self.data[slot.0].get() + self.data[slot.0].get().cast() } pub(crate) fn allocate(&self, page: PageIndex, value: V) -> Result @@ -226,7 +223,7 @@ impl Page { // Initialize entry `index` let data = &self.data[index]; - unsafe { std::ptr::write(data.get(), value()) }; + unsafe { (*data.get()).write(value()) }; // Update the length (this must be done after initialization!) self.allocated.store(index + 1); @@ -252,14 +249,13 @@ impl TablePage for Page { impl Drop for Page { fn drop(&mut self) { - // Free `self.data` and the data within: to do this, we swap it out with an empty vector - // and then convert it from a `Vec>` with partially uninitialized values - // to a `Vec` with the correct length. This way the `Vec` drop impl can do its job. - let mut data = std::mem::take(&mut self.data); + // Execute destructors for all initialized elements let len = self.allocated.load(); + // SAFETY: self.data is initialized for T's up to len unsafe { - data.set_len(len); - drop(std::mem::transmute::>, Vec>(data)); + // FIXME: Should be ptr::from_raw_parts_mut but that is unstable + let to_drop = slice::from_raw_parts_mut(self.data.as_mut_ptr().cast::(), len); + ptr::drop_in_place(to_drop) } } }