use thunderdome::{Arena, Index};
pub use iter_links::IterLinks;
mod iter_links;
#[derive(Clone, Copy, Debug)]
struct Node<T> {
data: T,
next: Option<Index>,
prev: Option<Index>,
}
#[derive(Clone, Debug)]
pub struct LinkedList<T> {
nodes: Arena<Node<T>>,
head: Option<Index>,
tail: Option<Index>,
}
impl<T> LinkedList<T> {
pub fn new() -> Self {
Self {
nodes: Arena::new(),
head: None,
tail: None,
}
}
pub fn get(&self, idx: Index) -> Option<&T> {
self.nodes.get(idx).map(|node| &node.data)
}
pub fn get_mut(&mut self, idx: Index) -> Option<&mut T> {
self.nodes.get_mut(idx).map(|node| &mut node.data)
}
pub fn head(&self) -> Option<&T> {
self.head.map(|head| self.get(head)).flatten()
}
pub fn head_mut(&mut self) -> Option<&mut T> {
let head = self.head?;
self.get_mut(head)
}
pub fn tail(&self) -> Option<&T> {
self.tail.map(|tail| self.get(tail)).flatten()
}
pub fn tail_mut(&mut self) -> Option<&mut T> {
let tail = self.tail?;
self.get_mut(tail)
}
pub fn pop_head(&mut self) -> Option<T> {
self.remove(self.head?)
}
pub fn pop_tail(&mut self) -> Option<T> {
self.remove(self.tail?)
}
pub fn push_head(&mut self, data: T) -> Index {
let node = Node {
data,
next: self.head,
prev: None,
};
let node_idx = self.nodes.insert(node);
if let Some(old_head_idx) = self.head {
self.nodes[old_head_idx].prev = Some(node_idx);
}
self.head = Some(node_idx);
if self.len() == 1 {
self.tail = self.head;
}
node_idx
}
pub fn push_tail(&mut self, data: T) -> Index {
let node = Node {
data,
next: None,
prev: self.tail,
};
let node_idx = self.nodes.insert(node);
if let Some(old_tail_idx) = self.tail {
self.nodes[old_tail_idx].next = Some(node_idx);
}
self.tail = Some(node_idx);
if self.len() == 1 {
self.head = self.tail;
}
node_idx
}
pub fn remove(&mut self, idx: Index) -> Option<T> {
let removed_node = match self.nodes.remove(idx) {
Some(node) => node,
None => return None,
};
if Some(idx) == self.head {
self.head = removed_node.next;
}
if Some(idx) == self.tail {
self.tail = removed_node.prev;
}
if let Some(prev_idx) = removed_node.prev {
self.nodes[prev_idx].next = removed_node.next;
}
if let Some(next_idx) = removed_node.next {
self.nodes[next_idx].prev = removed_node.prev;
}
Some(removed_node.data)
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn iter_links(&self) -> iter_links::IterLinks<T> {
IterLinks::new(self)
}
pub fn into_vec(mut self) -> Vec<T> {
let mut result_vec = Vec::new();
while let Some(head) = self.pop_head() {
result_vec.push(head);
}
result_vec
}
pub fn iter_fast(&self) -> impl Iterator<Item = &T> {
self.nodes.iter().map(|(_idx, node)| &node.data)
}
pub fn iter_fast_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.nodes.iter_mut().map(|(_idx, node)| &mut node.data)
}
}
impl<T> Default for LinkedList<T> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn size_of_node() {
assert_eq!(std::mem::size_of::<Node<u8>>(), 20);
}
}