use std::cell::RefCell;
use std::cmp::Ordering;
use std::fmt::Debug;
use std::rc::Rc;
pub const OUT_OF_BOUNDS: usize = usize::MAX;
#[derive(thiserror::Error, Debug)]
pub enum MapError {
#[error("error: Some error with the linked list")]
InternalError(String),
#[error(transparent)]
BorrowError(#[from] std::cell::BorrowError),
#[error(transparent)]
BorrowMutError(#[from] std::cell::BorrowMutError),
}
#[cfg(test)]
mod test;
#[derive(Clone, Debug)]
struct Node<K, V>
where
K: Debug,
V: Debug,
{
prev_: usize,
next_: usize,
key_: K,
value_: V,
}
#[derive(Clone, Debug)]
pub struct LinkedList<K, V>
where
K: Debug,
V: Debug,
{
head_: usize,
tail_: usize,
nodes_: Vec<Option<Node<K, V>>>,
id_pool_: Vec<usize>,
}
impl<K, V> Default for LinkedList<K, V>
where
K: Debug,
V: Debug,
{
fn default() -> Self {
Self {
head_: OUT_OF_BOUNDS,
tail_: OUT_OF_BOUNDS,
nodes_: Vec::new(),
id_pool_: Vec::new(),
}
}
}
#[derive(Clone, Debug)]
struct EraseOperation {
change_prev_: Option<(usize, usize)>,
erase_: usize,
change_next_: Option<(usize, usize)>,
}
#[allow(dead_code)]
impl<'a, K: 'a, V: 'a> LinkedList<K, V>
where
K: Debug + Ord + PartialOrd,
V: Debug,
{
pub fn with_capacity(capacity: usize) -> Self {
Self {
head_: OUT_OF_BOUNDS,
tail_: OUT_OF_BOUNDS,
nodes_: Vec::with_capacity(capacity),
id_pool_: Vec::with_capacity(capacity),
}
}
pub fn iter(&self) -> ListIterator<'_, K, V> {
ListIterator {
list_: self,
my_next_: self.head_,
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.nodes_.len() - self.id_pool_.len()
}
pub fn capacity(&self) -> (usize, usize) {
(self.nodes_.capacity(), self.id_pool_.capacity())
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn clear(&mut self) {
self.head_ = OUT_OF_BOUNDS;
self.tail_ = OUT_OF_BOUNDS;
self.nodes_.clear();
self.id_pool_.clear();
}
pub fn next_free_index(&self) -> usize {
if self.id_pool_.is_empty() {
self.nodes_.len()
} else {
*self.id_pool_.last().unwrap()
}
}
#[inline(always)]
pub fn get_k(&self, index: usize) -> Result<&K, MapError> {
let rv = self
.nodes_
.get(index)
.ok_or_else(|| MapError::InternalError("error, item not found".to_string()))?
.as_ref()
.ok_or_else(|| MapError::InternalError("error, item was not active".to_string()))?;
Ok(&rv.key_)
}
#[inline(always)]
pub fn get_v(&self, index: usize) -> Result<&V, MapError> {
let rv = self
.nodes_
.get(index)
.ok_or_else(|| MapError::InternalError("error, item not found".to_string()))?
.as_ref()
.ok_or_else(|| MapError::InternalError("error, item was not active".to_string()))?;
Ok(&rv.value_)
}
#[inline(always)]
pub fn get(&self, index: usize) -> Result<(&K, &V), MapError> {
if index == OUT_OF_BOUNDS {
return Err(MapError::InternalError(format!(
"Invalid pointer (moved past start/end). {}:{}",
file!(),
line!()
)));
}
let rv = self
.nodes_
.get(index)
.ok_or_else(|| MapError::InternalError("error, item not found".to_string()))?
.as_ref()
.ok_or_else(|| MapError::InternalError("error, item was not active".to_string()))?;
Ok((&rv.key_, &rv.value_))
}
#[inline(always)]
pub fn get_prev_k(&self, index: usize) -> Result<&K, MapError> {
let prev = self
.nodes_
.get(index)
.as_ref()
.ok_or_else(|| MapError::InternalError("error, item not found".to_string()))?
.as_ref()
.ok_or_else(|| MapError::InternalError("error, item was None".to_string()))?
.prev_;
let node = self
.nodes_
.get(prev)
.ok_or_else(|| MapError::InternalError("error, prev item not found".to_string()))?
.as_ref();
Ok(&node
.ok_or_else(|| MapError::InternalError("error, item was not active".to_string()))?
.key_)
}
fn push_front_(&mut self, key: K, value: V) -> Result<usize, MapError> {
let insertion_index = if !self.id_pool_.is_empty() {
self.id_pool_.pop().unwrap()
} else {
self.nodes_.len()
};
let new_node = if let Some(ref mut prev_head) = self.nodes_.get_mut(self.head_) {
if let Some(prev_head) = prev_head {
let new_node = Node {
next_: self.head_,
prev_: OUT_OF_BOUNDS,
key_: key,
value_: value,
};
self.head_ = insertion_index;
prev_head.prev_ = insertion_index;
new_node
} else {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)));
}
} else {
self.head_ = insertion_index;
self.tail_ = insertion_index;
Node {
next_: OUT_OF_BOUNDS,
prev_: OUT_OF_BOUNDS,
key_: key,
value_: value,
}
};
Ok(self.replace_or_push_(insertion_index, new_node))
}
#[inline(always)]
fn replace_or_push_(&mut self, insertion_index: usize, new_node: Node<K, V>) -> usize {
if insertion_index == self.nodes_.len() {
self.nodes_.push(Some(new_node));
} else {
let _ = self
.nodes_
.get_mut(insertion_index)
.unwrap()
.replace(new_node);
}
insertion_index
}
fn insert_before_(&mut self, index: usize, key: K, value: V) -> Result<usize, MapError> {
if index == OUT_OF_BOUNDS {
return self.push_front_(key, value);
}
let insertion_index = if !self.id_pool_.is_empty() {
self.id_pool_.pop().unwrap()
} else {
self.nodes_.len()
};
let new_node = if let Some(ref mut next_node) = self.nodes_.get_mut(index) {
if let Some(ref mut next_node) = next_node {
let new_node = Node {
next_: index,
prev_: next_node.prev_,
key_: key,
value_: value,
};
next_node.prev_ = insertion_index;
new_node
} else {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)));
}
} else {
self.head_ = insertion_index;
self.tail_ = insertion_index;
Node {
next_: OUT_OF_BOUNDS,
prev_: OUT_OF_BOUNDS,
key_: key,
value_: value,
}
};
let prev_node = new_node.prev_;
{
let _i = self.replace_or_push_(insertion_index, new_node);
#[cfg(feature = "console_debug")]
assert_eq!(insertion_index, _i);
};
if prev_node != OUT_OF_BOUNDS {
if let Some(prev_node) = self.nodes_.get_mut(prev_node) {
if let Some(prev_node) = prev_node {
prev_node.next_ = insertion_index;
} else {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)));
}
} else {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)));
}
} else {
self.head_ = insertion_index;
}
Ok(insertion_index)
}
fn push_back_(&mut self, key: K, value: V) -> Result<usize, MapError> {
let insertion_index = if !self.id_pool_.is_empty() {
self.id_pool_.pop().unwrap()
} else {
self.nodes_.len()
};
let new_node = if let Some(prev_tail) = self.nodes_.get_mut(self.tail_) {
if let Some(prev_tail) = prev_tail {
let new_node = Node {
next_: OUT_OF_BOUNDS,
prev_: self.tail_,
key_: key,
value_: value,
};
self.tail_ = insertion_index;
prev_tail.next_ = insertion_index;
new_node
} else {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)));
}
} else {
self.head_ = insertion_index;
self.tail_ = insertion_index;
Node {
next_: OUT_OF_BOUNDS,
prev_: OUT_OF_BOUNDS,
key_: key,
value_: value,
}
};
{
let _insert_index = self.replace_or_push_(insertion_index, new_node);
#[cfg(feature = "console_debug")]
assert_eq!(_insert_index, insertion_index);
}
Ok(insertion_index)
}
#[inline(always)]
pub fn ordered_insert(&mut self, key: K, value: V) -> Result<usize, MapError> {
self.ordered_insert_pos(key, value, self.head_)
}
pub fn ordered_insert_pos(
&mut self,
key: K,
value: V,
position: usize,
) -> Result<usize, MapError> {
if self.head_ == OUT_OF_BOUNDS {
return self.push_back_(key, value);
}
let mut insert_before: Option<usize> = None;
let (mut curr_index, first_node) = match self.nodes_.get(position) {
Some(Some(first_node)) => (position, first_node),
_ => (
self.head_,
self.nodes_
.get(self.head_)
.unwrap()
.as_ref()
.ok_or_else(|| {
MapError::InternalError(format!(
"head_ item was None {}:{}",
file!(),
line!()
))
})?,
),
};
let cmp = key.cmp(&first_node.key_);
#[allow(clippy::collapsible_else_if)] if (cmp == Ordering::Greater) || (cmp == Ordering::Equal) {
while let Some(Some(sample)) = self.nodes_.get(curr_index) {
match key.cmp(&sample.key_) {
Ordering::Equal => {
return Ok(curr_index); }
Ordering::Less => {
insert_before = Some(curr_index);
break;
}
_ => {
curr_index = sample.next_;
}
}
}
} else {
if cmp == Ordering::Less {
insert_before = Some(curr_index);
}
while let Some(Some(sample)) = self.nodes_.get(curr_index) {
match key.cmp(&sample.key_) {
Ordering::Equal => {
return Ok(curr_index); }
Ordering::Less => {
insert_before = Some(curr_index);
curr_index = sample.prev_;
}
_ => {
break;
}
}
}
}
if let Some(insert_before) = insert_before {
self.insert_before_(insert_before, key, value)
} else {
self.push_back_(key, value)
}
}
pub fn lower_bound(&self, key: K) -> Result<Option<usize>, MapError> {
#[cfg(feature = "console_debug")]
{
let mut iter = self.iter();
let mut flips = 0_usize;
let mut last_cmp = iter.next().map(|(first, _)| key.cmp(first));
for (node, _) in iter {
let cmp = Some(key.cmp(node));
if cmp != last_cmp {
last_cmp = cmp;
flips += 1;
}
}
if flips > 1 {
println!("\nkey={:?}", key);
for (n, _) in self.iter() {
println!("key.cmp({:?})=={:?}-{:?}", n, n.cmp(&key), key.cmp(n));
}
}
}
if self.tail_ == OUT_OF_BOUNDS {
return Ok(None);
}
let mut last_match: Option<usize> = None;
let mut curr_index = self.tail_;
while let Some(Some(sample)) = self.nodes_.get(curr_index) {
if key.cmp(&sample.key_) != Ordering::Greater {
last_match = Some(curr_index);
curr_index = sample.prev_;
} else {
return Ok(last_match);
}
}
Ok(last_match)
}
#[inline(always)]
pub fn pop_front(&mut self) -> Result<Option<(K, V)>, MapError> {
self.remove_(self.head_)
}
#[inline(always)]
pub fn pop_back(&mut self) -> Result<Option<(K, V)>, MapError> {
self.remove_(self.tail_)
}
#[inline(always)]
pub fn peek_front_k(&self) -> Option<&K> {
match self.nodes_.get(self.head_) {
Some(Some(node)) => Some(&node.key_),
_ => None,
}
}
#[inline(always)]
pub fn peek_back_k(&self) -> Option<&K> {
match self.nodes_.get(self.tail_) {
Some(Some(node)) => Some(&node.key_),
_ => None,
}
}
#[inline(always)]
pub fn tail(&self) -> usize {
self.tail_
}
#[inline(always)]
pub fn head(&self) -> usize {
self.head_
}
#[inline(always)]
fn remove_(&mut self, index: usize) -> Result<Option<(K, V)>, MapError> {
let rv = self.remove__(index)?;
Ok(Some(rv.1))
}
fn remove__(&mut self, index: usize) -> Result<(usize, (K, V), usize), MapError> {
if self.head_ == OUT_OF_BOUNDS {
return Err(MapError::InternalError(format!(
"Could not find element to remove {}:{}",
file!(),
line!()
)));
}
let rv = if self.head_ != OUT_OF_BOUNDS {
let operation = if let Some(node) = self.nodes_.get(index) {
let mut operation = EraseOperation {
change_prev_: None,
erase_: index,
change_next_: None,
};
if let Some(node) = node {
if let Some(next) = self.nodes_.get(node.next_) {
if next.is_some() {
operation.change_next_ = Some((node.next_, node.prev_));
} else {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)));
}
}
if let Some(prev) = self.nodes_.get(node.prev_) {
if prev.is_some() {
operation.change_prev_ = Some((node.prev_, node.next_));
} else {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)));
}
}
Some(operation)
} else {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)));
}
} else {
None
};
if let Some(operation) = operation {
Some(self.erase_node_(operation)?)
} else {
None
}
} else {
None
};
rv.ok_or_else(|| {
MapError::InternalError(format!(
"Could not find element to remove {}:{}",
file!(),
line!()
))
})
}
fn erase_node_(
&mut self,
operation: EraseOperation,
) -> Result<(usize, (K, V), usize), MapError> {
match (operation.change_prev_, operation.change_next_) {
(Some((prev_i, new_next)), Some((next_i, new_prev))) => {
#[cfg(feature = "console_debug")]
{
assert_eq!(new_next, next_i);
assert_eq!(prev_i, new_prev);
}
match self.nodes_.get_mut(prev_i) {
Some(Some(node)) => {
node.next_ = new_next;
}
_ => {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)))
}
};
match self.nodes_.get_mut(next_i) {
Some(Some(node)) => {
node.prev_ = new_prev;
}
_ => {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)))
}
};
}
(None, Some((new_head, new_head_prev))) => match self.nodes_.get_mut(new_head) {
Some(Some(node)) => {
node.prev_ = new_head_prev;
self.head_ = new_head;
}
_ => {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)))
}
},
(Some((new_tail, new_tail_next)), None) => match self.nodes_.get_mut(new_tail) {
Some(Some(node)) => {
node.next_ = new_tail_next;
self.tail_ = new_tail;
}
_ => {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)))
}
},
(None, None) => {
self.head_ = OUT_OF_BOUNDS;
self.tail_ = OUT_OF_BOUNDS
}
}
match self.nodes_.get_mut(operation.erase_) {
Some(old_head) => {
if let Some(old_head) = old_head.take() {
self.id_pool_.push(operation.erase_);
return Ok((
old_head.prev_,
(old_head.key_, old_head.value_),
old_head.next_,
));
}
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢ at {}:{}",
file!(),
line!()
)));
}
_ => {
return Err(MapError::InternalError(format!(
"Should not happen errorâ„¢, element to erase not found {} at {}:{}",
operation.erase_,
file!(),
line!()
)))
}
}
}
}
#[derive(Clone, Debug)]
pub struct ListIterator<'a, K: 'a, V: 'a>
where
K: Debug,
V: Debug,
{
list_: &'a LinkedList<K, V>,
my_next_: usize,
}
impl<'a, K: 'a, V: 'a> std::iter::Iterator for ListIterator<'a, K, V>
where
K: Debug,
V: Debug,
{
type Item = (&'a K, &'a V);
#[inline]
fn next(&mut self) -> Option<(&'a K, &'a V)> {
if self.my_next_ == OUT_OF_BOUNDS {
return None;
}
if let Some(node) = self.list_.nodes_.get(self.my_next_)? {
if self.my_next_ == self.list_.tail_ {
self.my_next_ = OUT_OF_BOUNDS;
} else {
self.my_next_ = node.next_
}
Some((&node.key_, &node.value_))
} else {
self.my_next_ = OUT_OF_BOUNDS;
None
}
}
}
impl<'a, K: 'a, V: 'a> DoubleEndedIterator for ListIterator<'a, K, V>
where
K: Debug,
V: Debug,
{
#[inline]
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
if let Some(node) = self.list_.nodes_.get(self.my_next_)? {
if self.my_next_ == self.list_.tail_ {
self.my_next_ = OUT_OF_BOUNDS;
} else {
self.my_next_ = node.prev_
}
Some((&node.key_, &node.value_))
} else {
self.my_next_ = OUT_OF_BOUNDS;
None
}
}
}
pub struct PIterator<K, V>
where
K: Debug,
V: Debug,
{
current: usize,
list: Rc<RefCell<LinkedList<K, V>>>,
}
#[allow(dead_code)]
impl<K, V> PIterator<K, V>
where
K: Clone + Debug + Unpin + Ord + PartialOrd,
V: Clone + Debug + Unpin,
{
pub fn new(list: Rc<RefCell<LinkedList<K, V>>>) -> Result<Self, MapError> {
let head = list.try_borrow()?.head_;
Ok(Self {
current: head,
list,
})
}
pub fn new_2(list: Rc<RefCell<LinkedList<K, V>>>, current: usize) -> Self {
Self { current, list }
}
#[inline(always)]
pub fn get_k(&self) -> Result<K, MapError> {
Ok(self.list.try_borrow()?.get(self.current)?.0.clone())
}
#[inline(always)]
pub fn get_v(&self) -> Result<V, MapError> {
Ok(self.list.try_borrow()?.get(self.current)?.1.clone())
}
#[allow(clippy::should_implement_trait)]
#[inline(always)]
pub fn next(&mut self) -> Result<(), MapError> {
let list_borrow = self.list.try_borrow()?;
match list_borrow.nodes_.get(self.current) {
Some(Some(node)) => self.current = node.next_,
Some(None) => {
return Err(MapError::InternalError(format!(
"next() failed at index:{}. {}:{}",
self.current,
file!(),
line!()
)));
}
None => self.current = OUT_OF_BOUNDS,
}
Ok(())
}
#[inline(always)]
pub fn prev(&mut self) -> Result<(), MapError> {
let list_borrow = self.list.try_borrow()?;
match list_borrow.nodes_.get(self.current) {
Some(Some(node)) => self.current = node.prev_,
Some(None) => {
return Err(MapError::InternalError(format!(
"prev() failed at index:{}. {}:{}",
self.current,
file!(),
line!()
)));
}
None => self.current = OUT_OF_BOUNDS,
}
Ok(())
}
#[inline(always)]
pub fn move_to_head(&mut self) -> Result<(), MapError> {
self.current = self.list.try_borrow()?.head_;
Ok(())
}
#[inline(always)]
pub fn move_to_tail(&mut self) -> Result<(), MapError> {
self.current = self.list.try_borrow()?.tail_;
Ok(())
}
#[inline(always)]
pub fn is_ok(&self) -> Result<bool, MapError> {
Ok(self.current != OUT_OF_BOUNDS
&& matches!(
self.list.try_borrow()?.nodes_.get(self.current),
Some(Some(_))
))
}
#[inline(always)]
pub fn is_at_head(&self) -> Result<bool, MapError> {
Ok(self.current == self.list.try_borrow()?.head_)
}
#[inline(always)]
pub fn is_at_tail(&self) -> Result<bool, MapError> {
Ok(self.current == self.list.try_borrow()?.tail_)
}
#[inline(always)]
pub fn replace_key(&mut self, key: K) -> Result<(), MapError> {
let mut list = std::pin::Pin::new(self.list.try_borrow_mut()?);
if let Some(Some(ref mut node)) = list.nodes_.get_mut(self.current) {
node.key_ = key;
}
Ok(())
}
#[inline(always)]
pub fn current(&self) -> usize {
self.current
}
#[inline(always)]
pub fn remove_current(&mut self) -> Result<(K, V), MapError> {
let rv = self.list.try_borrow_mut()?.remove__(self.current)?;
if rv.0 != OUT_OF_BOUNDS {
self.current = rv.0;
} else {
self.current = rv.2;
}
Ok(rv.1)
}
#[inline(always)]
pub fn lower_bound(list: Rc<RefCell<LinkedList<K, V>>>, key: K) -> Result<Self, MapError> {
let position = list.try_borrow()?.lower_bound(key)?;
if let Some(position) = position {
Ok(Self {
list,
current: position,
})
} else {
Ok(Self {
list,
current: OUT_OF_BOUNDS,
})
}
}
}
impl<K, V> Debug for PIterator<K, V>
where
K: Debug + Unpin + Ord + PartialOrd,
V: Debug + Unpin,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "PIterator({})", self.current)
}
}
impl<K, V> Clone for PIterator<K, V>
where
K: Debug + Unpin + Ord + PartialOrd,
V: Debug + Unpin,
{
fn clone(&self) -> Self {
Self {
current: self.current,
list: Rc::clone(&self.list),
}
}
}