use crate::clone::PClone;
use std::cell::UnsafeCell;
use std::cmp::Ordering;
use std::marker::PhantomData;
use std::panic::{RefUnwindSafe, UnwindSafe};
use crate::alloc::MemPool;
use crate::ptr::Ptr;
use crate::stm::{Journal, Notifier, Logger};
use crate::{PSafe,TxInSafe,TxOutSafe};
use std::{fmt, mem, ptr};
pub struct LogCell<T: PSafe + ?Sized, A: MemPool> {
heap: PhantomData<A>,
value: UnsafeCell<(u8, T)>,
}
unsafe impl<T: PSafe + Send + ?Sized, A: MemPool> Send for LogCell<T, A> {}
impl<T: PSafe + ?Sized, A: MemPool> RefUnwindSafe for LogCell<T, A> {}
impl<T: PSafe + ?Sized, A: MemPool> UnwindSafe for LogCell<T, A> {}
unsafe impl<T: PSafe + ?Sized, A: MemPool> TxInSafe for LogCell<T, A> {}
unsafe impl<T: PSafe + ?Sized, A: MemPool> PSafe for LogCell<T, A> {}
impl<T: ?Sized, A: MemPool> !TxOutSafe for LogCell<T, A> {}
impl<T: ?Sized, A: MemPool> !Sync for LogCell<T, A> {}
impl<T: PSafe + Default, A: MemPool> Default for LogCell<T, A> {
fn default() -> Self {
LogCell {
heap: PhantomData,
value: UnsafeCell::new((0, T::default())),
}
}
}
impl<T: PSafe + PartialEq + Copy, A: MemPool> PartialEq for LogCell<T, A> {
#[inline]
fn eq(&self, other: &LogCell<T, A>) -> bool {
self.get() == other.get()
}
}
impl<T: PSafe + Eq + Copy, A: MemPool> Eq for LogCell<T, A> {}
impl<T: PSafe + PartialOrd + Copy, A: MemPool> PartialOrd for LogCell<T, A> {
#[inline]
fn partial_cmp(&self, other: &LogCell<T, A>) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
}
#[inline]
fn lt(&self, other: &LogCell<T, A>) -> bool {
self.get() < other.get()
}
#[inline]
fn le(&self, other: &LogCell<T, A>) -> bool {
self.get() <= other.get()
}
#[inline]
fn gt(&self, other: &LogCell<T, A>) -> bool {
self.get() > other.get()
}
#[inline]
fn ge(&self, other: &LogCell<T, A>) -> bool {
self.get() >= other.get()
}
}
impl<T: PSafe + Ord + Copy, A: MemPool> Ord for LogCell<T, A> {
#[inline]
fn cmp(&self, other: &LogCell<T, A>) -> Ordering {
self.get().cmp(&other.get())
}
}
impl<T: PSafe, A: MemPool> LogCell<T, A> {
#[inline]
pub const fn new(value: T, _j: &Journal<A>) -> LogCell<T, A> {
LogCell {
heap: PhantomData,
value: UnsafeCell::new((0, value)),
}
}
#[inline]
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 { &mut (*self.value.get()).1 };
let that = unsafe { &mut (*other.value.get()).1 };
if ptr::eq(this, that) {
return;
}
self.take_log(journal);
other.take_log(journal);
unsafe {
ptr::swap(this, that);
}
}
pub fn replace(&self, val: T, journal: &Journal<A>) -> T {
self.take_log(journal);
mem::replace(unsafe { &mut (*self.value.get()).1 }, val)
}
pub fn into_inner(self) -> T {
self.value.into_inner().1
}
#[inline]
fn self_mut(&self) -> &mut Self {
unsafe { &mut *(self as *const Self as *mut Self) }
}
#[inline]
pub fn add(&self, val: T, journal: &Journal<A>)
where
T: std::ops::AddAssign,
{
let v = self.self_mut().get_mut(journal);
*v += val;
}
#[inline]
pub fn sub(&self, val: T, journal: &Journal<A>)
where
T: std::ops::SubAssign,
{
let v = self.self_mut().get_mut(journal);
*v -= val;
}
#[inline]
pub fn mul(&self, val: T, journal: &Journal<A>)
where
T: std::ops::MulAssign,
{
let v = self.self_mut().get_mut(journal);
*v *= val;
}
#[inline]
pub fn div(&self, val: T, journal: &Journal<A>)
where
T: std::ops::DivAssign,
{
let v = self.self_mut().get_mut(journal);
*v /= val;
}
#[inline]
pub fn rem(&self, val: T, journal: &Journal<A>)
where
T: std::ops::RemAssign,
{
let v = self.self_mut().get_mut(journal);
*v %= val;
}
}
impl<T: PSafe, A: MemPool> LogCell<T, A> {
#[inline]
pub fn get(&self) -> T where T: Copy {
unsafe { (*self.value.get()).1 }
}
#[inline]
pub fn get_ref(&self) -> &T {
unsafe { &(*self.value.get()).1 }
}
#[inline]
pub fn update<F>(&self, journal: &Journal<A>, f: F) -> T
where
F: FnOnce(T) -> T,
T: Copy
{
let old = self.get();
let new = f(old);
self.set(new, journal);
new
}
pub fn update_inplace<F>(&self, f: F)
where
F: FnOnce(&T)
{
f(unsafe { &(*self.value.get()).1 })
}
pub fn update_inplace_mut<F>(&self, journal: &Journal<A>, f: F)
where
F: FnOnce(&mut T)
{
self.take_log(journal);
f(unsafe { &mut (*self.value.get()).1 })
}
}
impl<T: PSafe + ?Sized, A: MemPool> LogCell<T, A> {
#[inline]
pub(crate) fn take_log(&self, journal: &Journal<A>) {
unsafe {
let inner = &mut *self.value.get();
if inner.0 == 0 {
inner.1.take_log(journal, Notifier::NonAtomic(Ptr::from_ref(&inner.0)));
}
}
}
#[inline]
pub fn get_mut(&mut self, journal: &Journal<A>) -> &mut T {
self.take_log(journal);
unsafe { &mut (*self.value.get()).1 }
}
#[inline]
pub unsafe fn as_mut(&self) -> &mut T {
&mut (*self.value.get()).1
}
}
impl<T: PSafe + Default, A: MemPool> LogCell<T, A> {
pub fn take(&self, journal: &Journal<A>) -> T {
self.replace(Default::default(), journal)
}
}
impl<T: fmt::Debug + PSafe, A: MemPool> fmt::Debug for LogCell<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unsafe { (*self.value.get()).1.fmt(f) }
}
}
impl<T: PSafe + Logger<A> + Copy, A: MemPool> PClone<A> for LogCell<T, A> {
#[inline]
fn pclone(&self, j: &Journal<A>) -> LogCell<T, A> {
unsafe { LogCell::new((*self.value.get()).1, j) }
}
}