diff --git a/src/linked_list.rs b/src/linked_list/mod.rs similarity index 60% rename from src/linked_list.rs rename to src/linked_list/mod.rs index 9cd0f5e..7219b7e 100644 --- a/src/linked_list.rs +++ b/src/linked_list/mod.rs @@ -1,4 +1,9 @@ +#[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; @@ -27,7 +32,7 @@ use std::ptr::NonNull; /// let mut list = LinkedList::new(); /// /// list.push_front(1); -/// let mut node = list.get_mut_head_node().unwrap(); +/// let mut node = list.front_node_mut().unwrap(); /// node.push_after(3); /// node.push_after(2); /// let next = node.next().unwrap(); @@ -37,6 +42,7 @@ use std::ptr::NonNull; /// /// # 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>>, @@ -53,59 +59,81 @@ impl LinkedList { } } - /// Push an element to the start of the list (O(1)) + /// 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 { - // empty list - None => { - let new_node = allocate_nonnull(Node { - value: element, - next: None, - prev: None, - }); - self.start = Some(new_node); - self.end = Some(new_node); - } - // at lest one element Some(mut old_start) => { - let new_node = allocate_nonnull(Node { - value: element, - next: Some(old_start), - prev: None, - }); - // SAFETY: All pointers should always be valid + // SAFETY: All pointers should always be valid. unsafe { old_start.as_mut() }.prev = Some(new_node); - self.start = 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)) + /// 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 { - None => { - let new_node = allocate_nonnull(Node { - value: element, - next: None, - prev: None, - }); - self.start = Some(new_node); - self.end = Some(new_node); - } Some(mut old_end) => { - let new_node = allocate_nonnull(Node { - value: element, - next: None, - prev: Some(old_end), - }); - // SAFETY: All pointers should always be valid + // SAFETY: All pointers should always be valid. unsafe { old_end.as_mut() }.next = Some(new_node); - self.end = Some(new_node); } + // List is empty - set the start + None => self.start = Some(new_node), } + self.end = Some(new_node); } - /// Get an element from the list (O(n)) + /// 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; @@ -122,17 +150,17 @@ impl LinkedList { result } - /// Gets the last element from the list (O(1)) + /// 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)) + /// 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 + /// 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; @@ -149,25 +177,6 @@ impl LinkedList { result } - /// Get the head node from the list that can only be used for navigation - pub fn get_head_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 get_tail_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 get_mut_head_node(&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 get_mut_tail_node(&mut self) -> Option<&mut Node> { - self.end.as_mut().map(|nn| unsafe { nn.as_mut() }) - } - /// 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; @@ -185,6 +194,25 @@ impl LinkedList { 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 @@ -198,8 +226,22 @@ impl LinkedList { 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() @@ -212,6 +254,50 @@ impl Default for LinkedList { } } +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; @@ -330,18 +416,14 @@ fn allocate_nonnull(element: T) -> NonNull { } /// The iterator over the linked list -pub struct Iter<'a, T> { - item: Option<&'a Node>, -} +pub struct Iter<'a, T>(Option<&'a Node>); impl<'a, T> Iter<'a, T> { fn new(list: &'a LinkedList) -> Self { - Self { - item: 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() } - }), - } + 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() } + })) } } @@ -349,10 +431,10 @@ impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option { - let current = self.item; + let current = self.0; match current { Some(node) => { - self.item = node.next.as_ref().map(|nn| { + self.0 = node.next.as_ref().map(|nn| { // SAFETY: All pointers should always be valid unsafe { nn.as_ref() } }); @@ -363,113 +445,67 @@ impl<'a, T> Iterator for Iter<'a, T> { } } -#[cfg(test)] -mod test { - use super::*; +/// The owning iterator over the linked list +pub struct IntoIter(Option>>); - #[test] - fn random_access() { - let mut list = LinkedList::new(); - 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 push_start_end() { - let mut list = LinkedList::new(); - list.push_back(3); - list.push_front(2); - list.push_front(1); - list.push_back(4); - list.push_back(5); - let vec = list.iter().cloned().collect::>(); - assert_eq!(&vec[..], &[1, 2, 3, 4, 5]); - } - - #[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)); - } - - #[test] - fn node_operations() { - let mut list = LinkedList::new(); - list.push_front(1); - list.push_back(2); - { - let node = list.get_mut_node(1).unwrap(); - assert_eq!(*node.get(), 2); - node.push_after(4); - let next = node.next_mut().unwrap(); - assert!(matches!(next.next(), None)); - next.push_before(3) - } - let vec = list.iter().cloned().collect::>(); - assert_eq!(&vec[..], &[1, 2, 3, 4]); - } - - #[test] - fn node_values() { - let mut list = LinkedList::new(); - list.push_front(1); - let node = list.get_mut_node(0).unwrap(); - assert_eq!(*node.get(), 1); - assert_eq!(node.replace_value(2), 1); - assert_eq!(*node.get(), 2); - node.push_after(3); - let node = node.next_mut().unwrap(); - node.set(4); - assert_eq!(*node.get(), 4); - } - - #[test] - fn node_removal() { - let mut list = LinkedList::new(); - list.push_back(1); - list.push_back(2); - list.push_back(4); - let node_two = list.get_mut_head_node().unwrap().next_mut().unwrap(); - node_two.replace_value(3); - let three = node_two.remove(); - assert_eq!(three, 3); - assert_eq!(list.get_head(), Some(&1)); - assert_eq!(list.get_tail(), Some(&4)); - assert_eq!(*list.get_head_node().unwrap().next().unwrap().get(), 4); +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, + } } } diff --git a/src/linked_list/test.rs b/src/linked_list/test.rs new file mode 100644 index 0000000..0420d5e --- /dev/null +++ b/src/linked_list/test.rs @@ -0,0 +1,158 @@ +use super::*; + +#[test] +fn random_access() { + let list = create_list(&["nice", "test", "hallo"]); + 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 push_start_end() { + let mut list = LinkedList::new(); + list.push_back(3); + list.push_front(2); + list.push_front(1); + list.push_back(4); + list.push_back(5); + let vec = list.iter().cloned().collect::>(); + assert_eq!(&vec[..], &[1, 2, 3, 4, 5]); +} + +#[test] +fn pop_back() { + let mut list = create_list(&["hi", "3", "5"]); + assert_eq!(Some("5"), list.pop_back()); + assert_eq!(Some("3"), list.pop_back()); + assert_eq!(Some("hi"), list.pop_back()); + assert_eq!(None, list.pop_back()); +} + +#[test] +fn pop_front() { + let mut list = create_list(&["hi", "3", "5"]); + assert_eq!(Some("hi"), list.pop_front()); + assert_eq!(Some("3"), list.pop_front()); + assert_eq!(Some("5"), list.pop_front()); + assert_eq!(None, list.pop_front()); +} + +#[test] +fn iter_simple() { + let list = create_list(&["nice", "test", "hallo"]); + 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 list = create_list(&["nice", "test", "hallo"]); + 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 into_iterator() { + let list = create_list(&["nice", "test", "hallo"]); + let vec = list.into_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 iter_mut() { + let mut list = create_list(&[1, 2, 3]); + let iter = list.iter_mut(); + iter.for_each(|item| { + *item *= 2; + }); + assert_eq!(list, create_list(&[2, 4, 6])); +} + +#[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)); +} + +#[test] +fn node_operations() { + let mut list = LinkedList::new(); + list.push_front(1); + list.push_back(2); + { + let node = list.get_mut_node(1).unwrap(); + assert_eq!(*node.get(), 2); + node.push_after(4); + let next = node.next_mut().unwrap(); + assert!(matches!(next.next(), None)); + next.push_before(3) + } + let vec = list.iter().cloned().collect::>(); + assert_eq!(&vec[..], &[1, 2, 3, 4]); +} + +#[test] +fn node_values() { + let mut list = LinkedList::new(); + list.push_front(1); + let node = list.get_mut_node(0).unwrap(); + assert_eq!(*node.get(), 1); + assert_eq!(node.replace_value(2), 1); + assert_eq!(*node.get(), 2); + node.push_after(3); + let node = node.next_mut().unwrap(); + node.set(4); + assert_eq!(*node.get(), 4); +} + +#[test] +fn node_removal() { + let mut list = create_list(&[1, 2, 4]); + let node_two = list.front_node_mut().unwrap().next_mut().unwrap(); + node_two.replace_value(3); + let three = node_two.remove(); + assert_eq!(three, 3); + assert_eq!(list.get_head(), Some(&1)); + assert_eq!(list.get_tail(), Some(&4)); + assert_eq!(*list.front_node().unwrap().next().unwrap().get(), 4); +} + +#[test] +fn list_len() { + let list = create_list(&[1, 2, 3, 4, 5, 6, 7, 8, 9]); + assert_eq!(list.len(), 9); +} + +#[test] +fn std_traits() { + let mut list1 = create_list(&[1, 5, 732, 533]); + let list2 = create_list(&[1, 5, 732, 533]); + assert_eq!(list1, list2); + + list1.extend([99, 100].iter().cloned()); + assert_eq!(list1, create_list(&[1, 5, 732, 533, 99, 100])); + + let vec1 = vec![1, 5, 732, 533, 99, 100]; + let list_from_vec = vec1.into_iter().collect::>(); + assert_eq!(list1, list_from_vec); +} + +/// Creates an owned list from a slice, not efficient at all but easy to use +fn create_list(iter: &[T]) -> LinkedList { + iter.into_iter().cloned().collect() +}