diff --git a/src/main.rs b/src/main.rs index 831fcfc..986cf3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod simulator; mod kernel; +pub mod utility; use simulator::machine::Machine; diff --git a/src/utility/list.rs b/src/utility/list.rs new file mode 100644 index 0000000..6b0ddbb --- /dev/null +++ b/src/utility/list.rs @@ -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 { + item: T, + next: Link, + prev: Link, +} + +impl ListNode { + fn new(item: T) -> Self { + Self { + item, + next: None, + prev: None, + } + } +} + +type Link = Option>>>; + +/// Defintion of the generic linked list +#[derive(Default)] +pub struct DoublyLinkedList { + head: Link, + tail: Link, + size: usize, +} + +impl DoublyLinkedList { + + 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 { + 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 { + 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 Drop for DoublyLinkedList { + /// 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); + } + + +} \ No newline at end of file diff --git a/src/utility/mod.rs b/src/utility/mod.rs new file mode 100644 index 0000000..651aed7 --- /dev/null +++ b/src/utility/mod.rs @@ -0,0 +1 @@ +pub mod list; \ No newline at end of file