mirror of
https://github.com/Noratrieb/datastructures.git
synced 2026-01-14 17:35:02 +01:00
started work on cursors
This commit is contained in:
parent
c0a009374d
commit
5c4deeadc0
2 changed files with 412 additions and 137 deletions
|
|
@ -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> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue