Add double linked list
This commit is contained in:
parent
f1f57a76e1
commit
bd0b6e17a5
@ -1,5 +1,6 @@
|
|||||||
mod simulator;
|
mod simulator;
|
||||||
mod kernel;
|
mod kernel;
|
||||||
|
pub mod utility;
|
||||||
|
|
||||||
use simulator::machine::Machine;
|
use simulator::machine::Machine;
|
||||||
|
|
||||||
|
142
src/utility/list.rs
Normal file
142
src/utility/list.rs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
1
src/utility/mod.rs
Normal file
1
src/utility/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod list;
|
Loading…
Reference in New Issue
Block a user