use crate::{
atm_p::{CASErr, NonNullAtomicNode, NonNullAtomicP},
sync::Node,
};
use std::{
fmt::Debug,
ops::Deref,
sync::{Arc, atomic::Ordering},
};
pub struct Cursor<T> {
atm_ptr: Arc<NonNullAtomicNode<T>>,
current: Node<T>,
peek: Option<Node<T>>,
}
impl<T> Debug for Cursor<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Cursor")
.field("current", &self.current)
.finish()
}
}
impl<T> Cursor<T> {
pub fn new(node: Node<T>) -> Self {
Self {
current: node.clone(),
atm_ptr: Arc::new(NonNullAtomicP::new(node)),
peek: None,
}
}
pub fn reload(&mut self) -> &mut Self {
self.current = self.atm_ptr.load(Ordering::Relaxed);
self.peek = None;
self
}
pub fn peek(&mut self) -> Option<Node<T>> {
if let Some(peek) = self.peek.clone() {
Some(peek)
} else {
self.peek_fresh()
}
}
pub fn peek_fresh(&mut self) -> Option<Node<T>> {
self.peek = Node::resolve_next(&self.current);
self.peek.clone()
}
pub fn get_current(this: &Self) -> &Node<T> {
&this.current
}
pub fn into_current(this: Self) -> Option<Node<T>> {
Arc::into_inner(this.atm_ptr).map(NonNullAtomicP::into_p)
}
pub fn try_unwrap(this: Self) -> Result<Node<T>, Self> {
let Self {
atm_ptr,
current,
peek,
} = this;
Arc::try_unwrap(atm_ptr)
.map(NonNullAtomicP::into_p)
.map_err(|atm_ptr| Self {
atm_ptr,
current,
peek,
})
}
pub fn increment_with<F: FnOnce(&Node<T>)>(this: &mut Self, prepare: F) -> bool {
loop {
let loaded = this.atm_ptr.load(Ordering::Acquire);
if Node::ptr_eq(&this.current, &loaded) {
if let Some(next) = Node::resolve_next(&this.current) {
prepare(&next);
match this.atm_ptr.compare_exchange(
&this.current,
next.clone(),
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
this.current = next;
this.peek = None;
break true;
}
Err(CASErr { actual, .. }) => {
this.current = actual;
this.peek = None;
break true;
}
}
} else {
this.peek = None;
break false;
};
} else {
this.current = loaded;
this.peek = None;
break true;
}
}
}
pub fn increment(this: &mut Self) -> bool {
Self::increment_with(this, |_| {})
}
pub fn push_before_peeked<F: Fn(&T) -> bool>(
&mut self,
elem: T,
predicate: F,
) -> Result<Node<T>, T> {
if let Some(peek) = self.peek() {
if !predicate(&peek) {
return Err(elem);
}
let new_node = Node::new(elem);
Node::next(&new_node)
.strong
.store(peek.clone(), Ordering::Release);
match Node::next(&self.current).strong.compare_exchange(
&peek,
new_node.clone(),
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
self.peek = Some(new_node.clone());
Ok(new_node)
}
Err(CASErr { new, .. }) => {
drop(new);
Err(Node::into_inner(new_node).expect("This node is owned by me.")) }
}
} else {
Err(elem)
}
}
}
impl<T> Deref for Cursor<T> {
type Target = Node<T>;
fn deref(&self) -> &Self::Target {
&self.current
}
}
impl<T> Clone for Cursor<T> {
fn clone(&self) -> Self {
Self {
atm_ptr: Arc::clone(&self.atm_ptr),
current: self.current.clone(),
peek: self.peek.clone(),
}
}
}
impl<T> AsRef<T> for Cursor<T> {
fn as_ref(&self) -> &T {
self.current.as_ref()
}
}