[chg] ez-ll: A safe linked list
This commit is contained in:
commit
382c54e5f1
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@ -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"
|
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "ez-ll"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
189
src/main.rs
Normal file
189
src/main.rs
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
type LLLink<T> = Option<Rc<RefCell<LLItem<T>>>>;
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LLItem<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
|
next: LLLink<T>,
|
||||||
|
prev: LLLink<T>,
|
||||||
|
val: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LL<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
|
first: LLLink<T>,
|
||||||
|
last: LLLink<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> LL<T>
|
||||||
|
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<T> {
|
||||||
|
// 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<T> {
|
||||||
|
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<T> {
|
||||||
|
LLIter {
|
||||||
|
current: self.first.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
while self.pop_back().is_some() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Display for LL<T>
|
||||||
|
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<T> Drop for LL<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LLIter<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
|
current: Option<Rc<RefCell<LLItem<T>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Iterator for LLIter<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
|
type Item = Rc<RefCell<LLItem<T>>>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.current.clone().map(|current| {
|
||||||
|
self.current = current.borrow().next.clone();
|
||||||
|
current
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Iterator for LLItem<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
|
type Item = Rc<RefCell<LLItem<T>>>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.next.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut l: LL<u64> = 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));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user