mirror of
https://github.com/Noratrieb/datastructures.git
synced 2026-01-14 17:35:02 +01:00
iter mut and len
This commit is contained in:
parent
7249de2bd4
commit
521609e769
3 changed files with 113 additions and 5 deletions
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>>>,
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue