Skip to content

Commit

Permalink
ensure HashMap is invariant with respect to K and V
Browse files Browse the repository at this point in the history
  • Loading branch information
ibraheemdev committed Dec 25, 2024
1 parent e93545f commit 58ad4bc
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 73 deletions.
41 changes: 22 additions & 19 deletions src/raw/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,23 @@ use seize::Collector;
use super::{probe, State};

// A hash-table laid out in a single allocation.
//
// Note that the PhantomData<T> ensures that the hash-table is invariant
// with respect to T, as RawTable is stored behind an AtomicPtr.
#[repr(transparent)]
pub struct RawTable(u8);
pub struct RawTable<T>(PhantomData<T>);

// Safety: `seize::Link` is the first field (see `TableLayout`).
unsafe impl seize::AsLink for RawTable {}
unsafe impl<T> seize::AsLink for RawTable<T> {}

// The layout of the table allocation.
#[repr(C)]
struct TableLayout {
struct TableLayout<T> {
link: seize::Link,
mask: usize,
limit: usize,
capacity: usize,
state: State,
state: State<T>,
meta: [AtomicU8; 0],
entries: [AtomicPtr<()>; 0],
}
Expand All @@ -34,7 +37,7 @@ pub struct Table<T> {
// The probe limit.
pub limit: usize,
// The raw table pointer.
pub raw: *mut RawTable,
pub raw: *mut RawTable<T>,
// The true (padded) table capacity.
capacity: usize,
_t: PhantomData<T>,
Expand Down Expand Up @@ -69,7 +72,7 @@ impl<T> Table<T> {
}

// Write the table state.
ptr.cast::<TableLayout>().write(TableLayout {
ptr.cast::<TableLayout<T>>().write(TableLayout {
link: collector.link(),
mask,
limit,
Expand All @@ -83,23 +86,23 @@ impl<T> Table<T> {
});

// Initialize the meta table.
ptr.add(mem::size_of::<TableLayout>())
ptr.add(mem::size_of::<TableLayout<T>>())
.cast::<u8>()
.write_bytes(super::meta::EMPTY, capacity);

Table {
mask,
limit,
capacity,
raw: ptr.cast::<RawTable>(),
raw: ptr.cast::<RawTable<T>>(),
_t: PhantomData,
}
}
}

// Creates a `Table` from a raw pointer.
#[inline]
pub unsafe fn from_raw(raw: *mut RawTable) -> Table<T> {
pub unsafe fn from_raw(raw: *mut RawTable<T>) -> Table<T> {
if raw.is_null() {
return Table {
raw,
Expand All @@ -110,7 +113,7 @@ impl<T> Table<T> {
};
}

let layout = unsafe { &*raw.cast::<TableLayout>() };
let layout = unsafe { &*raw.cast::<TableLayout<T>>() };

Table {
raw,
Expand All @@ -127,7 +130,7 @@ impl<T> Table<T> {
debug_assert!(i < self.capacity);
&*self
.raw
.add(mem::size_of::<TableLayout>())
.add(mem::size_of::<TableLayout<T>>())
.add(i)
.cast::<AtomicU8>()
}
Expand All @@ -139,7 +142,7 @@ impl<T> Table<T> {

&*self
.raw
.add(mem::size_of::<TableLayout>())
.add(mem::size_of::<TableLayout<T>>())
.add(self.capacity)
.add(i * mem::size_of::<AtomicPtr<T>>())
.cast::<AtomicPtr<T>>()
Expand All @@ -153,14 +156,14 @@ impl<T> Table<T> {

// Returns a reference to the table state.
#[inline]
pub fn state(&self) -> &State {
unsafe { &(*self.raw.cast::<TableLayout>()).state }
pub fn state(&self) -> &State<T> {
unsafe { &(*self.raw.cast::<TableLayout<T>>()).state }
}

// Returns a mutable reference to the table state.
#[inline]
pub fn state_mut(&mut self) -> &mut State {
unsafe { &mut (*self.raw.cast::<TableLayout>()).state }
pub fn state_mut(&mut self) -> &mut State<T> {
unsafe { &mut (*self.raw.cast::<TableLayout<T>>()).state }
}

// Returns a pointer to the next table, if it has already been created.
Expand All @@ -178,16 +181,16 @@ impl<T> Table<T> {
// Deallocate the table.
pub unsafe fn dealloc(table: Table<T>) {
let layout = Self::layout(table.capacity);
ptr::drop_in_place(table.raw.cast::<TableLayout>());
ptr::drop_in_place(table.raw.cast::<TableLayout<T>>());
unsafe { alloc::dealloc(table.raw.cast::<u8>(), layout) }
}

// The table layout used for allocation.
fn layout(capacity: usize) -> Layout {
let size = mem::size_of::<TableLayout>()
let size = mem::size_of::<TableLayout<T>>()
+ (mem::size_of::<u8>() * capacity) // meta
+ (mem::size_of::<usize>() * capacity); // entries
Layout::from_size_align(size, mem::align_of::<TableLayout>()).unwrap()
Layout::from_size_align(size, mem::align_of::<TableLayout<T>>()).unwrap()
}
}

Expand Down
Loading

0 comments on commit 58ad4bc

Please sign in to comment.