use core::{mem, ptr};
use crate::sync::Link;
use super::{super::arena::ArenaError, *};
#[derive(Debug)]
pub(crate) struct NodePtr<T> {
pub(super) ptr: *const Node<T>,
pub(super) offset: u32,
}
impl<T> Clone for NodePtr<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for NodePtr<T> {}
impl<T> NodePtr<T> {
pub(super) const NULL: Self = Self {
ptr: ptr::null(),
offset: 0,
};
#[inline]
pub(super) const fn new(ptr: *const u8, offset: u32) -> Self {
Self {
ptr: ptr.cast(),
offset,
}
}
#[inline]
pub(super) fn is_null(&self) -> bool {
self.ptr.is_null()
}
#[inline]
pub(super) const unsafe fn as_ptr(&self) -> &Node<T> {
&*self.ptr.cast()
}
#[inline]
pub(super) unsafe fn tower(&self, arena: &Arena, idx: usize) -> &Link {
let tower_ptr_offset = self.offset as usize + Node::<T>::SIZE + idx * Link::SIZE;
let tower_ptr = arena.get_pointer(tower_ptr_offset);
&*tower_ptr.cast()
}
#[inline]
pub(super) unsafe fn write_tower(
&self,
arena: &Arena,
idx: usize,
prev_offset: u32,
next_offset: u32,
) {
let tower_ptr_offset = self.offset as usize + Node::<T>::SIZE + idx * Link::SIZE;
let tower_ptr: *mut Link = arena.get_pointer_mut(tower_ptr_offset).cast();
*tower_ptr = Link::new(next_offset, prev_offset);
}
pub(super) unsafe fn next_offset(&self, arena: &Arena, idx: usize) -> u32 {
self.tower(arena, idx).next_offset.load(Ordering::Acquire)
}
pub(super) unsafe fn prev_offset(&self, arena: &Arena, idx: usize) -> u32 {
self.tower(arena, idx).prev_offset.load(Ordering::Acquire)
}
}
#[derive(Debug)]
#[repr(C)]
pub(super) struct Node<T> {
pub(super) trailer: T,
pub(super) key_offset: u32,
pub(super) key_size: u16,
pub(super) height: u16,
pub(super) value_size: u32,
pub(super) alloc_size: u32,
}
impl<T> Node<T> {
pub(super) const SIZE: usize = mem::size_of::<Self>();
pub(super) const MAX_NODE_SIZE: u64 = (Self::SIZE + MAX_HEIGHT * Link::SIZE) as u64;
#[inline]
pub(super) const fn min_cap() -> usize {
(Node::<T>::MAX_NODE_SIZE * 2) as usize
}
#[inline]
pub(super) const fn alignment() -> u32 {
let alignment = mem::align_of::<T>();
let alignment = if alignment < mem::size_of::<u32>() {
mem::size_of::<u32>()
} else {
alignment
};
alignment as u32
}
#[inline]
const fn max_node_size() -> u32 {
Node::<T>::MAX_NODE_SIZE as u32
}
pub(super) fn new_empty_node_ptr(arena: &Arena) -> Result<NodePtr<T>, ArenaError> {
let (node_offset, alloc_size) = arena.alloc(Self::max_node_size(), Self::alignment(), 0)?;
unsafe {
let ptr = arena.get_pointer_mut(node_offset as usize);
let node = &mut *(ptr as *mut Node<T>);
node.key_offset = 0;
node.key_size = 0;
node.value_size = 0;
node.height = MAX_HEIGHT as u16;
node.alloc_size = alloc_size;
Ok(NodePtr::new(ptr, node_offset))
}
}
}
impl<T: Trailer> Node<T> {
pub(super) fn new_node_ptr<'a, 'b: 'a, E>(
arena: &'a Arena,
height: u32,
key: &'b [u8],
trailer: T,
value_size: u32,
f: impl FnOnce(OccupiedValue<'a>) -> Result<(), E>,
) -> Result<NodePtr<T>, Either<E, Error>> {
if height < 1 || height > MAX_HEIGHT as u32 {
panic!("height cannot be less than one or greater than the max height");
}
let key_size = key.len();
if key_size as u64 > u32::MAX as u64 {
return Err(Either::Right(Error::KeyTooLarge(key_size as u64)));
}
if value_size as u64 > u32::MAX as u64 {
return Err(Either::Right(Error::ValueTooLarge(value_size as u64)));
}
let entry_size = (value_size as u64) + (key_size as u64) + Node::<T>::MAX_NODE_SIZE;
if entry_size > u32::MAX as u64 {
return Err(Either::Right(Error::EntryTooLarge(entry_size)));
}
let unused_size = (MAX_HEIGHT as u32 - height) * (Link::SIZE as u32);
let node_size = (Self::MAX_NODE_SIZE as u32) - unused_size;
let (node_offset, alloc_size) = arena
.alloc(
node_size + key_size as u32 + value_size,
Self::alignment(),
unused_size,
)
.map_err(|e| Either::Right(e.into()))?;
unsafe {
let ptr = arena.get_pointer_mut(node_offset as usize);
let node = &mut *(ptr as *mut Node<T>);
node.trailer = trailer;
node.key_offset = node_offset + node_size;
node.key_size = key_size as u16;
node.height = height as u16;
node.value_size = value_size;
node.alloc_size = alloc_size;
node.get_key_mut(arena).copy_from_slice(key);
f(OccupiedValue::new(
value_size as usize,
node.get_value_mut(arena),
))
.map_err(Either::Left)?;
Ok(NodePtr::new(ptr, node_offset))
}
}
}
impl<T> Node<T> {
pub(super) unsafe fn get_key<'a, 'b: 'a>(&'a self, arena: &'b Arena) -> &'b [u8] {
arena.get_bytes(self.key_offset as usize, self.key_size as usize)
}
#[allow(clippy::mut_from_ref)]
pub(super) unsafe fn get_key_mut<'a, 'b: 'a>(&'a mut self, arena: &'b Arena) -> &'b mut [u8] {
arena.get_bytes_mut(self.key_offset as usize, self.key_size as usize)
}
pub(super) unsafe fn get_value<'a, 'b: 'a>(&'a self, arena: &'b Arena) -> &'b [u8] {
arena.get_bytes(
self.key_offset as usize + self.key_size as usize,
self.value_size as usize,
)
}
#[allow(clippy::mut_from_ref)]
pub(super) unsafe fn get_value_mut<'a, 'b: 'a>(&'a mut self, arena: &'b Arena) -> &'b mut [u8] {
arena.get_bytes_mut(
self.key_offset as usize + self.key_size as usize,
self.value_size as usize,
)
}
}
#[cfg(test)]
#[test]
fn test_clone() {
let node_ptr = NodePtr::<u8>::NULL;
#[allow(clippy::clone_on_copy)]
let _ = node_ptr.clone();
}