use crate::clone::PClone;
use crate::alloc::MemPool;
use crate::stm::{Journal, Logger};
use crate::*;
use std::cell::UnsafeCell;
use std::cmp::Ordering;
use std::marker::PhantomData;
use std::panic::{RefUnwindSafe, UnwindSafe};
use std::{fmt, mem, ptr};
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))]
use crate::cell::TCell;
pub struct PCell<T: PSafe + ?Sized, A: MemPool> {
heap: PhantomData<A>,
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))]
temp: TCell<Option<*mut T>, A>,
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))]
value: UnsafeCell<T>,
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))]
value: UnsafeCell<(u8, T)>,
}
unsafe impl<T: PSafe + Send + ?Sized, A: MemPool> Send for PCell<T, A> {}
impl<T: PSafe + ?Sized, A: MemPool> RefUnwindSafe for PCell<T, A> {}
impl<T: PSafe + ?Sized, A: MemPool> UnwindSafe for PCell<T, A> {}
unsafe impl<T: PSafe + ?Sized, A: MemPool> TxInSafe for PCell<T, A> {}
unsafe impl<T: PSafe + ?Sized, A: MemPool> PSafe for PCell<T, A> {}
impl<T: ?Sized, A: MemPool> !TxOutSafe for PCell<T, A> {}
impl<T: ?Sized, A: MemPool> !Sync for PCell<T, A> {}
impl<T: ?Sized, A: MemPool> !PSend for PCell<T, A> {}
impl<T: PSafe + Default, A: MemPool> Default for PCell<T, A> {
fn default() -> Self {
PCell {
heap: PhantomData,
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))]
temp: TCell::new_invalid(None),
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))]
value: UnsafeCell::new(T::default()),
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))]
value: UnsafeCell::new((0, T::default())),
}
}
}
impl<T: PSafe + PartialEq + Copy, A: MemPool> PartialEq for PCell<T, A> {
#[inline]
fn eq(&self, other: &PCell<T, A>) -> bool {
self.get() == other.get()
}
}
impl<T: PSafe + Eq + Copy, A: MemPool> Eq for PCell<T, A> {}
impl<T: PSafe + PartialOrd + Copy, A: MemPool> PartialOrd for PCell<T, A> {
#[inline]
fn partial_cmp(&self, other: &PCell<T, A>) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
}
#[inline]
fn lt(&self, other: &PCell<T, A>) -> bool {
self.get() < other.get()
}
#[inline]
fn le(&self, other: &PCell<T, A>) -> bool {
self.get() <= other.get()
}
#[inline]
fn gt(&self, other: &PCell<T, A>) -> bool {
self.get() > other.get()
}
#[inline]
fn ge(&self, other: &PCell<T, A>) -> bool {
self.get() >= other.get()
}
}
impl<T: PSafe + Ord + Copy, A: MemPool> Ord for PCell<T, A> {
#[inline]
fn cmp(&self, other: &PCell<T, A>) -> Ordering {
self.get().cmp(&other.get())
}
}
impl<T: PSafe, A: MemPool> PCell<T, A> {
#[inline]
pub const fn new(value: T) -> PCell<T, A> {
PCell {
heap: PhantomData,
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))]
temp: TCell::new_invalid(None),
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))]
value: UnsafeCell::new(value),
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))]
value: UnsafeCell::new((0, value)),
}
}
#[inline]
#[track_caller]
pub fn set(&self, val: T, journal: &Journal<A>) {
let old = self.replace(val, journal);
drop(old);
}
#[inline]
pub fn swap(&self, other: &Self, journal: &Journal<A>) {
let this = unsafe { self.as_mut() };
let that = unsafe { other.as_mut() };
if ptr::eq(this, that) {
return;
}
self.create_log(journal);
other.create_log(journal);
unsafe {
ptr::swap(this, that);
}
}
#[inline]
#[track_caller]
pub fn replace(&self, val: T, journal: &Journal<A>) -> T {
self.create_log(journal);
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))] {
if let Some(tmp) = *self.temp {
mem::replace(unsafe { &mut *tmp }, val)
} else {
mem::replace(unsafe { &mut *self.value.get() }, val)
}
}
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))]
mem::replace(unsafe { &mut (*self.value.get()).1 }, val)
}
pub fn into_inner(self) -> T {
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))] {
self.value.into_inner()
}
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))] {
self.value.into_inner().1
}
}
#[inline]
fn self_mut(&self) -> &mut Self {
unsafe { &mut *(self as *const Self as *mut Self) }
}
}
impl<T: PSafe, A: MemPool> PCell<T, A> {
#[inline]
pub fn get(&self) -> T where T: Copy {
unsafe {
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))] {
if let Some(tmp) = *self.temp {
*tmp
} else {
*self.value.get()
}
}
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))] {
(*self.value.get()).1
}
}
}
#[inline]
pub fn update<F>(&self, f: F, journal: &Journal<A>) -> T
where
F: FnOnce(T) -> T,
T: Copy
{
let old = self.get();
let new = f(old);
self.set(new, journal);
new
}
}
impl<T: PSafe + ?Sized, A: MemPool> PCell<T, A> {
#[inline]
#[track_caller]
pub(crate) fn create_log(&self, journal: &Journal<A>) {
unsafe {
let inner = &mut *self.value.get();
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))] {
if self.temp.is_none() {
if let Some(p) = journal.draft(inner) {
self.temp.as_mut().replace(p);
}
}
}
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))] {
use crate::ptr::Ptr;
use crate::stm::Notifier;
if inner.0 == 0 {
assert!(A::valid(inner), "The object is not in the pool's valid range");
inner.1.create_log(journal, Notifier::NonAtomic(Ptr::from_ref(&inner.0)));
}
}
}
}
#[inline]
pub fn get_mut(&mut self, journal: &Journal<A>) -> &mut T {
self.create_log(journal);
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))] unsafe {
if let Some(tmp) = *self.temp {
&mut *tmp
} else {
&mut *self.value.get()
}
}
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))] {
unsafe { &mut (*self.value.get()).1 }
}
}
#[inline]
pub unsafe fn as_mut(&self) -> &mut T {
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))] {
if let Some(tmp) = *self.temp {
&mut *tmp
} else {
&mut *self.value.get()
}
}
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))] {
&mut (*self.value.get()).1
}
}
}
impl<T: PSafe + Default, A: MemPool> PCell<T, A> {
#[track_caller]
pub fn take(&self, journal: &Journal<A>) -> T {
self.replace(Default::default(), journal)
}
}
impl<T: fmt::Debug + PSafe + Copy, A: MemPool> fmt::Debug for PCell<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))] {
unsafe { (*self.value.get()).fmt(f) }
}
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))] {
unsafe { (*self.value.get()).1.fmt(f) }
}
}
}
impl<T: PSafe + Logger<A> + Copy, A: MemPool> PClone<A> for PCell<T, A> {
#[inline]
fn pclone(&self, _j: &Journal<A>) -> PCell<T, A> {
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))] {
unsafe { PCell::new(*self.value.get()) }
}
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))] {
unsafe { PCell::new((*self.value.get()).1) }
}
}
}
impl<T: PSafe + Logger<A> + Copy, A: MemPool> Clone for PCell<T, A> {
#[inline]
fn clone(&self) -> PCell<T, A> {
#[cfg(any(feature = "use_pspd", feature = "use_vspd"))] {
unsafe { PCell::new((*self.value.get()).clone()) }
}
#[cfg(not(any(feature = "use_pspd", feature = "use_vspd")))] {
unsafe { PCell::new((*self.value.get()).1.clone()) }
}
}
}