started work on cursors

This commit is contained in:
nora 2021-08-13 17:02:22 +02:00
parent c0a009374d
commit 5c4deeadc0
2 changed files with 412 additions and 137 deletions

View file

@ -7,6 +7,7 @@ use std::iter::FromIterator;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::option::Option::Some;
use std::ptr::NonNull; use std::ptr::NonNull;
fn allocate_nonnull<T>(element: T) -> NonNull<T> { fn allocate_nonnull<T>(element: T) -> NonNull<T> {
@ -160,16 +161,56 @@ impl<T, const COUNT: usize> PackedLinkedList<T, COUNT> {
} }
} }
pub fn iter(&self) -> Iter<T, COUNT> { pub fn cursor_front(&self) -> Cursor<T, COUNT> {
Iter::new(self) Cursor {
node: self.first,
index: 0,
list: self,
}
} }
pub fn iter_mut(&mut self) -> IterMut<T, COUNT> { pub fn cursor_back(&self) -> Cursor<T, COUNT> {
IterMut::new(self) Cursor {
node: self.last,
// point to the last element in the last node, or 0 if no node is found
index: self
.last
.map(|last| unsafe { last.as_ref().size - 1 })
.unwrap_or(0),
list: self,
}
} }
pub fn into_iter(self) -> IntoIter<T, COUNT> { pub fn cursor_mut_front(&mut self) -> CursorMut<T, COUNT> {
IntoIter::new(self) CursorMut {
node: self.first,
index: 0,
list: self,
}
}
pub fn cursor_mut_back(&mut self) -> CursorMut<T, COUNT> {
CursorMut {
node: self.last,
// point to the last element in the last node, or 0 if no node is found
index: self
.last
.map(|last| unsafe { last.as_ref().size - 1 })
.unwrap_or(0),
list: self,
}
}
pub fn iter(&self) -> iter::Iter<T, COUNT> {
iter::Iter::new(self)
}
pub fn iter_mut(&mut self) -> iter::IterMut<T, COUNT> {
iter::IterMut::new(self)
}
pub fn into_iter(self) -> iter::IntoIter<T, COUNT> {
iter::IntoIter::new(self)
} }
fn insert_node_start(&mut self) { fn insert_node_start(&mut self) {
@ -253,10 +294,7 @@ where
T: PartialEq, T: PartialEq,
{ {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() { self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a == b)
return false;
}
self.iter().zip(other.iter()).all(|(a, b)| a == b)
} }
} }
@ -316,24 +354,218 @@ impl<T, const COUNT: usize> Node<T, COUNT> {
self.values[0] = MaybeUninit::new(element); self.values[0] = MaybeUninit::new(element);
self.size += 1; self.size += 1;
} }
/// Inserts a new value at the index, copying the values up
/// # Safety
/// The node must not be full and the index must not be out of bounds
unsafe fn insert(&mut self, element: T, index: usize) {
debug_assert!(self.size < COUNT);
// copy all values up
if COUNT > 1 {
std::ptr::copy(
&self.values[index] as *const _,
&mut self.values[index + 1] as *mut _,
self.size - index,
);
}
self.values[index] = MaybeUninit::new(element);
}
} }
#[derive(Debug)] macro_rules! implement_cursor {
pub struct Iter<'a, T, const COUNT: usize> { ($cursor:ident) => {
impl<'a, T, const COUNT: usize> $cursor<'a, T, COUNT> {
pub fn get(&self) -> Option<&T> {
self.node
.map(|nn| unsafe { nn.as_ref().values[self.index].as_ptr().as_ref().unwrap() })
}
pub fn move_next(&mut self) {
match self.node {
None => {
// currently on the ghost node, move to the first node
self.node = self.list.first;
self.index = 0;
}
Some(node) => unsafe {
let node = node.as_ref();
if self.index == node.size - 1 {
// the last item, go to the next node
self.node = node.next;
self.index = 0;
} else {
// stay on the same node
self.index += 1;
}
},
}
}
pub fn move_prev(&mut self) {
match self.node {
None => {
// currently on the ghost node, move to the first node
self.node = self.list.last;
self.index = self
.list
.last
.map(|nn| unsafe { nn.as_ref().size - 1 })
.unwrap_or(0);
}
Some(node) => unsafe {
let node = node.as_ref();
if self.index == 0 {
// the first item, go to the previous node
self.node = node.prev;
self.index = node.prev.map(|nn| nn.as_ref().size - 1).unwrap_or(0);
} else {
// stay on the same node
self.index -= 1;
}
},
}
}
}
};
}
/// A cursor for navigating the Packed Linked List
pub struct Cursor<'a, T, const COUNT: usize> {
node: Option<NonNull<Node<T, COUNT>>>,
index: usize,
list: &'a PackedLinkedList<T, COUNT>,
}
// A cursor for navigating and editing the Packed Linked List
pub struct CursorMut<'a, T, const COUNT: usize> {
node: Option<NonNull<Node<T, COUNT>>>,
index: usize,
list: &'a mut PackedLinkedList<T, COUNT>,
}
implement_cursor!(Cursor);
implement_cursor!(CursorMut);
impl<'a, T, const COUNT: usize> CursorMut<'a, T, COUNT> {
pub fn get_mut(&mut self) -> Option<&mut T> {
let index = self.index;
self.node
.as_mut()
.map(|nn| unsafe { nn.as_mut().values[index].as_mut_ptr().as_mut().unwrap() })
}
pub fn replace(&mut self, _element: T) -> Option<T> {
todo!()
}
pub fn remove(&mut self) -> Option<T> {
todo!()
}
/// Inserts a new element after the element this cursor is pointing to.
/// If the cursor is pointing at the ghost node, the item gets inserted at the start of the list
/// The cursor position will not change.
pub fn insert_after(&mut self, element: T) {
match self.node {
None => self.list.push_front(element),
Some(mut current_node) => {
let current = unsafe { current_node.as_mut() };
// if we point at the last element, we do not need to copy anything
let append = self.index == current.size - 1;
// There are several cases here
// 1. we append an item to the node, and it is not full
// 2. we append an item to the node, and it is full
// 3. we insert an item into the node, and it is not full
// 4. we insert an item into the node, and it is full
match (append, current.is_full()) {
(true, false) => {
// SAFETY: the node is not full
unsafe { current.push_back(element) };
}
(true, true) => {
// check whether the next node is full. if it is not full, insert it at the start
// if it is full or the next node doesn't exist, allocate a new node inbetween
let next_node = unsafe { current.next.as_mut().map(|nn| nn.as_mut()) };
let need_allocate = next_node
.as_ref()
.map(|node| node.is_full())
.unwrap_or(true);
if need_allocate {
unsafe {
let mut new_node = self.allocate_new_node_after();
new_node.as_mut().push_back(element);
}
} else {
let next_node = next_node
.unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() });
// SAFETY: the node is not full, because `need_allocate` is false
unsafe { next_node.push_back(element) };
}
}
// SAFETY: the node is not full and the index is not out of bounds
(false, false) => unsafe { current.insert(element, self.index + 1) },
(false, true) => {
// check whether the next node is full. if it is not full, insert it at the start
// if it is full or the next node doesn't exist, allocate a new node inbetween
}
}
}
}
}
pub fn insert_before(&mut self, _element: T) {}
/// allocates a new node after the cursor
/// if self.node is None, it allocates the node at the start of the list
/// # Safety
/// The node must immediately be filled with at least on element, since an empty node is not a valid state
unsafe fn allocate_new_node_after(&mut self) -> NonNull<Node<T, COUNT>> {
let mut new_node = allocate_nonnull(Node::new(
self.node, None, // will be replaced in the match below
));
match self.node {
None => {
match self.list.first {
None => self.list.last = Some(new_node),
Some(mut first) => first.as_mut().prev = Some(new_node),
}
new_node.as_mut().next = self.list.first;
self.list.first = Some(new_node);
}
Some(mut node) => {
new_node.as_mut().next = node.as_ref().next;
node.as_mut().next = Some(new_node);
}
}
new_node
}
}
mod iter {
use super::{Node, PackedLinkedList};
use std::marker::PhantomData;
use std::mem;
use std::mem::MaybeUninit;
use std::ptr::NonNull;
#[derive(Debug)]
pub struct Iter<'a, T, const COUNT: usize> {
node: Option<&'a Node<T, COUNT>>, node: Option<&'a Node<T, COUNT>>,
index: usize, index: usize,
} }
impl<'a, T, const COUNT: usize> Iter<'a, T, COUNT> { impl<'a, T, const COUNT: usize> Iter<'a, T, COUNT> {
fn new(list: &'a PackedLinkedList<T, COUNT>) -> Self { pub(super) fn new(list: &'a PackedLinkedList<T, COUNT>) -> Self {
Self { Self {
node: list.first.as_ref().map(|nn| unsafe { nn.as_ref() }), node: list.first.as_ref().map(|nn| unsafe { nn.as_ref() }),
index: 0, index: 0,
} }
} }
} }
impl<'a, T, const COUNT: usize> Iterator for Iter<'a, T, COUNT> { impl<'a, T, const COUNT: usize> Iterator for Iter<'a, T, COUNT> {
type Item = &'a T; type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -357,26 +589,26 @@ impl<'a, T, const COUNT: usize> Iterator for Iter<'a, T, COUNT> {
} }
} }
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct IterMut<'a, T, const COUNT: usize> { pub struct IterMut<'a, T, const COUNT: usize> {
node: Option<NonNull<Node<T, COUNT>>>, node: Option<NonNull<Node<T, COUNT>>>,
index: usize, index: usize,
_marker: PhantomData<&'a T>, _marker: PhantomData<&'a T>,
} }
impl<'a, T, const COUNT: usize> IterMut<'a, T, COUNT> { impl<'a, T, const COUNT: usize> IterMut<'a, T, COUNT> {
fn new(list: &'a mut PackedLinkedList<T, COUNT>) -> Self { pub(super) fn new(list: &'a mut PackedLinkedList<T, COUNT>) -> Self {
Self { Self {
node: list.first, node: list.first,
index: 0, index: 0,
_marker: PhantomData, _marker: PhantomData,
} }
} }
} }
impl<'a, T: 'a, const COUNT: usize> Iterator for IterMut<'a, T, COUNT> { impl<'a, T: 'a, const COUNT: usize> Iterator for IterMut<'a, T, COUNT> {
type Item = &'a mut T; type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -404,22 +636,22 @@ impl<'a, T: 'a, const COUNT: usize> Iterator for IterMut<'a, T, COUNT> {
} }
} }
} }
} }
#[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>>>,
index: usize, index: usize,
} }
impl<T, const COUNT: usize> Drop for IntoIter<T, COUNT> { impl<T, const COUNT: usize> Drop for IntoIter<T, COUNT> {
fn drop(&mut self) { fn drop(&mut self) {
while let Some(_) = self.next() {} while let Some(_) = self.next() {}
} }
} }
impl<T, const COUNT: usize> IntoIter<T, COUNT> { impl<T, const COUNT: usize> IntoIter<T, COUNT> {
fn new(list: PackedLinkedList<T, COUNT>) -> Self { pub(super) fn new(list: PackedLinkedList<T, COUNT>) -> Self {
let iter = Self { let iter = Self {
node: list.first.map(|nn| unsafe { Box::from_raw(nn.as_ptr()) }), node: list.first.map(|nn| unsafe { Box::from_raw(nn.as_ptr()) }),
index: 0, index: 0,
@ -428,9 +660,9 @@ impl<T, const COUNT: usize> IntoIter<T, COUNT> {
mem::forget(list); mem::forget(list);
iter iter
} }
} }
impl<T, const COUNT: usize> Iterator for IntoIter<T, COUNT> { impl<T, const COUNT: usize> Iterator for IntoIter<T, COUNT> {
type Item = T; type Item = T;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -444,8 +676,8 @@ impl<T, const COUNT: usize> Iterator for IntoIter<T, COUNT> {
// take more items from the node // take more items from the node
// take out the item and replace it with uninitialized memory // take out the item and replace it with uninitialized memory
// the index pointer is increased, so no one will access this again // the index pointer is increased, so no one will access this again
let item = let item = mem::replace(&mut node.values[self.index], MaybeUninit::uninit())
mem::replace(&mut node.values[self.index], MaybeUninit::uninit()).assume_init(); .assume_init();
self.index += 1; self.index += 1;
// re-insert the node // re-insert the node
self.node = Some(node); self.node = Some(node);
@ -471,4 +703,5 @@ impl<T, const COUNT: usize> Iterator for IntoIter<T, COUNT> {
} }
} }
} }
}
} }

