use std::alloc::Layout;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::num::NonZeroUsize;
use std::ops::Deref;
use std::ptr::{addr_of, NonNull};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use std::thread::available_parallelism;
use fast_smr::smr;
use fast_smr::smr::{Reclaimer, ThreadContext};
pub(crate) static RECLAIMER: Reclaimer = Reclaimer::new();
thread_local! {
pub(crate) static CTX: RefCell<ThreadContext<'static>> = RefCell::new(
RECLAIMER.get_ctx(available_parallelism().map_or(8usize, NonZeroUsize::get)));
}
pub struct Guard<'a, T> {
pub(crate) guard: smr::Guard<'a, ArcInner<T>>,
}
impl<'a, T> Guard<'a, T> {
pub(crate) fn inner_ptr(this: &Self) -> *const ArcInner<T> {
this.guard.as_ptr()
}
pub(crate) fn data_ptr(this: &Self) -> *const T {
unsafe { addr_of!((*Self::inner_ptr(this)).data) }
}
}
impl<'a, T> Deref for Guard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::data_ptr(self) }
}
}
pub struct Arc<T> {
pub(crate) ptr: NonNull<ArcInner<T>>,
pub(crate) phantom: PhantomData<ArcInner<T>>,
}
impl<T> Arc<T> {
pub fn new(data: T) -> Self {
unsafe {
let ptr = NonNull::new_unchecked(ArcInner::new(data));
Self {
ptr,
phantom: PhantomData,
}
}
}
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
&mut (*this.ptr.as_ptr()).data
}
pub unsafe fn from_raw(ptr: *const T) -> Self {
Self {
ptr: NonNull::new_unchecked(find_inner_ptr(ptr).cast_mut()),
phantom: PhantomData,
}
}
pub fn ref_count(this: &Arc<T>) -> usize {
unsafe { (*this.ptr.as_ptr()).ref_count.load(SeqCst) }
}
pub(crate) fn inner_ptr(this: &Self) -> *const ArcInner<T> {
this.ptr.as_ptr()
}
pub(crate) fn data_ptr(this: &Self) -> *const T {
unsafe { addr_of!((*Self::inner_ptr(this)).data) }
}
}
impl<T> Clone for Arc<T> {
fn clone(&self) -> Self {
unsafe {
ArcInner::increment(self.ptr.as_ptr());
}
Self {
ptr: self.ptr,
phantom: PhantomData,
}
}
}
impl<T> Deref for Arc<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::data_ptr(self) }
}
}
impl<T> Drop for Arc<T> {
fn drop(&mut self) {
unsafe {
ArcInner::delayed_decrement(self.ptr.as_ptr());
}
}
}
impl<'a, T> From<&Guard<'a, T>> for Arc<T> {
fn from(value: &Guard<'a, T>) -> Self {
unsafe {
let inner_ptr = Guard::inner_ptr(value);
_ = (*inner_ptr).ref_count.fetch_add(1, SeqCst);
Self {
ptr: NonNull::new_unchecked(inner_ptr.cast_mut()),
phantom: PhantomData,
}
}
}
}
impl<'a, T> From<&Arc<T>> for Guard<'a, T> {
fn from(value: &Arc<T>) -> Self {
let guard = CTX.with_borrow(|ctx| ctx.must_protect(value.ptr));
Guard { guard }
}
}
pub(crate) unsafe fn find_inner_ptr<T>(ptr: *const T) -> *const ArcInner<T> {
let layout = Layout::new::<ArcInner<()>>();
let offset = layout.size() + padding_needed_for(&layout, align_of::<T>());
ptr.byte_sub(offset) as *const ArcInner<T>
}
fn padding_needed_for(layout: &Layout, align: usize) -> usize {
let len = layout.size();
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
len_rounded_up.wrapping_sub(len)
}
#[repr(C)]
pub(crate) struct ArcInner<T> {
pub(crate) birth_epoch: u64,
pub(crate) ref_count: AtomicUsize,
pub(crate) data: T,
}
impl<T> ArcInner<T> {
pub(crate) fn new(data: T) -> *mut Self {
Box::into_raw(Box::new(ArcInner {
birth_epoch: RECLAIMER.current_epoch(),
ref_count: AtomicUsize::new(1),
data,
}))
}
pub(crate) unsafe fn increment(ptr: *mut Self) {
_ = (*ptr).ref_count.fetch_add(1, SeqCst);
}
pub(crate) unsafe fn delayed_decrement(ptr: *mut ArcInner<T>) {
CTX.with_borrow(|ctx| {
ctx.retire(
ptr as *mut u8,
Layout::new::<ArcInner<T>>(),
Self::decrement,
(*ptr).birth_epoch,
);
});
}
unsafe fn decrement(ptr: *mut u8, _layout: Layout) {
let inner_ptr = ptr as *mut ArcInner<T>;
if (*inner_ptr).ref_count.fetch_sub(1, SeqCst) == 1 {
drop(Box::from_raw(inner_ptr));
}
}
}
impl<T> From<&Arc<T>> for NonNull<T> {
fn from(value: &Arc<T>) -> Self {
unsafe { NonNull::new_unchecked(Arc::data_ptr(value).cast_mut()) }
}
}
impl<'a, T> From<&Guard<'a, T>> for NonNull<T> {
fn from(value: &Guard<'a, T>) -> Self {
unsafe { NonNull::new_unchecked(Guard::data_ptr(value).cast_mut()) }
}
}
#[cfg(test)]
mod tests {
use crate::{Arc, Guard};
#[test]
fn basic_test() {
let x = Arc::new(55usize);
assert_eq!(*x, 55);
assert_eq!(Arc::ref_count(&x), 1);
let y = Guard::from(&x);
assert_eq!(*x, *y);
drop(x);
assert_eq!(*y, 55);
drop(y);
}
}