use crate::internal::{
epoch::EpochLock, pointer::PtrExt, seq_storage, usize_aligned::UsizeAligned,
};
use std::{
mem::{self, ManuallyDrop},
num::NonZeroUsize,
ptr::NonNull,
sync::atomic::{
AtomicUsize,
Ordering::{self, Acquire, Relaxed},
},
};
#[repr(transparent)]
#[derive(Debug)]
pub struct TCellErased {
pub current_epoch: EpochLock,
}
impl TCellErased {
#[inline]
pub const fn new() -> TCellErased {
TCellErased {
current_epoch: EpochLock::first(),
}
}
#[inline]
unsafe fn read_usize<T>(&self, ordering: Ordering) -> ManuallyDrop<T> {
debug_assert!(
mem::size_of::<T>() <= mem::size_of::<usize>(),
"attempt to read a > sizeof(usize) type as a usized type"
);
let ptr = self.as_atomic_ptr(NonZeroUsize::new_unchecked(1));
let a: UsizeAligned<ManuallyDrop<T>> = mem::transmute_copy(&ptr.as_ref().load(ordering));
a.into_inner()
}
#[inline]
pub unsafe fn read_inconsistent<T>(&self) -> ManuallyDrop<T> {
self.read_usize::<T>(Relaxed)
}
#[inline]
pub unsafe fn read_acquire<T>(&self) -> ManuallyDrop<T> {
if mem::size_of::<T>() <= mem::size_of::<usize>() {
self.read_usize::<T>(Acquire)
} else {
let mut a: UsizeAligned<ManuallyDrop<T>> = mem::uninitialized();
self.load_acquire(a.as_mut());
a.into_inner()
}
}
#[inline]
pub unsafe fn read_relaxed<T>(&self) -> ManuallyDrop<T> {
if mem::size_of::<T>() <= mem::size_of::<usize>() {
self.read_inconsistent()
} else {
let mut a: UsizeAligned<ManuallyDrop<T>> = mem::uninitialized();
self.load_relaxed(a.as_mut());
a.into_inner()
}
}
#[inline]
unsafe fn load_acquire(&self, dest: &mut [usize]) {
let len = dest.len();
assume!(len > 0, "`load_acquire` does not work for zero sized types");
let len = NonZeroUsize::new_unchecked(len);
seq_storage::load_nonoverlapping_acquire(self.as_atomic_ptr(len), dest)
}
#[inline]
unsafe fn load_relaxed(&self, dest: &mut [usize]) {
let len = dest.len();
assume!(len > 0, "`load_relaxed` does not work for zero sized types");
let len = NonZeroUsize::new_unchecked(len);
seq_storage::load_nonoverlapping_relaxed(self.as_atomic_ptr(len), dest)
}
#[inline]
pub unsafe fn store_release(&self, src: &[usize]) {
let len = src.len();
assume!(
len > 0,
"`store_release` does not work for zero sized types"
);
let len = NonZeroUsize::new_unchecked(len);
seq_storage::store_nonoverlapping_release(self.as_atomic_ptr(len), src)
}
#[inline]
pub unsafe fn as_atomic_ptr(&self, len: NonZeroUsize) -> NonNull<AtomicUsize> {
assume!(len.get() > 0);
NonNull::from(self).cast().sub(len.get())
}
}