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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-17 09:45:47 +01:00
|
|
|
/// Retrieve and remove the item at the end of the list
|
2023-02-15 18:10:08 +01:00
|
|
|
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
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-02-17 09:45:47 +01:00
|
|
|
/// Retrieve and remove the item at the start of the list
|
2023-02-15 18:10:08 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-17 09:45:47 +01:00
|
|
|
impl<T> IntoIterator for DoublyLinkedList<T> {
|
|
|
|
type Item = <ListIterator<T> as Iterator>::Item;
|
|
|
|
|
|
|
|
type IntoIter = ListIterator<T>;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
|
|
Self::IntoIter::new(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ListIterator<T> {
|
|
|
|
list: DoublyLinkedList<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> ListIterator<T> {
|
|
|
|
fn new(list: DoublyLinkedList<T>) -> Self {
|
|
|
|
Self { list }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Iterator for ListIterator<T> {
|
|
|
|
type Item = T;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
self.list.pop_front()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> DoubleEndedIterator for ListIterator<T> {
|
|
|
|
fn next_back(&mut self) -> Option<Self::Item> {
|
|
|
|
self.list.pop_back()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type List<T> = DoublyLinkedList<T>;
|
|
|
|
pub type ListInt = List<i32>;
|
|
|
|
|
2023-02-15 18:10:08 +01:00
|
|
|
#[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);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|