use std::{
cell::UnsafeCell,
num::NonZeroUsize,
ops::{Index, IndexMut},
};
use crate::{to_right, Prefix};
#[derive(Clone)]
pub(crate) struct Node<P, T> {
pub(crate) prefix: P,
pub(crate) value: Option<T>,
pub(crate) left: Option<NonZeroUsize>,
pub(crate) right: Option<NonZeroUsize>,
}
impl<P, T> Node<P, T> {
pub(crate) fn prefix_value(&self) -> Option<(&P, &T)> {
self.value.as_ref().map(|v| (&self.prefix, v))
}
pub(crate) fn prefix_value_mut(&mut self) -> Option<(&P, &mut T)> {
self.value.as_mut().map(|v| (&self.prefix, v))
}
}
pub(crate) struct Table<P, T>(UnsafeCell<Vec<Node<P, T>>>);
unsafe impl<P: Send, T: Send> Send for Table<P, T> {}
unsafe impl<P: Sync, T: Sync> Sync for Table<P, T> {}
impl<P, T> AsRef<Vec<Node<P, T>>> for Table<P, T> {
fn as_ref(&self) -> &Vec<Node<P, T>> {
unsafe { self.0.get().as_ref().unwrap() }
}
}
impl<P, T> AsMut<Vec<Node<P, T>>> for Table<P, T> {
fn as_mut(&mut self) -> &mut Vec<Node<P, T>> {
self.0.get_mut()
}
}
impl<P, T, I: Into<usize>> Index<I> for Table<P, T> {
type Output = Node<P, T>;
fn index(&self, index: I) -> &Self::Output {
&self.as_ref()[index.into()]
}
}
impl<P, T> IndexMut<usize> for Table<P, T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.as_mut()[index]
}
}
impl<P: Clone, T: Clone> Clone for Table<P, T> {
fn clone(&self) -> Self {
Self(UnsafeCell::new(self.as_ref().clone()))
}
}
impl<P, T> Default for Table<P, T>
where
P: Prefix,
{
fn default() -> Self {
Self(UnsafeCell::new(vec![Node {
prefix: P::zero(),
value: None,
left: None,
right: None,
}]))
}
}
pub(crate) enum Direction {
Reached,
Enter { next: NonZeroUsize, right: bool },
Missing,
}
pub(crate) enum DirectionForInsert<P> {
Reached,
Enter { next: usize, right: bool },
NewLeaf { right: bool },
NewChild { right: bool, child_right: bool },
NewBranch {
branch_prefix: P,
right: bool,
prefix_right: bool,
},
}
impl<P, T> Table<P, T> {
pub(crate) fn into_inner(self) -> Vec<Node<P, T>> {
self.0.into_inner()
}
#[allow(clippy::mut_from_ref)]
pub(crate) unsafe fn get_mut(&self, idx: usize) -> &mut Node<P, T> {
unsafe {
let len = self.0.get().as_ref().unwrap().len();
if idx >= len {
panic!("index out of bounds: the len is {len} but the index is {idx}");
}
let ptr_to_slice = self.0.get().as_ref().unwrap().as_ptr();
let ptr_to_elem = ptr_to_slice.add(idx);
(ptr_to_elem as *mut Node<P, T>).as_mut().unwrap()
}
}
}
impl<P: Prefix, T> Table<P, T> {
#[inline(always)]
pub(crate) fn get_child(&self, idx: impl Into<usize>, right: bool) -> Option<NonZeroUsize> {
if right {
self[idx.into()].right
} else {
self[idx.into()].left
}
}
#[inline(always)]
pub(crate) fn set_child(
&mut self,
idx: impl Into<usize>,
child: NonZeroUsize,
right: bool,
) -> Option<NonZeroUsize> {
if right {
self[idx.into()].right.replace(child)
} else {
self[idx.into()].left.replace(child)
}
}
#[inline(always)]
pub(crate) fn clear_child(
&mut self,
idx: impl Into<usize>,
right: bool,
) -> Option<NonZeroUsize> {
if right {
self[idx.into()].right.take()
} else {
self[idx.into()].left.take()
}
}
#[inline(always)]
pub(crate) fn get_direction(&self, cur: impl Into<usize>, prefix: &P) -> Direction {
let cur: usize = cur.into();
let cur_p = &self[cur].prefix;
if cur_p.eq(prefix) {
Direction::Reached
} else {
let right = to_right(cur_p, prefix);
match self.get_child(cur, right) {
Some(next) if self[next].prefix.contains(prefix) => {
Direction::Enter { next, right }
}
_ => Direction::Missing,
}
}
}
#[inline(always)]
pub(crate) fn get_direction_for_insert(&self, cur: usize, prefix: &P) -> DirectionForInsert<P> {
let cur_p = &self[cur].prefix;
if cur_p.eq(prefix) {
DirectionForInsert::Reached
} else {
let right = to_right(cur_p, prefix);
if let Some(next) = self.get_child(cur, right) {
let child_p = &self[next].prefix;
if child_p.contains(prefix) {
DirectionForInsert::Enter {
next: next.get(),
right,
}
} else if prefix.contains(child_p) {
DirectionForInsert::NewChild {
right,
child_right: to_right(prefix, child_p),
}
} else {
let branch_prefix = prefix.longest_common_prefix(child_p);
let prefix_right = to_right(&branch_prefix, prefix);
DirectionForInsert::NewBranch {
branch_prefix,
right,
prefix_right,
}
}
} else {
DirectionForInsert::NewLeaf { right }
}
}
}
}