use std::cell::UnsafeCell;
use std::cmp::Ordering;
use std::ptr as StdPtr;
use std::sync::atomic::{AtomicPtr, Ordering as AtomicOrdering};
use seize::{Guard, LocalGuard};
use crate::TreePermutation;
use crate::suffix::{InlineSuffixBag, SideCarUtils, SuffixBagCell};
use super::SuffixStore;
use super::suffix_ops as SuffixOps;
#[repr(C)]
pub struct EmbeddedSuffix {
inline_ksuf: UnsafeCell<InlineSuffixBag>,
external_ksuf: AtomicPtr<SuffixBagCell>,
}
unsafe impl Send for EmbeddedSuffix {}
unsafe impl Sync for EmbeddedSuffix {}
impl EmbeddedSuffix {
#[inline(always)]
fn inline_bag(&self) -> &InlineSuffixBag {
unsafe { &*self.inline_ksuf.get() }
}
}
impl SuffixStore for EmbeddedSuffix {
#[inline(always)]
fn new() -> Self {
Self {
inline_ksuf: UnsafeCell::new(InlineSuffixBag::new()),
external_ksuf: AtomicPtr::new(StdPtr::null_mut()),
}
}
#[inline(always)]
fn get(&self, slot: usize) -> Option<&[u8]> {
SuffixOps::get_suffix(self.inline_bag(), &self.external_ksuf, slot)
}
#[inline(always)]
fn suffix_equals(&self, slot: usize, suffix: &[u8]) -> bool {
SuffixOps::suffix_equals(self.inline_bag(), &self.external_ksuf, slot, suffix)
}
#[inline(always)]
fn suffix_compare(&self, slot: usize, suffix: &[u8]) -> Option<Ordering> {
SuffixOps::suffix_compare(self.inline_bag(), &self.external_ksuf, slot, suffix)
}
#[inline(always)]
fn has_external(&self) -> bool {
SuffixOps::has_external(&self.external_ksuf)
}
#[inline(always)]
fn prefetch(&self) {
}
#[inline(always)]
unsafe fn assign(
&self,
slot: usize,
suffix: &[u8],
perm: &impl TreePermutation,
_guard: &LocalGuard<'_>,
) -> *mut u8 {
unsafe {
SuffixOps::assign_suffix(self.inline_bag(), &self.external_ksuf, slot, suffix, perm)
}
}
#[inline(always)]
unsafe fn assign_init(&self, slot: usize, suffix: &[u8], guard: &LocalGuard<'_>) {
unsafe {
SuffixOps::assign_suffix_init(
self.inline_bag(),
&self.external_ksuf,
slot,
suffix,
guard,
);
}
}
#[inline(always)]
unsafe fn assign_prealloc(
&self,
slot: usize,
suffix: &[u8],
perm: &impl TreePermutation,
_guard: &LocalGuard<'_>,
prealloc: Vec<u8>,
) -> *mut u8 {
unsafe {
SuffixOps::assign_suffix_prealloc(
self.inline_bag(),
&self.external_ksuf,
slot,
suffix,
perm,
prealloc,
)
}
}
#[inline(always)]
unsafe fn ensure_external(&self) -> *mut SuffixBagCell {
unsafe { SuffixOps::ensure_external_bag(&self.external_ksuf) }
}
#[inline(always)]
unsafe fn clear(&self, slot: usize, _guard: &LocalGuard<'_>) {
unsafe { SuffixOps::clear_suffix(self.inline_bag(), &self.external_ksuf, slot) }
}
#[inline(always)]
unsafe fn retire_bag_ptr(ptr: *mut u8, guard: &LocalGuard<'_>) {
if ptr.is_null() {
return;
}
unsafe {
guard.defer_retire(ptr.cast::<SuffixBagCell>(), |ptr, collector| {
SideCarUtils::retire_suffix_bag_cell(ptr, collector);
});
}
}
unsafe fn drop_storage(&mut self) {
let external: *mut SuffixBagCell = self.external_ksuf.load(AtomicOrdering::Acquire);
if !external.is_null() {
unsafe {
drop(Box::from_raw(external));
}
}
}
unsafe fn init_at_zero(ptr: *mut Self) {
unsafe {
let bag_ptr: *mut InlineSuffixBag = StdPtr::addr_of_mut!((*ptr).inline_ksuf).cast();
StdPtr::write(bag_ptr, InlineSuffixBag::new());
}
}
}