mirror of
https://github.com/Noratrieb/datastructures.git
synced 2026-01-14 17:35:02 +01:00
actually works lol
This commit is contained in:
parent
b58312c196
commit
e9a51f8d52
1 changed files with 157 additions and 88 deletions
|
|
@ -1,116 +1,149 @@
|
|||
use std::fmt::Debug;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
type NodePtr<T> = Option<NonNull<Node<T>>>;
|
||||
|
||||
/// A doubly linked list with unsafe :O, except it's kind of shit compared to the std one
|
||||
#[derive(Debug)]
|
||||
pub struct LinkedList<T> {
|
||||
start: Option<NonNull<Node<T>>>,
|
||||
end: Option<NonNull<Node<T>>>,
|
||||
_maker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Clone for LinkedList<T>
|
||||
impl<T> LinkedList<T> {
|
||||
/// Creates a new empty Linked List
|
||||
pub fn new() -> LinkedList<T> {
|
||||
std::collections::LinkedList::new().push_front("hi");
|
||||
Self {
|
||||
start: None,
|
||||
end: None,
|
||||
_maker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepend an element to the start of the list
|
||||
pub fn push_front(&mut self, element: T) {
|
||||
match self.start {
|
||||
// empty list
|
||||
None => {
|
||||
let node = allocate_nonnull(Node {
|
||||
value: element,
|
||||
next: None,
|
||||
prev: None,
|
||||
_maker: PhantomData,
|
||||
});
|
||||
self.start = Some(node);
|
||||
self.end = Some(node);
|
||||
}
|
||||
// at lest one element
|
||||
Some(mut node) => {
|
||||
let new = allocate_nonnull(Node {
|
||||
value: element,
|
||||
next: Some(node),
|
||||
prev: None,
|
||||
_maker: PhantomData,
|
||||
});
|
||||
// SAFETY: All pointers should always be valid
|
||||
unsafe { node.as_mut() }.prev = Some(new);
|
||||
self.start = Some(new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_end(&mut self, element: T) {}
|
||||
|
||||
/// Random access over the list
|
||||
pub fn get(&self, index: usize) -> Option<&T> {
|
||||
fn get_inner<T2>(node: Option<&NonNull<Node<T2>>>, index: usize) -> Option<&Node<T2>> {
|
||||
match node {
|
||||
// SAFETY: All pointers should always be valid
|
||||
Some(ptr) => match index {
|
||||
0 => unsafe { Some(ptr.as_ref()) },
|
||||
n => get_inner(unsafe { ptr.as_ref() }.next.as_ref(), n - 1),
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
get_inner(self.start.as_ref(), index).map(|n| &n.value)
|
||||
}
|
||||
|
||||
pub fn get_node(&self, index: usize) {}
|
||||
|
||||
/// Returns an iterator over the items
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for LinkedList<T>
|
||||
where
|
||||
T: Clone,
|
||||
T: Debug,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
todo!()
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_list().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for LinkedList<T> {
|
||||
fn drop(&mut self) {
|
||||
let mut item = self.start;
|
||||
while let Some(content) = item {
|
||||
// SAFETY: All pointers should always be valid and created from a box
|
||||
unsafe {
|
||||
item = content.as_ref().next;
|
||||
Box::from_raw(content.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Node<T> {
|
||||
value: T,
|
||||
next: NodePtr<T>,
|
||||
prev: NodePtr<T>,
|
||||
}
|
||||
|
||||
impl<T> LinkedList<T> {
|
||||
/// Creates a new empty Linked List
|
||||
pub fn new() -> LinkedList<T> {
|
||||
Self {
|
||||
start: None,
|
||||
end: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepend an element to the start of the list
|
||||
pub fn prepend(&mut self, element: T) {
|
||||
match self.start {
|
||||
None => {
|
||||
let node = allocate_nonnull(Node {
|
||||
value: element,
|
||||
next: None,
|
||||
prev: None,
|
||||
});
|
||||
self.start = Some(node);
|
||||
self.end = Some(node);
|
||||
}
|
||||
Some(mut node) => {
|
||||
let new = allocate_nonnull(Node {
|
||||
value: element,
|
||||
next: Some(node),
|
||||
prev: None,
|
||||
});
|
||||
unsafe { node.as_mut() }.prev = Some(new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Random access over the list
|
||||
pub fn get(&self, index: usize) -> Option<&T> {
|
||||
dbg!(self);
|
||||
Self::get_inner(self.start.as_ref(), index).map(|n| &n.value)
|
||||
}
|
||||
|
||||
fn get_inner(node: Option<&NonNull<Node<T>>>, index: usize) -> Option<&Node<T>> {
|
||||
if let Some(ptr) = node {
|
||||
match index {
|
||||
0 => unsafe { Some(ptr.as_ref()) },
|
||||
n => LinkedList::get_inner(Some(ptr), n - 1),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
next: Option<NonNull<Node<T>>>,
|
||||
prev: Option<NonNull<Node<T>>>,
|
||||
_maker: PhantomData<T>,
|
||||
}
|
||||
|
||||
fn allocate_nonnull<T>(element: T) -> NonNull<T> {
|
||||
let mut boxed = Box::new(element);
|
||||
NonNull::new(boxed.as_mut()).expect("Allocation returned null pointer")
|
||||
// SAFETY: box is always non-null
|
||||
unsafe { NonNull::new_unchecked(Box::leak(boxed)) }
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for LinkedList<T> {
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
pub struct Iter<'a, T> {
|
||||
item: Option<&'a Node<T>>,
|
||||
}
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
todo!()
|
||||
impl<'a, T> Iter<'a, T> {
|
||||
fn new(list: &'a LinkedList<T>) -> Self {
|
||||
Self {
|
||||
item: match list.start {
|
||||
// SAFETY: All pointers should always be valid, the list lives as long as its items
|
||||
Some(ref nn) => unsafe { Some(nn.as_ref()) },
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntoIter<T> {
|
||||
item: NodePtr<T>,
|
||||
}
|
||||
|
||||
impl<T> IntoIter<T> {
|
||||
fn new(list: LinkedList<T>) -> Self {
|
||||
Self { item: list.start }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
impl<'a, T: Debug> Iterator for Iter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
//let next = self.item.take();
|
||||
//let ptr = match next {
|
||||
// None => return None,
|
||||
// Some(mut ptr) => unsafe { ptr.as_mut() },
|
||||
//};
|
||||
|
||||
todo!()
|
||||
let current = self.item;
|
||||
match current {
|
||||
Some(node) => {
|
||||
self.item = match &node.next {
|
||||
Some(ref nn) => {
|
||||
// SAFETY: All pointers should always be valid
|
||||
unsafe { Some(nn.as_ref()) }
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
Some(&node.value)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,12 +154,48 @@ mod test {
|
|||
#[test]
|
||||
fn random_access() {
|
||||
let mut list = LinkedList::new();
|
||||
list.prepend("hallo");
|
||||
list.prepend("test");
|
||||
list.prepend("nice");
|
||||
list.push_front("hallo");
|
||||
list.push_front("test");
|
||||
list.push_front("nice");
|
||||
assert_eq!(list.get(0), Some(&"nice"));
|
||||
assert_eq!(list.get(1), Some(&"test"));
|
||||
assert_eq!(list.get(2), Some(&"hallo"));
|
||||
assert_eq!(list.get(3), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter_simple() {
|
||||
let mut list = LinkedList::new();
|
||||
list.push_front("hallo");
|
||||
list.push_front("test");
|
||||
list.push_front("nice");
|
||||
let mut iter = list.iter();
|
||||
assert_eq!(iter.next(), Some(&"nice"));
|
||||
assert_eq!(iter.next(), Some(&"test"));
|
||||
let val = iter.next();
|
||||
assert_eq!(val, Some(&"hallo"));
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterator() {
|
||||
let mut list = LinkedList::new();
|
||||
list.push_front("hallo");
|
||||
list.push_front("test");
|
||||
list.push_front("nice");
|
||||
let vec = list.iter().collect::<Vec<_>>();
|
||||
assert_eq!(vec[0], &"nice");
|
||||
assert_eq!(vec[1], &"test");
|
||||
assert_eq!(vec[2], &"hallo");
|
||||
assert_eq!(vec.get(3), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_large_number() {
|
||||
let mut list = LinkedList::new();
|
||||
for i in 0..1000000 {
|
||||
list.push_front(i);
|
||||
}
|
||||
assert_eq!(list.get(999999), Some(&0));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue