Skip to content

Commit

Permalink
Replace Page data Vec with boxed fixed array
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Dec 13, 2024
1 parent f4ea167 commit 2d93c35
Showing 1 changed file with 14 additions and 15 deletions.
29 changes: 14 additions & 15 deletions src/table.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::{
any::{Any, TypeId},
cell::UnsafeCell,
mem::MaybeUninit,
panic::RefUnwindSafe,
ptr, slice,
};

use append_only_vec::AppendOnlyVec;
Expand Down Expand Up @@ -62,7 +64,7 @@ pub(crate) struct Page<T: Slot> {

/// 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<UnsafeCell<T>>,
data: Box<[UnsafeCell<MaybeUninit<T>>; PAGE_LEN]>,
}

pub(crate) trait Slot: Any + Send + Sync {
Expand Down Expand Up @@ -169,15 +171,11 @@ impl Table {
impl<T: Slot> Page<T> {
#[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]),
}
}

Expand All @@ -196,7 +194,7 @@ impl<T: Slot> Page<T> {
/// 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.
Expand All @@ -211,7 +209,7 @@ impl<T: Slot> Page<T> {
/// 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<V>(&self, page: PageIndex, value: V) -> Result<Id, V>
Expand All @@ -226,7 +224,7 @@ impl<T: Slot> Page<T> {

// 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);
Expand All @@ -252,14 +250,15 @@ impl<T: Slot> TablePage for Page<T> {

impl<T: Slot> Drop for Page<T> {
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<UnsafeCell<T>>` with partially uninitialized values
// to a `Vec<T>` 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<UnsafeCell<T>>, Vec<T>>(data));
// FIXME: Should be ptr::from_raw_parts_mut but that is unstable
ptr::drop_in_place(slice::from_raw_parts_mut(
&mut *self.data.as_mut_ptr().cast::<T>(),
len,
))
}
}
}
Expand Down

0 comments on commit 2d93c35

Please sign in to comment.