iter mut and len

This commit is contained in:
nora 2021-08-12 20:20:49 +02:00
parent 7249de2bd4
commit 521609e769
3 changed files with 113 additions and 5 deletions

View file

@ -1,4 +1,4 @@
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use datastructures::linked_list::LinkedList; use datastructures::linked_list::LinkedList;
use datastructures::packed_linked_list::PackedLinkedList; use datastructures::packed_linked_list::PackedLinkedList;

View file

@ -1,6 +1,8 @@
#[cfg(test)] #[cfg(test)]
mod test; mod test;
use std::fmt::Formatter;
use std::hash::Hasher;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
@ -22,9 +24,11 @@ fn allocate_nonnull<T>(element: T) -> NonNull<T> {
/// ///
/// Another way to optimize a linked list is by having a `Vec` of nodes that each have relative references, /// Another way to optimize a linked list is by having a `Vec` of nodes that each have relative references,
/// but this implementation does not implement this. /// but this implementation does not implement this.
#[derive(Eq)]
pub struct PackedLinkedList<T, const COUNT: usize> { pub struct PackedLinkedList<T, const COUNT: usize> {
first: Option<NonNull<Node<T, COUNT>>>, first: Option<NonNull<Node<T, COUNT>>>,
last: Option<NonNull<Node<T, COUNT>>>, last: Option<NonNull<Node<T, COUNT>>>,
len: usize,
_maker: PhantomData<T>, _maker: PhantomData<T>,
} }
@ -39,14 +43,21 @@ impl<T, const COUNT: usize> Drop for PackedLinkedList<T, COUNT> {
} }
impl<T, const COUNT: usize> PackedLinkedList<T, COUNT> { impl<T, const COUNT: usize> PackedLinkedList<T, COUNT> {
/// Constructs an empty PackedLinkedList
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
first: None, first: None,
last: None, last: None,
len: 0,
_maker: PhantomData, _maker: PhantomData,
} }
} }
/// The length of the list (O(1))
pub fn len(&self) -> usize {
self.len
}
/// Pushes a new value to the front of the list /// Pushes a new value to the front of the list
pub fn push_front(&mut self, element: T) { pub fn push_front(&mut self, element: T) {
// SAFETY: All pointers should always point to valid memory, // SAFETY: All pointers should always point to valid memory,
@ -62,6 +73,7 @@ impl<T, const COUNT: usize> PackedLinkedList<T, COUNT> {
} }
Some(mut node) => node.as_mut().push_front(element), Some(mut node) => node.as_mut().push_front(element),
} }
self.len += 1;
} }
} }
@ -76,10 +88,11 @@ impl<T, const COUNT: usize> PackedLinkedList<T, COUNT> {
} }
Some(node) if node.as_ref().is_full() => { Some(node) if node.as_ref().is_full() => {
self.insert_node_end(); self.insert_node_end();
self.last.unwrap().as_mut().push_front(element) self.last.unwrap().as_mut().push_back(element)
} }
Some(mut node) => node.as_mut().push_back(element), Some(mut node) => node.as_mut().push_back(element),
} }
self.len += 1;
} }
} }
@ -111,6 +124,7 @@ impl<T, const COUNT: usize> PackedLinkedList<T, COUNT> {
node.size -= 1; node.size -= 1;
} }
self.len -= 1;
Some(item) Some(item)
} }
} }
@ -141,7 +155,7 @@ impl<T, const COUNT: usize> PackedLinkedList<T, COUNT> {
// more items // more items
node.size -= 1; node.size -= 1;
} }
self.len -= 1;
Some(item) Some(item)
} }
} }
@ -150,6 +164,10 @@ impl<T, const COUNT: usize> PackedLinkedList<T, COUNT> {
Iter::new(self) Iter::new(self)
} }
pub fn iter_mut(&mut self) -> IterMut<T, COUNT> {
IterMut::new(self)
}
pub fn into_iter(self) -> IntoIter<T, COUNT> { pub fn into_iter(self) -> IntoIter<T, COUNT> {
IntoIter::new(self) IntoIter::new(self)
} }
@ -197,6 +215,51 @@ impl<T, const COUNT: usize> Extend<T> for PackedLinkedList<T, COUNT> {
} }
} }
impl<T, const COUNT: usize> std::fmt::Debug for PackedLinkedList<T, COUNT>
where
T: std::fmt::Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T, const COUNT: usize> Default for PackedLinkedList<T, COUNT> {
fn default() -> Self {
Self::new()
}
}
impl<T, const COUNT: usize> Clone for PackedLinkedList<T, COUNT>
where
T: Clone,
{
fn clone(&self) -> Self {
self.iter().cloned().collect()
}
}
impl<T, const COUNT: usize> std::hash::Hash for PackedLinkedList<T, COUNT>
where
T: std::hash::Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.iter().for_each(|item| item.hash(state))
}
}
impl<T, const COUNT: usize> PartialEq for PackedLinkedList<T, COUNT>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
self.iter().zip(other.iter()).all(|(a, b)| a == b)
}
}
/// A single node in the packed linked list /// A single node in the packed linked list
/// ///
/// The node can have 1 to `COUNT` items. /// The node can have 1 to `COUNT` items.
@ -296,6 +359,53 @@ impl<'a, T, const COUNT: usize> Iterator for Iter<'a, T, COUNT> {
} }
} }
#[derive(Debug)]
pub struct IterMut<'a, T, const COUNT: usize> {
node: Option<NonNull<Node<T, COUNT>>>,
index: usize,
_marker: PhantomData<&'a T>,
}
impl<'a, T, const COUNT: usize> IterMut<'a, T, COUNT> {
fn new(list: &'a mut PackedLinkedList<T, COUNT>) -> Self {
Self {
node: list.first,
index: 0,
_marker: PhantomData,
}
}
}
impl<'a, T: 'a, const COUNT: usize> Iterator for IterMut<'a, T, COUNT> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
// SAFETY: assume that all pointers point to the correct nodes,
// and that the sizes of the nodes are set correctly
unsafe {
let mut node = self.node?;
let node = node.as_mut();
if node.size > self.index {
// take more
let ptr = node.values[self.index].as_ptr() as *mut T;
let item = ptr.as_mut().unwrap();
self.index += 1;
Some(item)
} else {
// next node
let mut next_node = node.next?;
debug_assert_ne!(next_node.as_ref().size, 0);
self.index = 1;
self.node = Some(next_node);
// a node should never be empty
let ptr = next_node.as_mut().values[0].as_ptr() as *mut T;
Some(ptr.as_mut().unwrap())
}
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct IntoIter<T, const COUNT: usize> { pub struct IntoIter<T, const COUNT: usize> {
node: Option<Box<Node<T, COUNT>>>, node: Option<Box<Node<T, COUNT>>>,

View file

@ -57,9 +57,7 @@ fn into_iter() {
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
// ignore this test for now
#[test] #[test]
#[cfg(all(test, not(test)))]
fn iter_mut() { fn iter_mut() {
let mut list = create_list(&[1, 2, 3, 4]); let mut list = create_list(&[1, 2, 3, 4]);
let mut iter_mut = list.iter_mut(); let mut iter_mut = list.iter_mut();