commit 382c54e5f1bb956b2815cab31eb3694c3fed51f1 Author: ddidderr Date: Wed Feb 14 22:21:52 2024 +0100 [chg] ez-ll: A safe linked list diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..19b167f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ez-ll" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9ca8633 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ez-ll" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..72525b1 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,189 @@ +use std::cell::RefCell; +use std::fmt::{Debug, Display, Error, Formatter}; +use std::rc::Rc; + +type LLLink = Option>>>; +#[derive(Debug)] +pub struct LLItem +where + T: Debug, +{ + next: LLLink, + prev: LLLink, + val: T, +} + +#[derive(Debug)] +pub struct LL +where + T: Debug, +{ + first: LLLink, + last: LLLink, +} + +impl LL +where + T: Debug, +{ + pub fn empty() -> Self { + Self { + first: None, + last: None, + } + } + + pub fn push_back(&mut self, val: T) { + // create new item + let new_item = Rc::new(RefCell::new(LLItem { + next: None, + prev: self.last.clone(), + val, + })); + + // we have a last element so we update its next pointer + if let Some(last) = &self.last { + last.borrow_mut().next = Some(new_item.clone()); + + // we don't have a last element so the list is empty + } else { + self.first = Some(new_item.clone()); + } + + self.last = Some(new_item); + } + + pub fn push_front(&mut self, val: T) { + // create new item + let new_item = Rc::new(RefCell::new(LLItem { + next: self.first.clone(), + prev: None, + val, + })); + + // we have a first element so we update its prev pointer + if let Some(first) = &self.first { + first.borrow_mut().prev = Some(new_item.clone()); + + // we don't have a first element so the list is empty + } else { + self.last = Some(new_item.clone()); + } + + self.first = Some(new_item); + } + + pub fn pop_back(&mut self) -> Option { + // Take the current last node out of the list + let old_last = self.last.take()?; + + // Handle the case where there is a previous node before the last node + if let Some(prev_node) = old_last.borrow().prev.clone() { + prev_node.borrow_mut().next = None; + self.last = Some(prev_node); + } else { + // This was the only node in the list + self.first = None; + } + + // Extract the value from the old last node and return it + let old_value = Rc::try_unwrap(old_last).ok()?.into_inner().val; + Some(old_value) + } + + pub fn pop_front(&mut self) -> Option { + let old_first = self.first.take()?; + + if let Some(next_node) = old_first.borrow().next.clone() { + next_node.borrow_mut().prev = None; + self.first = Some(next_node); + } else { + self.last = None; + } + + let old_value = Rc::try_unwrap(old_first).ok()?.into_inner().val; + Some(old_value) + } + + pub fn is_empty(&self) -> bool { + self.first.is_none() + } + + pub fn len(&self) -> usize { + self.iter().count() + } + + pub fn iter(&self) -> LLIter { + LLIter { + current: self.first.clone(), + } + } + + pub fn clear(&mut self) { + while self.pop_back().is_some() {} + } +} + +impl Display for LL +where + T: Debug + Display, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { + for elem in self.iter() { + f.write_str(&format!("{} ", elem.borrow().val))?; + } + Ok(()) + } +} + +impl Drop for LL +where + T: Debug, +{ + fn drop(&mut self) { + self.clear(); + } +} + +pub struct LLIter +where + T: Debug, +{ + current: Option>>>, +} + +impl Iterator for LLIter +where + T: Debug, +{ + type Item = Rc>>; + + fn next(&mut self) -> Option { + self.current.clone().map(|current| { + self.current = current.borrow().next.clone(); + current + }) + } +} + +impl Iterator for LLItem +where + T: Debug, +{ + type Item = Rc>>; + + fn next(&mut self) -> Option { + self.next.clone() + } +} + +fn main() { + let mut l: LL = LL::empty(); + + (1..=100).for_each(|nr| match nr % 2 == 0 { + true => l.push_front(nr), + false => l.push_back(nr), + }); + println!("{l}"); + l.iter().for_each(|e| println!("{}", e.borrow().val)); +}