View file

@ -76,6 +76,48 @@ fn from_iter() {
assert!(list_iter.zip(vec.iter()).all(|(a, b)| a == b)); assert!(list_iter.zip(vec.iter()).all(|(a, b)| a == b));
} }
#[test]
fn get_cursor() {
let list = create_list(&[1, 2, 3, 4, 5, 6]);
let mut cursor = list.cursor_front();
assert_eq!(cursor.get(), Some(&1));
cursor.move_next();
assert_eq!(cursor.get(), Some(&2));
cursor.move_prev();
assert_eq!(cursor.get(), Some(&1));
cursor.move_prev();
assert_eq!(cursor.get(), None);
cursor.move_prev();
assert_eq!(cursor.get(), Some(&6));
cursor.move_prev();
cursor.move_prev();
cursor.move_prev();
cursor.move_prev();
cursor.move_prev();
assert_eq!(cursor.get(), Some(&1));
cursor.move_prev();
cursor.move_next();
assert_eq!(cursor.get(), Some(&1));
}
#[test]
fn insert_cursor() {
let mut list = create_list(&[1, 2, 3, 4, 5, 6]);
let mut cursor = list.cursor_mut_front();
cursor.move_prev();
cursor.move_prev();
*cursor.get_mut().unwrap() = 100;
cursor.move_next();
cursor.move_next();
cursor.insert_after(11);
cursor.insert_before(0);
cursor.move_next();
assert_eq!(cursor.replace(12), Some(1));
assert_eq!(cursor.get(), Some(&12));
assert_eq!(cursor.remove(), Some(12));
assert_eq!(list, create_list(&[0, 11, 2, 3, 4, 5, 100]));
}
fn create_list<T: Clone>(iter: &[T]) -> PackedLinkedList<T, 16> { fn create_list<T: Clone>(iter: &[T]) -> PackedLinkedList<T, 16> {
iter.into_iter().cloned().collect() iter.into_iter().cloned().collect()
} }