Skip to content

Commit

Permalink
SortedLinkedList: add SortedLinkedListView, similar to VecView on top…
Browse files Browse the repository at this point in the history
… of #486
  • Loading branch information
sosthene-nitrokey committed Jul 1, 2024
1 parent 02cc494 commit eb48d9e
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `LinearMapView`, the `!Sized` version of `LinearMap`.
- Added `HistoryBufferView`, the `!Sized` version of `HistoryBuffer`.
- Added `DequeView`, the `!Sized` version of `Deque`.
- Added `SortedLinkedListView`, the `!Sized` version of `SortedLinkedList`.

### Changed

Expand Down
104 changes: 80 additions & 24 deletions src/sorted_linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@
//!
//! [`BinaryHeap`]: `crate::binary_heap::BinaryHeap`

use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
use core::ptr;

use crate::storage::{OwnedStorage, Storage, ViewStorage};

/// Trait for defining an index for the linked list, never implemented by users.
pub trait SortedLinkedListIndex: Copy {
#[doc(hidden)]
Expand Down Expand Up @@ -83,17 +86,28 @@ pub struct Node<T, Idx> {
next: Idx,
}

/// The linked list.
pub struct SortedLinkedList<T, Idx, K, const N: usize>
/// Base struct for [`SortedLinkedList`] and [`SortedLinkedListView`], generic over the [`Storage`].
///
/// In most cases you should use [`SortedLinkedList`] or [`SortedLinkedListView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct SortedLinkedListInner<T, Idx, K, S>
where
Idx: SortedLinkedListIndex,
S: Storage,
{
list: [Node<T, Idx>; N],
head: Idx,
free: Idx,
_kind: PhantomData<K>,
list: S::Buffer<Node<T, Idx>>,
}

/// The linked list.
pub type SortedLinkedList<T, Idx, K, const N: usize> =
SortedLinkedListInner<T, Idx, K, OwnedStorage<N>>;

/// The linked list.
pub type SortedLinkedListView<T, Idx, K> = SortedLinkedListInner<T, Idx, K, ViewStorage>;

// Internal macro for generating indexes for the linkedlist and const new for the linked list
macro_rules! impl_index_and_const_new {
($name:ident, $ty:ty, $new_name:ident, $max_val:expr) => {
Expand Down Expand Up @@ -186,19 +200,35 @@ impl_index_and_const_new!(LinkedIndexUsize, usize, new_usize, { usize::MAX - 1 }
impl<T, Idx, K, const N: usize> SortedLinkedList<T, Idx, K, N>
where
Idx: SortedLinkedListIndex,
{
/// Get a reference to the `SortedLinkedList`, erasing the `N` const-generic.
pub fn as_view(&self) -> &SortedLinkedListView<T, Idx, K> {
self
}

/// Get a mutable reference to the `Vec`, erasing the `N` const-generic.
pub fn as_mut_view(&mut self) -> &mut SortedLinkedListView<T, Idx, K> {
self
}
}

impl<T, Idx, K, S> SortedLinkedListInner<T, Idx, K, S>
where
Idx: SortedLinkedListIndex,
S: Storage,
{
/// Internal access helper
#[inline(always)]
fn node_at(&self, index: usize) -> &Node<T, Idx> {
// Safety: The entire `self.list` is initialized in `new`, which makes this safe.
unsafe { self.list.get_unchecked(index) }
unsafe { self.list.borrow().get_unchecked(index) }
}

/// Internal access helper
#[inline(always)]
fn node_at_mut(&mut self, index: usize) -> &mut Node<T, Idx> {
// Safety: The entire `self.list` is initialized in `new`, which makes this safe.
unsafe { self.list.get_unchecked_mut(index) }
unsafe { self.list.borrow_mut().get_unchecked_mut(index) }
}

/// Internal access helper
Expand Down Expand Up @@ -232,11 +262,12 @@ where
}
}

impl<T, Idx, K, const N: usize> SortedLinkedList<T, Idx, K, N>
impl<T, Idx, K, S> SortedLinkedListInner<T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
{
/// Pushes a value onto the list without checking if the list is full.
///
Expand Down Expand Up @@ -335,8 +366,8 @@ where
/// assert_eq!(iter.next(), Some(&1));
/// assert_eq!(iter.next(), None);
/// ```
pub fn iter(&self) -> Iter<'_, T, Idx, K, N> {
Iter {
pub fn iter(&self) -> IterInner<'_, T, Idx, K, S> {
IterInner {
list: self,
index: self.head,
}
Expand Down Expand Up @@ -364,15 +395,15 @@ where
/// assert_eq!(ll.pop(), Ok(1));
/// assert_eq!(ll.pop(), Err(()));
/// ```
pub fn find_mut<F>(&mut self, mut f: F) -> Option<FindMut<'_, T, Idx, K, N>>
pub fn find_mut<F>(&mut self, mut f: F) -> Option<FindMutInner<'_, T, Idx, K, S>>
where
F: FnMut(&T) -> bool,
{
let head = self.head.option()?;

// Special-case, first element
if f(self.read_data_in_node_at(head)) {
return Some(FindMut {
return Some(FindMutInner {
is_head: true,
prev_index: Idx::none(),
index: self.head,
Expand All @@ -385,7 +416,7 @@ where

while let Some(next) = self.node_at(current).next.option() {
if f(self.read_data_in_node_at(next)) {
return Some(FindMut {
return Some(FindMutInner {
is_head: false,
prev_index: unsafe { Idx::new_unchecked(current) },
index: unsafe { Idx::new_unchecked(next) },
Expand Down Expand Up @@ -514,22 +545,32 @@ where
}
}

/// Iterator for the linked list.
pub struct Iter<'a, T, Idx, K, const N: usize>
/// Base struct for [`Iter`] and [`IterView`], generic over the [`Storage`].
///
/// In most cases you should use [`Iter`] or [`IterView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct IterInner<'a, T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
{
list: &'a SortedLinkedList<T, Idx, K, N>,
list: &'a SortedLinkedListInner<T, Idx, K, S>,
index: Idx,
}

impl<'a, T, Idx, K, const N: usize> Iterator for Iter<'a, T, Idx, K, N>
/// Iterator for the linked list.
pub type Iter<'a, T, Idx, K, const N: usize> = IterInner<'a, T, Idx, K, OwnedStorage<N>>;
/// Iterator for the linked list.
pub type IterView<'a, T, Idx, K, const N: usize> = IterInner<'a, T, Idx, K, ViewStorage>;

impl<'a, T, Idx, K, S> Iterator for IterInner<'a, T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
{
type Item = &'a T;

Expand All @@ -543,25 +584,35 @@ where
}
}

/// Comes from [`SortedLinkedList::find_mut`].
pub struct FindMut<'a, T, Idx, K, const N: usize>
/// Base struct for [`FindMut`] and [`FindMutView`], generic over the [`Storage`].
///
/// In most cases you should use [`FindMut`] or [`FindMutView`] directly. Only use this
/// struct if you want to write code that's generic over both.
pub struct FindMutInner<'a, T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
{
list: &'a mut SortedLinkedList<T, Idx, K, N>,
list: &'a mut SortedLinkedListInner<T, Idx, K, S>,
is_head: bool,
prev_index: Idx,
index: Idx,
maybe_changed: bool,
}

impl<'a, T, Idx, K, const N: usize> FindMut<'a, T, Idx, K, N>
/// Comes from [`SortedLinkedList::find_mut`].
pub type FindMut<'a, T, Idx, K, const N: usize> = FindMutInner<'a, T, Idx, K, OwnedStorage<N>>;
/// Comes from [`SortedLinkedList::find_mut`].
pub type FindMutView<'a, T, Idx, K, const N: usize> = FindMutInner<'a, T, Idx, K, ViewStorage>;

impl<'a, T, Idx, K, S> FindMutInner<'a, T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
{
fn pop_internal(&mut self) -> T {
if self.is_head {
Expand Down Expand Up @@ -645,11 +696,12 @@ where
}
}

impl<T, Idx, K, const N: usize> Drop for FindMut<'_, T, Idx, K, N>
impl<T, Idx, K, S> Drop for FindMutInner<'_, T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
{
fn drop(&mut self) {
// Only resort the list if the element has changed
Expand All @@ -660,11 +712,12 @@ where
}
}

impl<T, Idx, K, const N: usize> Deref for FindMut<'_, T, Idx, K, N>
impl<T, Idx, K, S> Deref for FindMutInner<'_, T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
{
type Target = T;

Expand All @@ -674,11 +727,12 @@ where
}
}

impl<T, Idx, K, const N: usize> DerefMut for FindMut<'_, T, Idx, K, N>
impl<T, Idx, K, S> DerefMut for FindMutInner<'_, T, Idx, K, S>
where
T: Ord,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.maybe_changed = true;
Expand Down Expand Up @@ -712,20 +766,22 @@ where
// }
// }

impl<T, Idx, K, const N: usize> fmt::Debug for SortedLinkedList<T, Idx, K, N>
impl<T, Idx, K, S> fmt::Debug for SortedLinkedListInner<T, Idx, K, S>
where
T: Ord + core::fmt::Debug,
Idx: SortedLinkedListIndex,
K: Kind,
S: Storage,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}

impl<T, Idx, K, const N: usize> Drop for SortedLinkedList<T, Idx, K, N>
impl<T, Idx, K, S> Drop for SortedLinkedListInner<T, Idx, K, S>
where
Idx: SortedLinkedListIndex,
S: Storage,
{
fn drop(&mut self) {
let mut index = self.head;
Expand Down

0 comments on commit eb48d9e

Please sign in to comment.