use std::cell::Cell;
use std::sync::atomic::{AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize, Ordering};
pub trait RefCount {
type Value;
fn one() -> Self;
fn is_one(val: &Self::Value) -> bool;
fn load_acquire(&self) -> Self::Value;
fn fence_acquire(&self);
fn fetch_inc_relaxed(&self) -> Self::Value;
fn fetch_dec_release(&self) -> Self::Value;
}
macro_rules! impl_cell_refcount {
($type:ty) => {
impl RefCount for Cell<$type> {
type Value = $type;
#[inline(always)]
fn one() -> Self {
Self::new(1)
}
#[inline(always)]
fn is_one(val: &Self::Value) -> bool {
*val == 1
}
#[inline(always)]
fn load_acquire(&self) -> Self::Value {
self.get()
}
#[inline(always)]
fn fence_acquire(&self) {
}
#[inline(always)]
fn fetch_inc_relaxed(&self) -> Self::Value {
let count = self.load_acquire();
assume!(count != 0);
match count.checked_add(1) {
Some(c) => {
self.set(c);
count
}
None => std::process::abort(), }
}
#[inline(always)]
fn fetch_dec_release(&self) -> Self::Value {
let count = self.load_acquire();
assume!(0 < count);
self.set(count - 1);
count
}
}
};
}
impl_cell_refcount!(u8);
impl_cell_refcount!(u16);
impl_cell_refcount!(u32);
impl_cell_refcount!(u64);
impl_cell_refcount!(usize);
macro_rules! impl_atomic_refcount {
($type:ty, $value_type:ty) => {
impl RefCount for $type {
type Value = $value_type;
#[inline(always)]
fn one() -> Self {
Self::new(1)
}
#[inline(always)]
fn is_one(val: &Self::Value) -> bool {
*val == 1
}
#[inline(always)]
fn load_acquire(&self) -> Self::Value {
self.load(Ordering::Acquire)
}
#[inline(always)]
fn fence_acquire(&self) {
let _count = self.load_acquire();
}
#[inline(always)]
fn fetch_inc_relaxed(&self) -> Self::Value {
let count = self.fetch_add(1, Ordering::Relaxed);
if count == <$value_type>::MAX {
std::process::abort();
}
count
}
#[inline(always)]
fn fetch_dec_release(&self) -> Self::Value {
let count = self.fetch_sub(1, Ordering::Release);
assume!(0 < count);
count
}
}
};
}
impl_atomic_refcount!(AtomicU8, u8);
impl_atomic_refcount!(AtomicU16, u16);
impl_atomic_refcount!(AtomicU32, u32);
impl_atomic_refcount!(AtomicU64, u64);
impl_atomic_refcount!(AtomicUsize, usize);