[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