From f9bf0a31914754342f07b2a7e46649371648e019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 1 Jul 2024 16:59:13 +0200 Subject: [PATCH] SortedLinkedList: add SortedLinkedListView, similar to VecView on top of #486 --- CHANGELOG.md | 1 + src/sorted_linked_list.rs | 104 +++++++++++++++++++++++++++++--------- 2 files changed, 81 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 500c43622f..0d4656c264 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/sorted_linked_list.rs b/src/sorted_linked_list.rs index 64bcdd6bf0..a3c9cb502f 100644 --- a/src/sorted_linked_list.rs +++ b/src/sorted_linked_list.rs @@ -26,6 +26,7 @@ //! //! [`BinaryHeap`]: `crate::binary_heap::BinaryHeap` +use core::borrow::{Borrow, BorrowMut}; use core::cmp::Ordering; use core::fmt; use core::marker::PhantomData; @@ -33,6 +34,8 @@ 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)] @@ -83,17 +86,28 @@ pub struct Node { next: Idx, } -/// The linked list. -pub struct SortedLinkedList +/// 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 where Idx: SortedLinkedListIndex, + S: Storage, { - list: [Node; N], head: Idx, free: Idx, _kind: PhantomData, + list: S::Buffer>, } +/// The linked list. +pub type SortedLinkedList = + SortedLinkedListInner>; + +/// The linked list. +pub type SortedLinkedListView = SortedLinkedListInner; + // 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) => { @@ -186,19 +200,35 @@ impl_index_and_const_new!(LinkedIndexUsize, usize, new_usize, { usize::MAX - 1 } impl SortedLinkedList where Idx: SortedLinkedListIndex, +{ + /// Get a reference to the `SortedLinkedList`, erasing the `N` const-generic. + pub fn as_view(&self) -> &SortedLinkedListView { + self + } + + /// Get a mutable reference to the `Vec`, erasing the `N` const-generic. + pub fn as_mut_view(&mut self) -> &mut SortedLinkedListView { + self + } +} + +impl SortedLinkedListInner +where + Idx: SortedLinkedListIndex, + S: Storage, { /// Internal access helper #[inline(always)] fn node_at(&self, index: usize) -> &Node { // 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 { // 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 @@ -232,11 +262,12 @@ where } } -impl SortedLinkedList +impl SortedLinkedListInner where T: Ord, Idx: SortedLinkedListIndex, K: Kind, + S: Storage, { /// Pushes a value onto the list without checking if the list is full. /// @@ -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, } @@ -364,7 +395,7 @@ where /// assert_eq!(ll.pop(), Ok(1)); /// assert_eq!(ll.pop(), Err(())); /// ``` - pub fn find_mut(&mut self, mut f: F) -> Option> + pub fn find_mut(&mut self, mut f: F) -> Option> where F: FnMut(&T) -> bool, { @@ -372,7 +403,7 @@ where // 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, @@ -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) }, @@ -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, + list: &'a SortedLinkedListInner, 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>; +/// 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; @@ -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, + list: &'a mut SortedLinkedListInner, 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>; +/// 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 { @@ -645,11 +696,12 @@ where } } -impl Drop for FindMut<'_, T, Idx, K, N> +impl 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 @@ -660,11 +712,12 @@ where } } -impl Deref for FindMut<'_, T, Idx, K, N> +impl Deref for FindMutInner<'_, T, Idx, K, S> where T: Ord, Idx: SortedLinkedListIndex, K: Kind, + S: Storage, { type Target = T; @@ -674,11 +727,12 @@ where } } -impl DerefMut for FindMut<'_, T, Idx, K, N> +impl 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; @@ -712,20 +766,22 @@ where // } // } -impl fmt::Debug for SortedLinkedList +impl fmt::Debug for SortedLinkedListInner 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 Drop for SortedLinkedList +impl Drop for SortedLinkedListInner where Idx: SortedLinkedListIndex, + S: Storage, { fn drop(&mut self) { let mut index = self.head;