#[cfg(test)] mod test; use std::fmt::{Debug, Formatter}; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; use std::marker::PhantomData; use std::ptr::NonNull; /// A doubly linked list using unsafe code. /// It is loosely inspired by the `std::collections::LinkedList`, but I haven't looked at that one too close, /// so most it is my own. /// /// It was not made with efficiency in mind, but at least it doesn't but `std::rc::Rc` everywhere, but uses /// unsafe pointers instead. /// /// # How to use /// ``` /// # use datastructures::linked_list::LinkedList; /// # /// let mut list = LinkedList::new(); /// list.push_front("hello"); /// assert_eq!(list.get(0), Some(&"hello")); /// list.push_back("bye"); /// assert_eq!(list.get(1), Some(&"bye")); /// ``` /// /// The list can also be edited using the `Node` methods /// ``` /// # use datastructures::linked_list::LinkedList; /// # /// let mut list = LinkedList::new(); /// /// list.push_front(1); /// let mut node = list.front_node_mut().unwrap(); /// node.push_after(3); /// node.push_after(2); /// let next = node.next().unwrap(); /// let next = next.next().unwrap(); /// assert_eq!(*next.get(), 3); /// ``` /// /// # Note /// You should generally not use Linked Lists, and if you really do need to use one, use `std::collections::LinkedList` #[derive(Eq)] pub struct LinkedList { start: Option>>, end: Option>>, _marker: PhantomData, } impl LinkedList { /// Creates a new empty Linked List pub fn new() -> LinkedList { Self { start: None, end: None, _marker: PhantomData, } } /// Push an element to the start of the list, O(1) pub fn push_front(&mut self, element: T) { let new_node = allocate_nonnull(Node { value: element, next: self.start, prev: None, }); match self.start { Some(mut old_start) => { // SAFETY: All pointers should always be valid. unsafe { old_start.as_mut() }.prev = Some(new_node); } // List is empty - set the end None => self.end = Some(new_node), } self.start = Some(new_node); } /// Push an element to the end of the list, O(1) pub fn push_back(&mut self, element: T) { let new_node = allocate_nonnull(Node { value: element, next: None, prev: self.end, }); match self.end { Some(mut old_end) => { // SAFETY: All pointers should always be valid. unsafe { old_end.as_mut() }.next = Some(new_node); } // List is empty - set the start None => self.start = Some(new_node), } self.end = Some(new_node); } /// Pops the first value in the list and returns it, O(1) pub fn pop_front(&mut self) -> Option { self.start.map(|node| { // SAFETY: all pointers should always be valid let boxed = unsafe { Box::from_raw(node.as_ptr()) }; self.start = boxed.next; match boxed.next { Some(mut next) => { // the next item is now the first item unsafe { next.as_mut().prev = None } } // node was the last element in the list None => self.end = None, } boxed.value // node is freed here }) } /// Pops the last value in the list and returns it, O(1) pub fn pop_back(&mut self) -> Option { self.end.map(|node| { // SAFETY: all pointers should always be valid let boxed = unsafe { Box::from_raw(node.as_ptr()) }; self.end = boxed.prev; match boxed.prev { Some(mut prev) => { // the previous item is now the last item unsafe { prev.as_mut().next = None } } // node was the last element in the list None => self.start = None, } boxed.value // node is freed here }) } /// Get an element from the list, O(n) pub fn get(&self, mut index: usize) -> Option<&T> { let mut node = &self.start; let mut result = None; while let Some(content) = node { // SAFETY: All pointers should always be valid let content = unsafe { content.as_ref() }; if index == 0 { result = Some(&content.value); break; } index -= 1; node = &content.next; } result } /// Gets the last element from the list, O(1) pub fn get_tail(&self) -> Option<&T> { self.end.as_ref().map(|nn| unsafe { &nn.as_ref().value }) } /// Gets the first element from the list, O(1) pub fn get_head(&self) -> Option<&T> { self.start.as_ref().map(|nn| unsafe { &nn.as_ref().value }) } /// Get a node from the list that can only be used for navigation, O(n) pub fn get_node(&self, mut index: usize) -> Option<&Node> { let mut node = &self.start; let mut result = None; while let Some(content) = node { // SAFETY: All pointers should always be valid let content = unsafe { content.as_ref() }; if index == 0 { result = Some(content); break; } index -= 1; node = &content.next; } result } /// Get a node from the list that can be used the edit the list pub fn get_mut_node(&mut self, mut index: usize) -> Option<&mut Node> { let mut node = &mut self.start; let mut result = None; while let Some(ref mut content) = node { // SAFETY: All pointers should always be valid let content = unsafe { content.as_mut() }; if index == 0 { result = Some(content); break; } index -= 1; node = &mut content.next; } result } /// Get the head node from the list that can only be used for navigation pub fn front_node(&self) -> Option<&Node> { self.start.as_ref().map(|nn| unsafe { nn.as_ref() }) } /// Get the tail node from the list that can only be used for navigation pub fn back_node(&self) -> Option<&Node> { self.end.as_ref().map(|nn| unsafe { nn.as_ref() }) } /// Get the head node from the list that can be used the edit the list pub fn front_node_mut(&mut self) -> Option<&mut Node> { self.start.as_mut().map(|nn| unsafe { nn.as_mut() }) } /// Get the tail node from the list that can be used the edit the list pub fn back_node_mut(&mut self) -> Option<&mut Node> { self.end.as_mut().map(|nn| unsafe { nn.as_mut() }) } /// Calculates the length of the list /// # Important /// This implementation is O(n), since unlike in `std::collections::LinkedList`, the length of the list is not stored /// (and can't be because the list can be modified through nodes - a node could theoretically have a reference to the list, /// but that would make node extraction slower because you'd always have to construct a new struct. pub fn len(&self) -> usize { self.iter().count() } /// Returns an iterator over the items pub fn iter(&self) -> Iter { Iter::new(self) } /// Returns a mut iterator over the items pub fn iter_mut(&mut self) -> IterMut { IterMut::new(self) } /// Returns an iterator owning the items pub fn into_iter(self) -> IntoIter { IntoIter::new(self) } } ///// ///// std trait implementations ///// impl Debug for LinkedList { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_list().entries(self.iter()).finish() } } impl Default for LinkedList { fn default() -> Self { Self::new() } } impl Clone for LinkedList { fn clone(&self) -> Self { self.iter().cloned().collect() } } impl Hash for LinkedList { fn hash(&self, state: &mut H) { self.iter().for_each(|item| item.hash(state)); } } impl PartialEq for LinkedList { fn eq(&self, other: &Self) -> bool { // TODO this is very inefficient if self.len() != other.len() { return false; } self.iter() .zip(other.iter()) .all(|(left, right)| left == right) } } impl FromIterator for LinkedList { fn from_iter>(iter: I) -> Self { let mut iter = iter.into_iter(); let mut list = Self::new(); while let Some(item) = iter.next() { list.push_back(item) } list } } impl Extend for LinkedList { fn extend>(&mut self, iter: I) { let mut iter = iter.into_iter(); while let Some(item) = iter.next() { self.push_back(item) } } } 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()); } } } } /// A Node in a `LinkedList` /// Can be used to navigate the `LinkedList`, using the `Node::get_next` and `Node::get_previous` methods, /// and edit the List using the push methods. /// /// # Examples /// ``` /// # use datastructures::linked_list::*; /// # /// let mut list = LinkedList::new(); /// list.push_front(1); /// let mut node = list.get_mut_node(0); /// ``` /// #[derive(Debug)] pub struct Node { value: T, next: Option>>, prev: Option>>, } impl Node { /// Push a value after this node pub fn push_after(&mut self, element: T) { let new_node = Some(allocate_nonnull(Node { value: element, next: self.next, prev: NonNull::new(self as _), })); self.next.map(|mut next| { // SAFETY: All pointers should always be valid and created from a box unsafe { next.as_mut() }.prev = new_node }); self.next = new_node; } /// Push a value before this node pub fn push_before(&mut self, element: T) { let new_node = Some(allocate_nonnull(Node { value: element, next: NonNull::new(self as _), prev: self.prev, })); self.prev.map(|mut next| { // SAFETY: All pointers should always be valid and created from a box unsafe { next.as_mut() }.next = new_node }); self.prev = new_node; } /// Get the next node pub fn next(&self) -> Option<&Node> { self.next.as_ref().map(|nn| unsafe { nn.as_ref() }) } /// Get the next node mutably pub fn next_mut(&mut self) -> Option<&mut Node> { self.next.as_mut().map(|nn| unsafe { nn.as_mut() }) } /// Get the previous node pub fn previous(&self) -> Option<&Node> { self.prev.as_ref().map(|nn| unsafe { nn.as_ref() }) } /// Get the previous node mutably pub fn previous_mut(&mut self) -> Option<&mut Node> { self.prev.as_mut().map(|nn| unsafe { nn.as_mut() }) } /// Gets the value from the node pub fn get(&self) -> &T { &self.value } /// Gets the value from the node pub fn set(&mut self, value: T) { self.value = value; } /// Gets the value from the node and replaces it with the old one pub fn replace_value(&mut self, value: T) -> T { std::mem::replace(&mut self.value, value) } /// Removes a value from the List and returns it pub fn remove(&mut self) -> T { // SAFETY: All pointers should always be valid unsafe { self.next.map(|mut next| next.as_mut().prev = self.prev); self.prev.map(|mut prev| prev.as_mut().next = self.next); } // SAFETY: A reference is always valid and we have the only one now let node = unsafe { Box::from_raw(self) }; node.value } } fn allocate_nonnull(element: T) -> NonNull { let boxed = Box::new(element); // SAFETY: box is always non-null unsafe { NonNull::new_unchecked(Box::leak(boxed)) } } /// The iterator over the linked list pub struct Iter<'a, T>(Option<&'a Node>); impl<'a, T> Iter<'a, T> { fn new(list: &'a LinkedList) -> Self { Self(list.start.as_ref().map(|nn| { // SAFETY: All pointers should always be valid, the list lives as long as its items unsafe { nn.as_ref() } })) } } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option { let current = self.0; match current { Some(node) => { self.0 = node.next.as_ref().map(|nn| { // SAFETY: All pointers should always be valid unsafe { nn.as_ref() } }); Some(&node.value) } None => None, } } } /// The owning iterator over the linked list pub struct IntoIter(Option>>); impl IntoIter { fn new(list: LinkedList) -> Self { let iter = Self(list.start.as_ref().map(|nn| { // SAFETY: All pointers should always be valid, the list lives as long as its items unsafe { Box::from_raw(nn.as_ptr()) } })); // We are not allowed to drop the list - the items will be freed during the iteration std::mem::forget(list); iter } } impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { let current = self.0.take(); match current { Some(node) => { self.0 = node.next.as_ref().map(|nn| { // SAFETY: All pointers should always be valid, the list lives as long as its items unsafe { Box::from_raw(nn.as_ptr()) } }); Some(node.value) // the node is freed here } None => None, } } } /// The iterator over the linked list pub struct IterMut<'a, T>(Option<&'a mut Node>); impl<'a, T> IterMut<'a, T> { fn new(list: &'a mut LinkedList) -> Self { Self(list.start.as_mut().map(|nn| { // SAFETY: All pointers should always be valid, the list lives as long as its items unsafe { nn.as_mut() } })) } } impl<'a, T> Iterator for IterMut<'a, T> { type Item = &'a mut T; fn next(&mut self) -> Option { let current = self.0.take(); match current { Some(node) => { self.0 = node.next.as_mut().map(|nn| { // SAFETY: All pointers should always be valid unsafe { nn.as_mut() } }); Some(&mut node.value) } None => None, } } }