actually works lol

This commit is contained in:
nora 2021-08-07 18:27:54 +02:00
parent b58312c196
commit e9a51f8d52

View file

@ -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));
}
}