mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-02-02 09:46:06 +00:00
Replace Page
data Vec with boxed fixed array
This commit is contained in:
parent
5cd2b63ef0
commit
a861b14abe
1 changed files with 13 additions and 17 deletions
30
src/table.rs
30
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<T: Slot> {
|
|||
/// 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<UnsafeCell<T>>,
|
||||
/// The potentially uninitialized data of this page. As we initialize new entries, we increment `allocated`.
|
||||
data: Box<[UnsafeCell<MaybeUninit<T>>; PAGE_LEN]>,
|
||||
}
|
||||
|
||||
pub(crate) trait Slot: Any + Send + Sync {
|
||||
|
@ -169,15 +170,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]),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +193,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.
|
||||
|
@ -211,7 +208,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>
|
||||
|
@ -226,7 +223,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);
|
||||
|
@ -252,14 +249,13 @@ 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
|
||||
let to_drop = slice::from_raw_parts_mut(self.data.as_mut_ptr().cast::<T>(), len);
|
||||
ptr::drop_in_place(to_drop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue