diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bea10baa6..d1ff1b8500 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `VecView`, the `!Sized` version of `Vec`. - Added pool implementations for 64-bit architectures. - Added `IntoIterator` implementation for `LinearMap` +- Added `BinaryHeapView`, the `!Sized` version of `BinaryHeap`. ### Changed diff --git a/src/binary_heap.rs b/src/binary_heap.rs index 8bd740845e..e891bff11d 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -17,7 +17,7 @@ use core::{ ptr, slice, }; -use crate::vec::Vec; +use crate::{vec::Vec, VecView}; /// Min-heap pub enum Min {} @@ -45,9 +45,24 @@ impl Kind for Max { /// Sealed traits mod private { + use core::marker::PhantomData; + pub trait Sealed {} + + ///
This is private API and should not be used
+ pub struct BinaryHeapInner { + pub(crate) _kind: PhantomData, + pub(crate) data: B, + } } +// Workaround https://github.com/rust-lang/rust/issues/119015. This is required so that the methods on `VecView` and `Vec` are properly documented. +// cfg(doc) prevents `VecInner` being part of the public API. +// doc(hidden) prevents the `pub use vec::VecInner` from being visible in the documentation. +#[cfg(doc)] +#[doc(hidden)] +pub use private::BinaryHeapInner as _; + impl private::Sealed for Max {} impl private::Sealed for Min {} @@ -97,10 +112,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 = private::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: BinaryHeap<_, Max, 8> = BinaryHeap::new(); +/// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; +/// +/// // We can use peek to look at the next item in the heap_view. In this case, +/// // there's no items in there yet so we get None. +/// assert_eq!(heap_view.peek(), None); +/// +/// // Let's add some scores... +/// heap_view.push(1).unwrap(); +/// heap_view.push(5).unwrap(); +/// heap_view.push(2).unwrap(); +/// +/// // Now peek shows the most important item in the heap. +/// assert_eq!(heap_view.peek(), Some(&5)); +/// +/// // We can check the length of a heap. +/// assert_eq!(heap_view.len(), 3); +/// +/// // We can iterate over the items in the heap, although they are returned in +/// // a random order. +/// for x in &*heap_view { +/// println!("{}", x); +/// } +/// +/// // If we instead pop these scores, they should come back in order. +/// assert_eq!(heap_view.pop(), Some(5)); +/// assert_eq!(heap_view.pop(), Some(2)); +/// assert_eq!(heap_view.pop(), Some(1)); +/// assert_eq!(heap_view.pop(), None); +/// +/// // We can clear the heap of any remaining items. +/// heap_view.clear(); +/// +/// // The heap_view should now be empty. +/// assert!(heap_view.is_empty()) +/// ``` +pub type BinaryHeapView = private::BinaryHeapInner>; impl BinaryHeap { /* Constructors */ @@ -122,6 +183,48 @@ impl BinaryHeap { data: Vec::new(), } } + + /// Get a reference to the `BinaryHeap`, erasing the `N` const-generic + /// + /// ``` + /// # use heapless::{BinaryHeap, BinaryHeapView, binary_heap::Max}; + /// + /// let heap: BinaryHeap = BinaryHeap::new(); + /// let heap_view: &BinaryHeapView<_, _> = heap.as_view(); + /// ```` + /// + /// It is often preferable to do the same through type coerction, since `BinaryHeap` implements `Unsize>`: + /// + /// ```rust + /// # use heapless::{BinaryHeap, BinaryHeapView, binary_heap::Max}; + /// + /// let heap: BinaryHeap = BinaryHeap::new(); + /// let heap_view: &BinaryHeapView<_, _> = &heap; + /// ``` + pub fn as_view(&self) -> &BinaryHeapView { + self + } + + /// Get a mutable reference to the `BinaryHeap`, erasing the `N` const-generic + /// + /// ``` + /// # use heapless::{BinaryHeap, BinaryHeapView, binary_heap::Max}; + /// + /// let mut heap: BinaryHeap = BinaryHeap::new(); + /// let heap_view: &mut BinaryHeapView<_, _> = heap.as_mut_view(); + /// ```` + /// + /// It is often preferable to do the same through type coerction, since `BinaryHeap` implements `Unsize>`: + /// + /// ```rust + /// # use heapless::{BinaryHeap, BinaryHeapView, binary_heap::Max}; + /// + /// let mut heap: BinaryHeap = BinaryHeap::new(); + /// let heap_view: &mut BinaryHeapView<_, _> = &mut heap; + /// ``` + pub fn as_mut_view(&mut self) -> &mut BinaryHeapView { + self + } } impl BinaryHeap @@ -132,7 +235,7 @@ where /* Public API */ /// Returns the capacity of the binary heap. pub fn capacity(&self) -> usize { - self.data.capacity() + self.as_view().capacity() } /// Drops all items from the binary heap. @@ -151,7 +254,7 @@ where /// assert!(heap.is_empty()); /// ``` pub fn clear(&mut self) { - self.data.clear() + self.as_mut_view().clear() } /// Returns the length of the binary heap. @@ -166,7 +269,7 @@ where /// assert_eq!(heap.len(), 2); /// ``` pub fn len(&self) -> usize { - self.data.len() + self.as_view().len() } /// Checks if the binary heap is empty. @@ -185,7 +288,7 @@ where /// assert!(!heap.is_empty()); /// ``` pub fn is_empty(&self) -> bool { - self.len() == 0 + self.as_view().is_empty() } /// Returns an iterator visiting all values in the underlying vector, in arbitrary order. @@ -205,7 +308,7 @@ where /// } /// ``` pub fn iter(&self) -> slice::Iter<'_, T> { - self.data.as_slice().iter() + self.as_view().iter() } /// Returns a mutable iterator visiting all values in the underlying vector, in arbitrary order. @@ -213,7 +316,7 @@ where /// **WARNING** Mutating the items in the binary heap can leave the heap in an inconsistent /// state. pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> { - self.data.as_mut_slice().iter_mut() + self.as_mut_view().iter_mut() } /// Returns the *top* (greatest if max-heap, smallest if min-heap) item in the binary heap, or @@ -231,7 +334,7 @@ where /// assert_eq!(heap.peek(), Some(&5)); /// ``` pub fn peek(&self) -> Option<&T> { - self.data.as_slice().first() + self.as_view().peek() } /// Returns a mutable reference to the greatest item in the binary heap, or @@ -261,6 +364,7 @@ where /// assert_eq!(heap.peek(), Some(&2)); /// ``` pub fn peek_mut(&mut self) -> Option> { + // FIXME: return a PeekMutView. Require breaking change if self.is_empty() { None } else { @@ -285,6 +389,220 @@ where /// assert_eq!(heap.pop(), Some(1)); /// assert_eq!(heap.pop(), None); /// ``` + pub fn pop(&mut self) -> Option { + self.as_mut_view().pop() + } + + /// Removes the *top* (greatest if max-heap, smallest if min-heap) item from the binary heap and + /// returns it, without checking if the binary heap is empty. + #[allow(clippy::missing_safety_doc)] // TODO + pub unsafe fn pop_unchecked(&mut self) -> T { + self.as_mut_view().pop_unchecked() + } + + /// Pushes an item onto the binary heap. + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// heap.push(3).unwrap(); + /// heap.push(5).unwrap(); + /// heap.push(1).unwrap(); + /// + /// assert_eq!(heap.len(), 3); + /// assert_eq!(heap.peek(), Some(&5)); + /// ``` + pub fn push(&mut self, item: T) -> Result<(), T> { + self.as_mut_view().push(item) + } + + /// Pushes an item onto the binary heap without first checking if it's full. + #[allow(clippy::missing_safety_doc)] // TODO + pub unsafe fn push_unchecked(&mut self, item: T) { + self.as_mut_view().push_unchecked(item) + } + + /// 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, pos: usize) { + self.as_mut_view().sift_down_to_bottom(pos) + } +} + +impl BinaryHeapView +where + T: Ord, + K: Kind, +{ + /* Public API */ + /// Returns the capacity of the binary heap. + pub fn capacity(&self) -> usize { + self.data.capacity() + } + + /// Drops all items from the binary heap. + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// + /// heap_view.push(1).unwrap(); + /// heap_view.push(3).unwrap(); + /// + /// assert!(!heap_view.is_empty()); + /// + /// heap_view.clear(); + /// + /// assert!(heap_view.is_empty()); + /// ``` + pub fn clear(&mut self) { + self.data.clear() + } + + /// Returns the length of the binary heap. + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// heap_view.push(1).unwrap(); + /// heap_view.push(3).unwrap(); + /// + /// assert_eq!(heap_view.len(), 2); + /// ``` + pub fn len(&self) -> usize { + self.data.len() + } + + /// Checks if the binary heap is empty. + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// + /// assert!(heap_view.is_empty()); + /// + /// heap_view.push(3).unwrap(); + /// heap_view.push(5).unwrap(); + /// heap_view.push(1).unwrap(); + /// + /// assert!(!heap_view.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an iterator visiting all values in the underlying vector, in arbitrary order. + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// heap_view.push(1).unwrap(); + /// heap_view.push(2).unwrap(); + /// heap_view.push(3).unwrap(); + /// heap_view.push(4).unwrap(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order + /// for x in heap_view.iter() { + /// println!("{}", x); + /// } + /// ``` + pub fn iter(&self) -> slice::Iter<'_, T> { + self.data.as_slice().iter() + } + + /// Returns a mutable iterator visiting all values in the underlying vector, in arbitrary order. + /// + /// **WARNING** Mutating the items in the binary heap can leave the heap in an inconsistent + /// state. + pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> { + self.data.as_mut_slice().iter_mut() + } + + /// Returns the *top* (greatest if max-heap, smallest if min-heap) item in the binary heap, or + /// None if it is empty. + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// assert_eq!(heap_view.peek(), None); + /// + /// heap_view.push(1).unwrap(); + /// heap_view.push(5).unwrap(); + /// heap_view.push(2).unwrap(); + /// assert_eq!(heap_view.peek(), Some(&5)); + /// ``` + pub fn peek(&self) -> Option<&T> { + self.data.as_slice().first() + } + + /// Returns a mutable reference to the greatest item in the binary heap, or + /// `None` if it is empty. + /// + /// Note: If the `PeekMut` value is leaked, the heap may be in an + /// inconsistent state. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// assert!(heap_view.peek_mut().is_none()); + /// + /// heap_view.push(1); + /// heap_view.push(5); + /// heap_view.push(2); + /// { + /// let mut val = heap_view.peek_mut().unwrap(); + /// *val = 0; + /// } + /// + /// assert_eq!(heap_view.peek(), Some(&2)); + /// ``` + pub fn peek_mut(&mut self) -> Option> { + if self.is_empty() { + None + } else { + Some(PeekMutView { + heap: self, + sift: true, + }) + } + } + + /// Removes the *top* (greatest if max-heap, smallest if min-heap) item from the binary heap and + /// returns it, or None if it is empty. + /// + /// ``` + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; + /// + /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// heap_view.push(1).unwrap(); + /// heap_view.push(3).unwrap(); + /// + /// assert_eq!(heap_view.pop(), Some(3)); + /// assert_eq!(heap_view.pop(), Some(1)); + /// assert_eq!(heap_view.pop(), None); + /// ``` pub fn pop(&mut self) -> Option { if self.is_empty() { None @@ -309,15 +627,16 @@ where /// Pushes an item onto the binary heap. /// /// ``` - /// use heapless::binary_heap::{BinaryHeap, Max}; + /// use heapless::binary_heap::{BinaryHeap, BinaryHeapView, Max}; /// /// let mut heap: BinaryHeap<_, Max, 8> = BinaryHeap::new(); - /// heap.push(3).unwrap(); - /// heap.push(5).unwrap(); - /// heap.push(1).unwrap(); + /// let heap_view: &mut BinaryHeapView<_, Max> = &mut heap; + /// heap_view.push(3).unwrap(); + /// heap_view.push(5).unwrap(); + /// heap_view.push(1).unwrap(); /// - /// assert_eq!(heap.len(), 3); - /// assert_eq!(heap.peek(), Some(&5)); + /// assert_eq!(heap_view.len(), 3); + /// assert_eq!(heap_view.peek(), Some(&5)); /// ``` pub fn push(&mut self, item: T) -> Result<(), T> { if self.data.is_full() { @@ -336,11 +655,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(); @@ -505,6 +819,70 @@ where } } +/// 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 struct PeekMutView<'a, T, K> +where + T: Ord, + K: Kind, +{ + heap: &'a mut BinaryHeapView, + sift: bool, +} + +impl Drop for PeekMutView<'_, T, K> +where + T: Ord, + K: Kind, +{ + fn drop(&mut self) { + if self.sift { + self.heap.sift_down_to_bottom(0); + } + } +} + +impl Deref for PeekMutView<'_, T, K> +where + T: Ord, + K: Kind, +{ + type Target = T; + fn deref(&self) -> &T { + debug_assert!(!self.heap.is_empty()); + // SAFE: PeekMut is only instantiated for non-empty heaps + unsafe { self.heap.data.as_slice().get_unchecked(0) } + } +} + +impl DerefMut for PeekMutView<'_, T, K> +where + T: Ord, + K: Kind, +{ + fn deref_mut(&mut self) -> &mut T { + debug_assert!(!self.heap.is_empty()); + // SAFE: PeekMut is only instantiated for non-empty heaps + unsafe { self.heap.data.as_mut_slice().get_unchecked_mut(0) } + } +} + +impl<'a, T, K> PeekMutView<'a, T, K> +where + T: Ord, + K: Kind, +{ + /// Removes the peeked value from the heap and returns it. + pub fn pop(mut this: PeekMutView<'a, T, K>) -> T { + let value = this.heap.pop().unwrap(); + this.sift = false; + value + } +} + impl<'a, T> Drop for Hole<'a, T> { #[inline] fn drop(&mut self) { @@ -540,6 +918,16 @@ where } impl fmt::Debug for BinaryHeap +where + K: Kind, + T: Ord + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_view().fmt(f) + } +} + +impl fmt::Debug for BinaryHeapView where K: Kind, T: Ord + fmt::Debug, @@ -557,6 +945,19 @@ where type Item = &'a T; type IntoIter = slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + self.as_view().into_iter() + } +} + +impl<'a, T, K> IntoIterator for &'a BinaryHeapView +where + K: Kind, + T: Ord, +{ + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { self.iter() } diff --git a/src/lib.rs b/src/lib.rs index b5238c672c..67c18af948 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,7 +85,7 @@ feature(integer_atomics) )] -pub use binary_heap::BinaryHeap; +pub use binary_heap::{BinaryHeap, BinaryHeapView}; pub use deque::Deque; pub use histbuf::{HistoryBuffer, OldestOrdered}; pub use indexmap::{ diff --git a/src/ser.rs b/src/ser.rs index f929ba8b12..6b14728601 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,14 +1,27 @@ use core::hash::{BuildHasher, Hash}; use crate::{ - binary_heap::Kind as BinaryHeapKind, BinaryHeap, Deque, IndexMap, IndexSet, LinearMap, String, - Vec, + binary_heap::Kind as BinaryHeapKind, BinaryHeap, BinaryHeapView, Deque, IndexMap, IndexSet, + LinearMap, String, Vec, }; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; // Sequential containers impl Serialize for BinaryHeap +where + T: Ord + Serialize, + KIND: BinaryHeapKind, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_view().serialize(serializer) + } +} + +impl Serialize for BinaryHeapView where T: Ord + Serialize, KIND: BinaryHeapKind,