From a809731f848cf0282d02d229fc08ba9d9605f6de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 1 Jul 2024 15:21:46 +0200 Subject: [PATCH] BinaryHeap: implement BinaryHeapView on top of #486 --- CHANGELOG.md | 1 + src/binary_heap.rs | 136 +++++++++++++++++++++++++++++++++++++-------- src/ser.rs | 15 +++-- 3 files changed, 124 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21e7f6aad4..7f876adbf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Implemented `DoubleEndedIterator` for `OldestOrdered`. - Added std `Entry` methods to indexmap `Entry`. - Added `StringView`, the `!Sized` version of `String`. +- Added `BinaryHeapView`, the `!Sized` version of `BinaryHeap`. - Added `MpMcQueueView`, the `!Sized` version of `MpMcQueue`. - Added `LinearMapView`, the `!Sized` version of `LinearMap`. diff --git a/src/binary_heap.rs b/src/binary_heap.rs index 8bd740845e..e137bdd67d 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -17,7 +17,10 @@ use core::{ ptr, slice, }; -use crate::vec::Vec; +use crate::{ + storage::{OwnedStorage, Storage, ViewStorage}, + vec::{Vec, VecInner}, +}; /// Min-heap pub enum Min {} @@ -51,6 +54,15 @@ mod private { impl private::Sealed for Max {} impl private::Sealed for Min {} +/// Base struct for [`BinaryHeap`] and [`BinaryHeapView`], generic over the [`Storage`]. +/// +/// In most cases you should use [`BinaryHeap`] or [`BinaryHeapView`] directly. Only use this +/// struct if you want to write code that's generic over both. +pub struct BinaryHeapInner { + pub(crate) _kind: PhantomData, + pub(crate) data: VecInner, +} + /// A priority queue implemented with a binary heap. /// /// This can be either a min-heap or a max-heap. @@ -97,10 +109,56 @@ impl private::Sealed for Min {} /// // The heap should now be empty. /// assert!(heap.is_empty()) /// ``` -pub struct BinaryHeap { - pub(crate) _kind: PhantomData, - pub(crate) data: Vec, -} +pub type BinaryHeap = BinaryHeapInner>; + +/// A priority queue implemented with a binary heap. +/// +/// This can be either a min-heap or a max-heap. +/// +/// It is a logic error for an item to be modified in such a way that the item's ordering relative +/// to any other item, as determined by the `Ord` trait, changes while it is in the heap. This is +/// normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe code. +/// +/// ``` +/// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; +/// +/// let mut heap_buffer: BinaryHeap<_, Max, 8> = BinaryHeap::new(); +/// let heap: &mut BinaryHeapView<_, Max> = &mut heap_buffer; +/// +/// // We can use peek to look at the next item in the heap. In this case, +/// // there's no items in there yet so we get None. +/// assert_eq!(heap.peek(), None); +/// +/// // Let's add some scores... +/// heap.push(1).unwrap(); +/// heap.push(5).unwrap(); +/// heap.push(2).unwrap(); +/// +/// // Now peek shows the most important item in the heap. +/// assert_eq!(heap.peek(), Some(&5)); +/// +/// // We can check the length of a heap. +/// assert_eq!(heap.len(), 3); +/// +/// // We can iterate over the items in the heap, although they are returned in +/// // a random order. +/// for x in &*heap { +/// println!("{}", x); +/// } +/// +/// // If we instead pop these scores, they should come back in order. +/// assert_eq!(heap.pop(), Some(5)); +/// assert_eq!(heap.pop(), Some(2)); +/// assert_eq!(heap.pop(), Some(1)); +/// assert_eq!(heap.pop(), None); +/// +/// // We can clear the heap of any remaining items. +/// heap.clear(); +/// +/// // The heap should now be empty. +/// assert!(heap.is_empty()) +/// ``` +pub type BinaryHeapView = BinaryHeapInner; impl BinaryHeap { /* Constructors */ @@ -124,7 +182,23 @@ impl BinaryHeap { } } -impl BinaryHeap +impl BinaryHeap { + /// Returns the underlying `Vec`. Order is arbitrary and time is *O*(1). + pub fn into_vec(self) -> Vec { + self.data + } + + /// Get a reference to the `BinaryHeap`, erasing the `N` const-generic. + pub fn as_view(&self) -> &BinaryHeapView { + self + } + /// Get a mutable reference to the `BinaryHeap`, erasing the `N` const-generic. + pub fn as_mut_view(&mut self) -> &mut BinaryHeapView { + self + } +} + +impl BinaryHeapInner where T: Ord, K: Kind, @@ -260,11 +334,11 @@ where /// /// assert_eq!(heap.peek(), Some(&2)); /// ``` - pub fn peek_mut(&mut self) -> Option> { + pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { None } else { - Some(PeekMut { + Some(PeekMutInner { heap: self, sift: true, }) @@ -336,11 +410,6 @@ where self.sift_up(0, old_len); } - /// Returns the underlying `Vec`. Order is arbitrary and time is *O*(1). - pub fn into_vec(self) -> Vec { - self.data - } - /* Private API */ fn sift_down_to_bottom(&mut self, mut pos: usize) { let end = self.len(); @@ -444,21 +513,37 @@ impl<'a, T> Hole<'a, T> { /// Structure wrapping a mutable reference to the greatest item on a /// `BinaryHeap`. /// -/// This `struct` is created by [`BinaryHeap::peek_mut`]. +/// This `struct` is created by [`BinaryHeapInner::peek_mut`]. /// See its documentation for more. -pub struct PeekMut<'a, T, K, const N: usize> +pub struct PeekMutInner<'a, T, K, S> where T: Ord, K: Kind, + S: Storage, { - heap: &'a mut BinaryHeap, + heap: &'a mut BinaryHeapInner, sift: bool, } -impl Drop for PeekMut<'_, T, K, N> +/// Structure wrapping a mutable reference to the greatest item on a +/// `BinaryHeap`. +/// +/// This `struct` is created by [`BinaryHeap::peek_mut`]. +/// See its documentation for more. +pub type PeekMut<'a, T, K, const N: usize> = PeekMutInner<'a, T, K, OwnedStorage>; + +/// Structure wrapping a mutable reference to the greatest item on a +/// `BinaryHeap`. +/// +/// This `struct` is created by [`BinaryHeapView::peek_mut`]. +/// See its documentation for more. +pub type PeekMutView<'a, T, K> = PeekMutInner<'a, T, K, ViewStorage>; + +impl Drop for PeekMutInner<'_, T, K, S> where T: Ord, K: Kind, + S: Storage, { fn drop(&mut self) { if self.sift { @@ -467,10 +552,11 @@ where } } -impl Deref for PeekMut<'_, T, K, N> +impl Deref for PeekMutInner<'_, T, K, S> where T: Ord, K: Kind, + S: Storage, { type Target = T; fn deref(&self) -> &T { @@ -480,10 +566,11 @@ where } } -impl DerefMut for PeekMut<'_, T, K, N> +impl DerefMut for PeekMutInner<'_, T, K, S> where T: Ord, K: Kind, + S: Storage, { fn deref_mut(&mut self) -> &mut T { debug_assert!(!self.heap.is_empty()); @@ -492,13 +579,14 @@ where } } -impl<'a, T, K, const N: usize> PeekMut<'a, T, K, N> +impl<'a, T, K, S> PeekMutInner<'a, T, K, S> where T: Ord, K: Kind, + S: Storage, { /// Removes the peeked value from the heap and returns it. - pub fn pop(mut this: PeekMut<'a, T, K, N>) -> T { + pub fn pop(mut this: PeekMutInner<'a, T, K, S>) -> T { let value = this.heap.pop().unwrap(); this.sift = false; value @@ -539,20 +627,22 @@ where } } -impl fmt::Debug for BinaryHeap +impl fmt::Debug for BinaryHeapInner where K: Kind, T: Ord + fmt::Debug, + S: Storage, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } -impl<'a, T, K, const N: usize> IntoIterator for &'a BinaryHeap +impl<'a, T, K, S> IntoIterator for &'a BinaryHeapInner where K: Kind, T: Ord, + S: Storage, { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; diff --git a/src/ser.rs b/src/ser.rs index 52064a1c78..a60854324c 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,21 +1,26 @@ use core::hash::{BuildHasher, Hash}; use crate::{ - binary_heap::Kind as BinaryHeapKind, linear_map::LinearMapInner, storage::Storage, - string::StringInner, vec::VecInner, BinaryHeap, Deque, HistoryBuffer, IndexMap, IndexSet, + binary_heap::{BinaryHeapInner, Kind as BinaryHeapKind}, + linear_map::LinearMapInner, + storage::Storage, + string::StringInner, + vec::VecInner, + Deque, HistoryBuffer, IndexMap, IndexSet, }; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; // Sequential containers -impl Serialize for BinaryHeap +impl Serialize for BinaryHeapInner where T: Ord + Serialize, KIND: BinaryHeapKind, + S: Storage, { - fn serialize(&self, serializer: S) -> Result + fn serialize(&self, serializer: SER) -> Result where - S: Serializer, + SER: Serializer, { let mut seq = serializer.serialize_seq(Some(self.len()))?; for element in self {