Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SortedLinkedList: add SortedLinkedListView, similar to VecView on top of #486 #497

Merged
merged 1 commit into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `HistoryBufferView`, the `!Sized` version of `HistoryBuffer`.
- Added `DequeView`, the `!Sized` version of `Deque`.
- Added `QueueView`, the `!Sized` version of `Queue`.
- 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
Loading