From e9a51f8d528bd158b4caba4a96b875dd35d56725 Mon Sep 17 00:00:00 2001 From: Nilstrieb Date: Sat, 7 Aug 2021 18:27:54 +0200 Subject: [PATCH] actually works lol --- src/linked_list.rs | 245 +++++++++++++++++++++++++++++---------------- 1 file changed, 157 insertions(+), 88 deletions(-) diff --git a/src/linked_list.rs b/src/linked_list.rs index dd3295e..b4404db 100644 --- a/src/linked_list.rs +++ b/src/linked_list.rs @@ -1,116 +1,149 @@ -use std::fmt::Debug; +use std::fmt::{Debug, Formatter}; +use std::marker::PhantomData; use std::ptr::NonNull; -type NodePtr = Option>>; - /// A doubly linked list with unsafe :O, except it's kind of shit compared to the std one -#[derive(Debug)] pub struct LinkedList { start: Option>>, end: Option>>, + _maker: PhantomData, } -impl Clone for LinkedList +impl LinkedList { + /// Creates a new empty Linked List + pub fn new() -> LinkedList { + 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(node: Option<&NonNull>>, index: usize) -> Option<&Node> { + 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 { + Iter::new(self) + } +} + +impl Debug for LinkedList 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 Drop for LinkedList { + 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 { value: T, - next: NodePtr, - prev: NodePtr, -} - -impl LinkedList { - /// Creates a new empty Linked List - pub fn new() -> LinkedList { - 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>>, index: usize) -> Option<&Node> { - 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>>, + prev: Option>>, + _maker: PhantomData, } fn allocate_nonnull(element: T) -> NonNull { 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 IntoIterator for LinkedList { - type Item = T; - type IntoIter = IntoIter; +pub struct Iter<'a, T> { + item: Option<&'a Node>, +} - fn into_iter(self) -> Self::IntoIter { - todo!() +impl<'a, T> Iter<'a, T> { + fn new(list: &'a LinkedList) -> 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 { - item: NodePtr, -} - -impl IntoIter { - fn new(list: LinkedList) -> Self { - Self { item: list.start } - } -} - -impl Iterator for IntoIter { - type Item = T; +impl<'a, T: Debug> Iterator for Iter<'a, T> { + type Item = &'a T; fn next(&mut self) -> Option { - //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::>(); + 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)); + } }