use std::cmp::Ordering;
use std::ptr as StdPtr;
use std::sync::atomic::{AtomicPtr, Ordering as AtomicOrdering};
use seize::{Collector, Guard, LocalGuard};
use crate::TreePermutation;
use crate::prefetch::prefetch_read;
use crate::suffix::{SideCarUtils, SuffixBagCell, SuffixSidecar};
use super::SuffixStore;
use super::suffix_ops as SuffixOps;
#[repr(C)]
pub struct SidecarSuffix {
sidecar: AtomicPtr<SuffixSidecar>,
}
unsafe impl Send for SidecarSuffix {}
unsafe impl Sync for SidecarSuffix {}
impl SidecarSuffix {
#[inline(always)]
fn sidecar_ptr(&self) -> *mut SuffixSidecar {
self.sidecar.load(AtomicOrdering::Acquire)
}
#[inline]
unsafe fn ensure_sidecar(&self) -> *mut SuffixSidecar {
let ptr: *mut SuffixSidecar = self.sidecar.load(AtomicOrdering::Acquire);
if !ptr.is_null() {
return ptr;
}
let new_sidecar: Box<SuffixSidecar> = Box::default();
let ptr: *mut SuffixSidecar = Box::into_raw(new_sidecar);
self.sidecar.store(ptr, AtomicOrdering::Release);
ptr
}
}
impl SuffixStore for SidecarSuffix {
#[inline(always)]
fn new() -> Self {
Self {
sidecar: AtomicPtr::new(StdPtr::null_mut()),
}
}
#[inline(always)]
fn get(&self, slot: usize) -> Option<&[u8]> {
let ptr: *mut SuffixSidecar = self.sidecar_ptr();
if ptr.is_null() {
return None;
}
let sidecar: &SuffixSidecar = unsafe { &*ptr };
SuffixOps::get_suffix(&sidecar.inline, &sidecar.external, slot)
}
#[inline(always)]
fn suffix_equals(&self, slot: usize, suffix: &[u8]) -> bool {
let ptr: *mut SuffixSidecar = self.sidecar_ptr();
if ptr.is_null() {
return false;
}
let sidecar: &SuffixSidecar = unsafe { &*ptr };
SuffixOps::suffix_equals(&sidecar.inline, &sidecar.external, slot, suffix)
}
#[inline(always)]
fn suffix_compare(&self, slot: usize, suffix: &[u8]) -> Option<Ordering> {
let ptr: *mut SuffixSidecar = self.sidecar_ptr();
if ptr.is_null() {
return None;
}
let sidecar: &SuffixSidecar = unsafe { &*ptr };
SuffixOps::suffix_compare(&sidecar.inline, &sidecar.external, slot, suffix)
}
#[inline(always)]
fn has_external(&self) -> bool {
let ptr: *mut SuffixSidecar = self.sidecar_ptr();
if ptr.is_null() {
return false;
}
let sidecar: &SuffixSidecar = unsafe { &*ptr };
SuffixOps::has_external(&sidecar.external)
}
#[inline(always)]
fn prefetch(&self) {
let ptr: *mut SuffixSidecar = self.sidecar.load(AtomicOrdering::Relaxed);
if !ptr.is_null() {
prefetch_read(ptr);
let external_offset: usize = std::mem::offset_of!(SuffixSidecar, external);
let external_addr: *const u8 = (ptr as *const u8).wrapping_add(external_offset);
prefetch_read(external_addr);
}
}
#[inline(always)]
unsafe fn assign(
&self,
slot: usize,
suffix: &[u8],
perm: &impl TreePermutation,
_guard: &LocalGuard<'_>,
) -> *mut u8 {
let sidecar_ptr: *mut SuffixSidecar = unsafe { self.ensure_sidecar() };
let sidecar: &SuffixSidecar = unsafe { &*sidecar_ptr };
unsafe { SuffixOps::assign_suffix(&sidecar.inline, &sidecar.external, slot, suffix, perm) }
}
#[inline(always)]
unsafe fn assign_init(&self, slot: usize, suffix: &[u8], guard: &LocalGuard<'_>) {
let sidecar_ptr: *mut SuffixSidecar = unsafe { self.ensure_sidecar() };
let sidecar: &SuffixSidecar = unsafe { &*sidecar_ptr };
unsafe {
SuffixOps::assign_suffix_init(&sidecar.inline, &sidecar.external, slot, suffix, guard);
}
}
#[inline(always)]
unsafe fn assign_prealloc(
&self,
slot: usize,
suffix: &[u8],
perm: &impl TreePermutation,
_guard: &LocalGuard<'_>,
prealloc: Vec<u8>,
) -> *mut u8 {
let sidecar_ptr: *mut SuffixSidecar = unsafe { self.ensure_sidecar() };
let sidecar: &SuffixSidecar = unsafe { &*sidecar_ptr };
unsafe {
SuffixOps::assign_suffix_prealloc(
&sidecar.inline,
&sidecar.external,
slot,
suffix,
perm,
prealloc,
)
}
}
#[inline(always)]
unsafe fn ensure_external(&self) -> *mut SuffixBagCell {
let sidecar_ptr: *mut SuffixSidecar = unsafe { self.ensure_sidecar() };
let sidecar: &SuffixSidecar = unsafe { &*sidecar_ptr };
unsafe { SuffixOps::ensure_external_bag(&sidecar.external) }
}
#[inline(always)]
unsafe fn clear(&self, slot: usize, _guard: &LocalGuard<'_>) {
let ptr: *mut SuffixSidecar = self.sidecar_ptr();
if ptr.is_null() {
return;
}
let sidecar: &SuffixSidecar = unsafe { &*ptr };
unsafe { SuffixOps::clear_suffix(&sidecar.inline, &sidecar.external, 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: *mut SuffixBagCell, collector: &Collector| {
SideCarUtils::retire_suffix_bag_cell(ptr, collector);
},
);
}
}
unsafe fn drop_storage(&mut self) {
let ptr: *mut SuffixSidecar = self.sidecar.load(AtomicOrdering::Acquire);
if !ptr.is_null() {
unsafe {
drop(Box::from_raw(ptr));
}
}
}
unsafe fn init_at_zero(_ptr: *mut Self) {
}
}