burritos/src/utility/list.rs

142 lines
3.6 KiB
Rust
Raw Normal View History

2023-02-15 18:10:08 +01:00
use std::{cell::RefCell, rc::Rc};
/// Definition of an element of the list
///
/// Contain one stored item and the previous/next element of the list
struct ListNode<T> {
item: T,
next: Link<T>,
prev: Link<T>,
}
impl<T> ListNode<T> {
fn new(item: T) -> Self {
Self {
item,
next: None,
prev: None,
}
}
}
type Link<T> = Option<Rc<RefCell<ListNode<T>>>>;
/// Defintion of the generic linked list
#[derive(Default)]
pub struct DoublyLinkedList<T> {
head: Link<T>,
tail: Link<T>,
size: usize,
}
impl<T> DoublyLinkedList<T> {
pub fn new() -> Self {
Self {
head: None,
tail: None,
size: 0,
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn len(&self) -> usize {
self.size
}
/// Add the item at the end of the list
pub fn push_back(&mut self, item: T) {
let node = Rc::new(RefCell::new(ListNode::new(item)));
if let Some(prev_tail) = self.tail.take() {
prev_tail.borrow_mut().next = Some(Rc::clone(&node));
node.borrow_mut().prev = Some(prev_tail);
self.tail = Some(node);
self.size += 1;
} else {
self.head = Some(Rc::clone(&node));
self.tail = Some(node);
self.size = 1;
}
}
/// Add the item at the start of the list
pub fn push_front(&mut self, item: T) {
let node = Rc::new(RefCell::new(ListNode::new(item)));
if let Some(prev_head) = self.head.take() {
prev_head.borrow_mut().prev = Some(Rc::clone(&node));
node.borrow_mut().next = Some(prev_head);
self.head = Some(node);
self.size += 1;
} else {
self.head = Some(Rc::clone(&node));
self.tail = Some(node);
self.size = 1;
}
}
/// Remove the item at the end of the list
pub fn pop_back(&mut self) -> Option<T> {
self.tail.take().map(|prev_tail| {
self.size -= 1;
match prev_tail.borrow_mut().prev.take() {
Some(node) => {
node.borrow_mut().next = None;
self.tail = Some(node);
}
None => {
self.head.take();
}
}
Rc::try_unwrap(prev_tail).ok().unwrap().into_inner().item
})
}
/// Remove the item at the start of the list
pub fn pop_front(&mut self) -> Option<T> {
self.head.take().map(|prev_head| {
self.size -= 1;
match prev_head.borrow_mut().next.take() {
Some(node) => {
node.borrow_mut().prev = None;
self.head = Some(node);
}
None => {
self.tail.take();
}
}
Rc::try_unwrap(prev_head).ok().unwrap().into_inner().item
})
}
}
impl<T> Drop for DoublyLinkedList<T> {
/// list destructor, safely desallocate smart pointer Rc
fn drop(&mut self) {
while let Some(node) = self.head.take() {
let _ = node.borrow_mut().prev.take();
self.head = node.borrow_mut().next.take();
}
self.tail.take();
}
}
#[cfg(test)]
mod test {
use super::DoublyLinkedList;
#[test]
fn test_list_push() {
let mut list = DoublyLinkedList::new();
list.push_back(5);
list.push_front(45);
assert_eq!(list.pop_front().unwrap(), 45);
assert_eq!(list.pop_front().unwrap(), 5);
}
}