mirror of
https://github.com/Noratrieb/datastructures.git
synced 2026-01-14 17:35:02 +01:00
more impls and tests
This commit is contained in:
parent
e41d110dd7
commit
73f9094f20
2 changed files with 372 additions and 178 deletions
|
|
@ -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<T> {
|
||||
start: Option<NonNull<Node<T>>>,
|
||||
end: Option<NonNull<Node<T>>>,
|
||||
|
|
@ -53,59 +59,81 @@ impl<T> LinkedList<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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<T> {
|
||||
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<T> {
|
||||
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<T> LinkedList<T> {
|
|||
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<T>> {
|
||||
let mut node = &self.start;
|
||||
let mut result = None;
|
||||
|
|
@ -149,25 +177,6 @@ impl<T> LinkedList<T> {
|
|||
result
|
||||
}
|
||||
|
||||
/// Get the head node from the list that can only be used for navigation
|
||||
pub fn get_head_node(&self) -> Option<&Node<T>> {
|
||||
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<T>> {
|
||||
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<T>> {
|
||||
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<T>> {
|
||||
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<T>> {
|
||||
let mut node = &mut self.start;
|
||||
|
|
@ -185,6 +194,25 @@ impl<T> LinkedList<T> {
|
|||
result
|
||||
}
|
||||
|
||||
/// Get the head node from the list that can only be used for navigation
|
||||
pub fn front_node(&self) -> Option<&Node<T>> {
|
||||
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<T>> {
|
||||
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<T>> {
|
||||
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<T>> {
|
||||
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<T> LinkedList<T> {
|
|||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter::new(self)
|
||||
}
|
||||
|
||||
/// Returns a mut iterator over the items
|
||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||
IterMut::new(self)
|
||||
}
|
||||
|
||||
/// Returns an iterator owning the items
|
||||
pub fn into_iter(self) -> IntoIter<T> {
|
||||
IntoIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
/////
|
||||
///// std trait implementations
|
||||
/////
|
||||
|
||||
impl<T: Debug> Debug for LinkedList<T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_list().entries(self.iter()).finish()
|
||||
|
|
@ -212,6 +254,50 @@ impl<T> Default for LinkedList<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for LinkedList<T> {
|
||||
fn clone(&self) -> Self {
|
||||
self.iter().cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash> Hash for LinkedList<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.iter().for_each(|item| item.hash(state));
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for LinkedList<T> {
|
||||
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<T> FromIterator<T> for LinkedList<T> {
|
||||
fn from_iter<I: IntoIterator<Item = T>>(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<T> Extend<T> for LinkedList<T> {
|
||||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
let mut iter = iter.into_iter();
|
||||
while let Some(item) = iter.next() {
|
||||
self.push_back(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for LinkedList<T> {
|
||||
fn drop(&mut self) {
|
||||
let mut item = self.start;
|
||||
|
|
@ -330,18 +416,14 @@ fn allocate_nonnull<T>(element: T) -> NonNull<T> {
|
|||
}
|
||||
|
||||
/// The iterator over the linked list
|
||||
pub struct Iter<'a, T> {
|
||||
item: Option<&'a Node<T>>,
|
||||
}
|
||||
pub struct Iter<'a, T>(Option<&'a Node<T>>);
|
||||
|
||||
impl<'a, T> Iter<'a, T> {
|
||||
fn new(list: &'a LinkedList<T>) -> 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<Self::Item> {
|
||||
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<T>(Option<Box<Node<T>>>);
|
||||
|
||||
#[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::<Vec<_>>();
|
||||
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::<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));
|
||||
}
|
||||
|
||||
#[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::<Vec<_>>();
|
||||
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<T> IntoIter<T> {
|
||||
fn new(list: LinkedList<T>) -> 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<T> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
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<T>>);
|
||||
|
||||
impl<'a, T> IterMut<'a, T> {
|
||||
fn new(list: &'a mut LinkedList<T>) -> 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<Self::Item> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
158
src/linked_list/test.rs
Normal file
158
src/linked_list/test.rs
Normal file
|
|
@ -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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
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::<LinkedList<_>>();
|
||||
assert_eq!(list1, list_from_vec);
|
||||
}
|
||||
|
||||
/// Creates an owned list from a slice, not efficient at all but easy to use
|
||||
fn create_list<T: Clone>(iter: &[T]) -> LinkedList<T> {
|
||||
iter.into_iter().cloned().collect()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue