From f876f114c9c3e25a5affa8d21bdf0eaa007ccc51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 1 Jul 2024 11:38:52 +0200 Subject: [PATCH 1/3] Implement DequeView on top of #486 --- src/deque.rs | 496 ++++++++++++++++++++++++++++++--------------------- src/lib.rs | 2 +- 2 files changed, 289 insertions(+), 209 deletions(-) diff --git a/src/deque.rs b/src/deque.rs index b596086dfb..5f09756f75 100644 --- a/src/deque.rs +++ b/src/deque.rs @@ -1,9 +1,62 @@ +//! A fixed capacity double-ended queue. +//! +//! # Examples +//! +//! ``` +//! use heapless::Deque; +//! +//! // A deque with a fixed capacity of 8 elements allocated on the stack +//! let mut deque = Deque::<_, 8>::new(); +//! +//! // You can use it as a good old FIFO queue. +//! deque.push_back(1); +//! deque.push_back(2); +//! assert_eq!(deque.len(), 2); +//! +//! assert_eq!(deque.pop_front(), Some(1)); +//! assert_eq!(deque.pop_front(), Some(2)); +//! assert_eq!(deque.len(), 0); +//! +//! // Deque is double-ended, you can push and pop from the front and back. +//! deque.push_back(1); +//! deque.push_front(2); +//! deque.push_back(3); +//! deque.push_front(4); +//! assert_eq!(deque.pop_front(), Some(4)); +//! assert_eq!(deque.pop_front(), Some(2)); +//! assert_eq!(deque.pop_front(), Some(1)); +//! assert_eq!(deque.pop_front(), Some(3)); +//! +//! // You can iterate it, yielding all the elements front-to-back. +//! for x in &deque { +//! println!("{}", x); +//! } +//! ``` + +use core::borrow::{Borrow, BorrowMut}; use core::fmt; use core::iter::FusedIterator; -use core::marker::PhantomData; use core::mem::MaybeUninit; use core::{ptr, slice}; +use crate::storage::{OwnedStorage, Storage, ViewStorage}; + +/// Base struct for [`Deque`] and [`Deque`], generic over the [`Storage`]. +/// +/// In most cases you should use [`Deque`] or [`Deque`] directly. Only use this +/// struct if you want to write code that's generic over both. +pub struct DequeInner { + /// Front index. Always 0..=(N-1) + front: usize, + /// Back index. Always 0..=(N-1). + back: usize, + + /// Used to distinguish "empty" and "full" cases when `front == back`. + /// May only be `true` if `front == back`, always `false` otherwise. + full: bool, + buffer: S::Buffer>, +} + /// A fixed capacity double-ended queue. /// /// # Examples @@ -38,18 +91,46 @@ use core::{ptr, slice}; /// println!("{}", x); /// } /// ``` -pub struct Deque { - buffer: [MaybeUninit; N], - - /// Front index. Always 0..=(N-1) - front: usize, - /// Back index. Always 0..=(N-1). - back: usize, +pub type Deque = DequeInner>; - /// Used to distinguish "empty" and "full" cases when `front == back`. - /// May only be `true` if `front == back`, always `false` otherwise. - full: bool, -} +/// A double-ended queue with dynamic capacity. +/// +/// # Examples +/// +/// ``` +/// use heapless::deque::{Deque, DequeView}; +/// +/// // A deque with a fixed capacity of 8 elements allocated on the stack +/// let mut deque_buf = Deque::<_, 8>::new(); +/// +/// // A DequeView can be obtained through unsized coercion of a `Deque` +/// let deque: &mut DequeView<_> = &mut deque_buf; +/// +/// // You can use it as a good old FIFO queue. +/// deque.push_back(1); +/// deque.push_back(2); +/// assert_eq!(deque.storage_len(), 2); +/// +/// assert_eq!(deque.pop_front(), Some(1)); +/// assert_eq!(deque.pop_front(), Some(2)); +/// assert_eq!(deque.storage_len(), 0); +/// +/// // DequeView is double-ended, you can push and pop from the front and back. +/// deque.push_back(1); +/// deque.push_front(2); +/// deque.push_back(3); +/// deque.push_front(4); +/// assert_eq!(deque.pop_front(), Some(4)); +/// assert_eq!(deque.pop_front(), Some(2)); +/// assert_eq!(deque.pop_front(), Some(1)); +/// assert_eq!(deque.pop_front(), Some(3)); +/// +/// // You can iterate it, yielding all the elements front-to-back. +/// for x in deque { +/// println!("{}", x); +/// } +/// ``` +pub type DequeView = DequeInner; impl Deque { const INIT: MaybeUninit = MaybeUninit::uninit(); @@ -79,33 +160,65 @@ impl Deque { } } - fn increment(i: usize) -> usize { - if i + 1 == N { + /// Returns the maximum number of elements the deque can hold. + /// + /// This method is not available on a `DequeView`, use [`storage_len`](DequeInner::storage_capacity) instead + pub const fn capacity(&self) -> usize { + N + } + + /// Returns the number of elements currently in the deque. + /// + /// This method is not available on a `DequeView`, use [`storage_len`](DequeInner::storage_len) instead + pub const fn len(&self) -> usize { + if self.full { + N + } else if self.back < self.front { + self.back + N - self.front + } else { + self.back - self.front + } + } + + /// Get a reference to the `Deque`, erasing the `N` const-generic. + pub fn as_view(&self) -> &DequeView { + self + } + + /// Get a mutable reference to the `Deque`, erasing the `N` const-generic. + pub fn as_mut_view(&mut self) -> &mut DequeView { + self + } +} + +impl DequeInner { + /// Returns the maximum number of elements the deque can hold. + pub fn storage_capacity(&self) -> usize { + self.buffer.borrow().len() + } + + fn increment(&self, i: usize) -> usize { + if i + 1 == self.storage_capacity() { 0 } else { i + 1 } } - fn decrement(i: usize) -> usize { + fn decrement(&self, i: usize) -> usize { if i == 0 { - N - 1 + self.storage_capacity() - 1 } else { i - 1 } } - /// Returns the maximum number of elements the deque can hold. - pub const fn capacity(&self) -> usize { - N - } - /// Returns the number of elements currently in the deque. - pub const fn len(&self) -> usize { + pub fn storage_len(&self) -> usize { if self.full { - N + self.storage_capacity() } else if self.back < self.front { - self.back + N - self.front + self.back + self.storage_capacity() - self.front } else { self.back - self.front } @@ -149,15 +262,15 @@ impl Deque { } else if self.back <= self.front { ( slice::from_raw_parts( - self.buffer.as_ptr().add(self.front) as *const T, - N - self.front, + self.buffer.borrow().as_ptr().add(self.front) as *const T, + self.storage_capacity() - self.front, ), - slice::from_raw_parts(self.buffer.as_ptr() as *const T, self.back), + slice::from_raw_parts(self.buffer.borrow().as_ptr() as *const T, self.back), ) } else { ( slice::from_raw_parts( - self.buffer.as_ptr().add(self.front) as *const T, + self.buffer.borrow().as_ptr().add(self.front) as *const T, self.back - self.front, ), &[], @@ -168,7 +281,7 @@ impl Deque { /// Returns a pair of mutable slices which contain, in order, the contents of the `Deque`. pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { - let ptr = self.buffer.as_mut_ptr(); + let ptr = self.buffer.borrow_mut().as_mut_ptr(); // NOTE(unsafe) avoid bound checks in the slicing operation unsafe { @@ -176,7 +289,10 @@ impl Deque { (&mut [], &mut []) } else if self.back <= self.front { ( - slice::from_raw_parts_mut(ptr.add(self.front) as *mut T, N - self.front), + slice::from_raw_parts_mut( + ptr.add(self.front) as *mut T, + self.storage_capacity() - self.front, + ), slice::from_raw_parts_mut(ptr as *mut T, self.back), ) } else { @@ -193,7 +309,7 @@ impl Deque { #[inline] fn is_contiguous(&self) -> bool { - self.front <= N - self.len() + self.front <= self.storage_capacity() - self.storage_len() } /// Rearranges the internal storage of the [`Deque`] to make it into a contiguous slice, @@ -230,18 +346,18 @@ impl Deque { if self.is_contiguous() { return unsafe { slice::from_raw_parts_mut( - self.buffer.as_mut_ptr().add(self.front).cast(), - self.len(), + self.buffer.borrow_mut().as_mut_ptr().add(self.front).cast(), + self.storage_len(), ) }; } - let buffer_ptr: *mut T = self.buffer.as_mut_ptr().cast(); + let buffer_ptr: *mut T = self.buffer.borrow_mut().as_mut_ptr().cast(); - let len = self.len(); + let len = self.storage_len(); - let free = N - len; - let front_len = N - self.front; + let free = self.storage_capacity() - len; + let front_len = self.storage_capacity() - self.front; let back = len - front_len; let back_len = back; @@ -320,7 +436,10 @@ impl Deque { // We just copied the tail right next to the head slice, // so all of the elements in the range are initialized - let slice: &mut [T] = slice::from_raw_parts_mut(buffer_ptr.add(free), N - free); + let slice: &mut [T] = slice::from_raw_parts_mut( + buffer_ptr.add(free), + self.storage_capacity() - free, + ); // because the deque wasn't contiguous, we know that `tail_len < self.len == slice.len()`, // so this will never panic. @@ -373,7 +492,7 @@ impl Deque { if self.is_empty() { None } else { - Some(unsafe { &*self.buffer.get_unchecked(self.front).as_ptr() }) + Some(unsafe { &*self.buffer.borrow().get_unchecked(self.front).as_ptr() }) } } @@ -382,7 +501,13 @@ impl Deque { if self.is_empty() { None } else { - Some(unsafe { &mut *self.buffer.get_unchecked_mut(self.front).as_mut_ptr() }) + Some(unsafe { + &mut *self + .buffer + .borrow_mut() + .get_unchecked_mut(self.front) + .as_mut_ptr() + }) } } @@ -391,8 +516,8 @@ impl Deque { if self.is_empty() { None } else { - let index = Self::decrement(self.back); - Some(unsafe { &*self.buffer.get_unchecked(index).as_ptr() }) + let index = self.decrement(self.back); + Some(unsafe { &*self.buffer.borrow().get_unchecked(index).as_ptr() }) } } @@ -401,8 +526,14 @@ impl Deque { if self.is_empty() { None } else { - let index = Self::decrement(self.back); - Some(unsafe { &mut *self.buffer.get_unchecked_mut(index).as_mut_ptr() }) + let index = self.decrement(self.back); + Some(unsafe { + &mut *self + .buffer + .borrow_mut() + .get_unchecked_mut(index) + .as_mut_ptr() + }) } } @@ -459,8 +590,12 @@ impl Deque { let index = self.front; self.full = false; - self.front = Self::increment(self.front); - self.buffer.get_unchecked_mut(index).as_ptr().read() + self.front = self.increment(self.front); + self.buffer + .borrow_mut() + .get_unchecked_mut(index) + .as_ptr() + .read() } /// Removes an item from the back of the deque and returns it, without checking that the deque @@ -473,8 +608,12 @@ impl Deque { debug_assert!(!self.is_empty()); self.full = false; - self.back = Self::decrement(self.back); - self.buffer.get_unchecked_mut(self.back).as_ptr().read() + self.back = self.decrement(self.back); + self.buffer + .borrow_mut() + .get_unchecked_mut(self.back) + .as_ptr() + .read() } /// Appends an `item` to the front of the deque @@ -485,10 +624,10 @@ impl Deque { pub unsafe fn push_front_unchecked(&mut self, item: T) { debug_assert!(!self.is_full()); - let index = Self::decrement(self.front); + let index = self.decrement(self.front); // NOTE: the memory slot that we are about to write to is uninitialized. We assign // a `MaybeUninit` to avoid running `T`'s destructor on the uninitialized memory - *self.buffer.get_unchecked_mut(index) = MaybeUninit::new(item); + *self.buffer.borrow_mut().get_unchecked_mut(index) = MaybeUninit::new(item); self.front = index; if self.front == self.back { self.full = true; @@ -505,44 +644,19 @@ impl Deque { // NOTE: the memory slot that we are about to write to is uninitialized. We assign // a `MaybeUninit` to avoid running `T`'s destructor on the uninitialized memory - *self.buffer.get_unchecked_mut(self.back) = MaybeUninit::new(item); - self.back = Self::increment(self.back); + *self.buffer.borrow_mut().get_unchecked_mut(self.back) = MaybeUninit::new(item); + self.back = self.increment(self.back); if self.front == self.back { self.full = true; } } - - /// Returns an iterator over the deque. - pub fn iter(&self) -> Iter<'_, T, N> { - let done = self.is_empty(); - Iter { - _phantom: PhantomData, - buffer: &self.buffer as *const MaybeUninit, - front: self.front, - back: self.back, - done, - } - } - - /// Returns an iterator that allows modifying each value. - pub fn iter_mut(&mut self) -> IterMut<'_, T, N> { - let done = self.is_empty(); - IterMut { - _phantom: PhantomData, - buffer: &mut self.buffer as *mut _ as *mut MaybeUninit, - front: self.front, - back: self.back, - done, - } - } - /// Returns a reference to the element at the given index. /// /// Index 0 is the front of the `Deque`. pub fn get(&self, index: usize) -> Option<&T> { - if index < self.len() { + if index < self.storage_len() { let idx = self.to_physical_index(index); - Some(unsafe { self.buffer.get_unchecked(idx).assume_init_ref() }) + Some(unsafe { self.buffer.borrow().get_unchecked(idx).assume_init_ref() }) } else { None } @@ -552,9 +666,14 @@ impl Deque { /// /// Index 0 is the front of the `Deque`. pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - if index < self.len() { + if index < self.storage_len() { let idx = self.to_physical_index(index); - Some(unsafe { self.buffer.get_unchecked_mut(idx).assume_init_mut() }) + Some(unsafe { + self.buffer + .borrow_mut() + .get_unchecked_mut(idx) + .assume_init_mut() + }) } else { None } @@ -566,10 +685,10 @@ impl Deque { /// /// The element at the given `index` must exist (i.e. `index < self.len()`). pub unsafe fn get_unchecked(&self, index: usize) -> &T { - debug_assert!(index < self.len()); + debug_assert!(index < self.storage_len()); let idx = self.to_physical_index(index); - self.buffer.get_unchecked(idx).assume_init_ref() + self.buffer.borrow().get_unchecked(idx).assume_init_ref() } /// Returns a mutable reference to the element at the given index without checking if it exists. @@ -578,21 +697,95 @@ impl Deque { /// /// The element at the given `index` must exist (i.e. `index < self.len()`). pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T { - debug_assert!(index < self.len()); + debug_assert!(index < self.storage_len()); let idx = self.to_physical_index(index); - self.buffer.get_unchecked_mut(idx).assume_init_mut() + self.buffer + .borrow_mut() + .get_unchecked_mut(idx) + .assume_init_mut() } fn to_physical_index(&self, index: usize) -> usize { let mut res = self.front + index; - if res >= N { - res -= N; + if res >= self.storage_capacity() { + res -= self.storage_capacity(); } res } + + /// Returns an iterator over the deque. + pub fn iter(&self) -> Iter<'_, T> { + let (start, end) = self.as_slices(); + Iter { + inner: start.iter().chain(end), + } + } + + /// Returns an iterator that allows modifying each value. + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + let (start, end) = self.as_mut_slices(); + IterMut { + inner: start.iter_mut().chain(end), + } + } +} + +/// Iterator over the contents of a [`Deque`] +pub struct Iter<'a, T> { + inner: core::iter::Chain, core::slice::Iter<'a, T>>, +} + +/// Iterator over the contents of a [`Deque`] +pub struct IterMut<'a, T> { + inner: core::iter::Chain, core::slice::IterMut<'a, T>>, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + #[inline] + fn next(&mut self) -> Option { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + #[inline] + fn next_back(&mut self) -> Option { + self.inner.next_back() + } +} + +impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +impl<'a, T> FusedIterator for Iter<'a, T> {} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + #[inline] + fn next(&mut self) -> Option { + self.inner.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option { + self.inner.next_back() + } +} + +impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} +impl<'a, T> FusedIterator for IterMut<'a, T> {} + // Trait implementations impl Default for Deque { @@ -601,7 +794,7 @@ impl Default for Deque { } } -impl Drop for Deque { +impl Drop for DequeInner { fn drop(&mut self) { // safety: `self` is left in an inconsistent state but it doesn't matter since // it's getting dropped. Nothing should be able to observe `self` after drop. @@ -609,21 +802,21 @@ impl Drop for Deque { } } -impl fmt::Debug for Deque { +impl fmt::Debug for DequeInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self).finish() } } /// As with the standard library's `VecDeque`, items are added via `push_back`. -impl Extend for Deque { +impl Extend for DequeInner { fn extend>(&mut self, iter: I) { for item in iter { self.push_back(item).ok().unwrap(); } } } -impl<'a, T: 'a + Copy, const N: usize> Extend<&'a T> for Deque { +impl<'a, T: 'a + Copy, S: Storage> Extend<&'a T> for DequeInner { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().copied()) } @@ -653,131 +846,18 @@ impl IntoIterator for Deque { } } -/// An iterator over the elements of a [`Deque`]. -/// -/// This struct is created by calling the `iter` method. -#[derive(Clone)] -pub struct Iter<'a, T, const N: usize> { - buffer: *const MaybeUninit, - _phantom: PhantomData<&'a T>, - front: usize, - back: usize, - done: bool, -} - -impl<'a, T, const N: usize> Iterator for Iter<'a, T, N> { - type Item = &'a T; - fn next(&mut self) -> Option { - if self.done { - None - } else { - let index = self.front; - self.front = Deque::::increment(self.front); - if self.front == self.back { - self.done = true; - } - Some(unsafe { &*(self.buffer.add(index) as *const T) }) - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = if self.done { - 0 - } else if self.back <= self.front { - self.back + N - self.front - } else { - self.back - self.front - }; - - (len, Some(len)) - } -} - -impl<'a, T, const N: usize> DoubleEndedIterator for Iter<'a, T, N> { - fn next_back(&mut self) -> Option { - if self.done { - None - } else { - self.back = Deque::::decrement(self.back); - if self.front == self.back { - self.done = true; - } - Some(unsafe { &*(self.buffer.add(self.back) as *const T) }) - } - } -} - -impl<'a, T, const N: usize> ExactSizeIterator for Iter<'a, T, N> {} -impl<'a, T, const N: usize> FusedIterator for Iter<'a, T, N> {} - -/// An iterator over the elements of a [`Deque`]. -/// -/// This struct is created by calling the `iter` method. -pub struct IterMut<'a, T, const N: usize> { - buffer: *mut MaybeUninit, - _phantom: PhantomData<&'a mut T>, - front: usize, - back: usize, - done: bool, -} - -impl<'a, T, const N: usize> Iterator for IterMut<'a, T, N> { - type Item = &'a mut T; - fn next(&mut self) -> Option { - if self.done { - None - } else { - let index = self.front; - self.front = Deque::::increment(self.front); - if self.front == self.back { - self.done = true; - } - Some(unsafe { &mut *(self.buffer.add(index) as *mut T) }) - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = if self.done { - 0 - } else if self.back <= self.front { - self.back + N - self.front - } else { - self.back - self.front - }; - - (len, Some(len)) - } -} - -impl<'a, T, const N: usize> DoubleEndedIterator for IterMut<'a, T, N> { - fn next_back(&mut self) -> Option { - if self.done { - None - } else { - self.back = Deque::::decrement(self.back); - if self.front == self.back { - self.done = true; - } - Some(unsafe { &mut *(self.buffer.add(self.back) as *mut T) }) - } - } -} - -impl<'a, T, const N: usize> ExactSizeIterator for IterMut<'a, T, N> {} -impl<'a, T, const N: usize> FusedIterator for IterMut<'a, T, N> {} - -impl<'a, T, const N: usize> IntoIterator for &'a Deque { +impl<'a, T, S: Storage> IntoIterator for &'a DequeInner { type Item = &'a T; - type IntoIter = Iter<'a, T, N>; + type IntoIter = Iter<'a, T>; fn into_iter(self) -> Self::IntoIter { self.iter() } } -impl<'a, T, const N: usize> IntoIterator for &'a mut Deque { +impl<'a, T, S: Storage> IntoIterator for &'a mut DequeInner { type Item = &'a mut T; - type IntoIter = IterMut<'a, T, N>; + type IntoIter = IterMut<'a, T>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() diff --git a/src/lib.rs b/src/lib.rs index 86fa687467..17f6056dc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,7 +103,7 @@ pub use vec::{Vec, VecView}; #[cfg(test)] mod test_helpers; -mod deque; +pub mod deque; pub mod histbuf; mod indexmap; mod indexset; From aad37a8ab64c29765b9532c284eb118dbf93be33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 1 Jul 2024 11:45:47 +0200 Subject: [PATCH 2/3] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a310ad9e35..146453b708 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `MpMcQueueView`, the `!Sized` version of `MpMcQueue`. - Added `LinearMapView`, the `!Sized` version of `LinearMap`. - Added `HistoryBufferView`, the `!Sized` version of `HistoryBuffer`. +- Added `DequeView`, the `!Sized` version of `Deque`. ### Changed From 235f794cb66af34540735def396b1a5c48052b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 1 Jul 2024 13:51:03 +0200 Subject: [PATCH 3/3] Generalize serialize implementation --- src/ser.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ser.rs b/src/ser.rs index 0b8419f210..d26add100d 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -2,12 +2,13 @@ use core::hash::{BuildHasher, Hash}; use crate::{ binary_heap::{BinaryHeapInner, Kind as BinaryHeapKind}, + deque::DequeInner, histbuf::HistoryBufferInner, linear_map::LinearMapInner, storage::Storage, string::StringInner, vec::VecInner, - Deque, IndexMap, IndexSet, + IndexMap, IndexSet, }; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; @@ -64,15 +65,15 @@ where } } -impl Serialize for Deque +impl Serialize for DequeInner where T: Serialize, { - 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()))?; + let mut seq = serializer.serialize_seq(Some(self.storage_len()))?; for element in self { seq.serialize_element(element)?; }