diff --git a/CHANGELOG.md b/CHANGELOG.md index ab05dbd7..324cd252 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [v0.7.3] - 2021-07-1 +### Added + +- Added `Deque`. + ### Changed - `Box::freeze` is deprecated due to possibility of undefined behavior. diff --git a/src/deque.rs b/src/deque.rs new file mode 100644 index 00000000..dde8c2fd --- /dev/null +++ b/src/deque.rs @@ -0,0 +1,775 @@ +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem::MaybeUninit; +use core::{ptr, slice}; + +/// 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); +/// } +/// ``` +pub struct Deque { + buffer: [MaybeUninit; N], + + /// 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, +} + +impl Deque { + const INIT: MaybeUninit = MaybeUninit::uninit(); + + /// Constructs a new, empty deque with a fixed capacity of `N` + /// + /// # Examples + /// + /// ``` + /// use heapless::Deque; + /// + /// // allocate the deque on the stack + /// let mut x: Deque = Deque::new(); + /// + /// // allocate the deque in a static variable + /// static mut X: Deque = Deque::new(); + /// ``` + pub const fn new() -> Self { + // Const assert N > 0 + crate::sealed::greater_than_0::(); + + Self { + buffer: [Self::INIT; N], + front: 0, + back: 0, + full: false, + } + } + + fn increment(i: usize) -> usize { + if i + 1 == N { + 0 + } else { + i + 1 + } + } + + fn decrement(i: usize) -> usize { + if i == 0 { + N - 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 { + if self.full { + N + } else if self.back < self.front { + self.back + N - self.front + } else { + self.back - self.front + } + } + + /// Clears the deque, removing all values. + pub fn clear(&mut self) { + // safety: we're immediately setting a consistent empty state. + unsafe { self.drop_contents() } + self.front = 0; + self.back = 0; + self.full = false; + } + + /// Drop all items in the `Deque`, leaving the state `back/front/full` unmodified. + /// + /// safety: leaves the `Deque` in an inconsistent state, so can cause duplicate drops. + unsafe fn drop_contents(&mut self) { + // We drop each element used in the deque by turning into a &mut[T] + let (a, b) = self.as_mut_slices(); + ptr::drop_in_place(a); + ptr::drop_in_place(b); + } + + /// Returns whether the deque is empty. + pub fn is_empty(&self) -> bool { + self.front == self.back && !self.full + } + + /// Returns whether the deque is full (i.e. if `len() == capacity()`. + pub fn is_full(&self) -> bool { + self.full + } + + /// Returns a pair of slices which contain, in order, the contents of the `Deque`. + pub fn as_slices(&self) -> (&[T], &[T]) { + // NOTE(unsafe) avoid bound checks in the slicing operation + unsafe { + if self.is_empty() { + (&[], &[]) + } else if self.back <= self.front { + ( + slice::from_raw_parts( + self.buffer.as_ptr().add(self.front) as *const T, + N - self.front, + ), + slice::from_raw_parts(self.buffer.as_ptr() as *const T, self.back), + ) + } else { + ( + slice::from_raw_parts( + self.buffer.as_ptr().add(self.front) as *const T, + self.back - self.front, + ), + &[], + ) + } + } + } + + /// 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]) { + // NOTE(unsafe) avoid bound checks in the slicing operation + unsafe { + if self.is_empty() { + (&mut [], &mut []) + } else if self.back <= self.front { + ( + slice::from_raw_parts_mut( + self.buffer.as_mut_ptr().add(self.front) as *mut T, + N - self.front, + ), + slice::from_raw_parts_mut(self.buffer.as_mut_ptr() as *mut T, self.back), + ) + } else { + ( + slice::from_raw_parts_mut( + self.buffer.as_mut_ptr().add(self.front) as *mut T, + self.back - self.front, + ), + &mut [], + ) + } + } + } + + /// Removes the item from the front of the deque and returns it, or `None` if it's empty + pub fn pop_front(&mut self) -> Option { + if self.is_empty() { + None + } else { + Some(unsafe { self.pop_front_unchecked() }) + } + } + + /// Removes the item from the back of the deque and returns it, or `None` if it's empty + pub fn pop_back(&mut self) -> Option { + if self.is_empty() { + None + } else { + Some(unsafe { self.pop_back_unchecked() }) + } + } + + /// Appends an `item` to the front of the deque + /// + /// Returns back the `item` if the deque is full + pub fn push_front(&mut self, item: T) -> Result<(), T> { + if self.is_full() { + Err(item) + } else { + unsafe { self.push_front_unchecked(item) } + Ok(()) + } + } + + /// Appends an `item` to the back of the deque + /// + /// Returns back the `item` if the deque is full + pub fn push_back(&mut self, item: T) -> Result<(), T> { + if self.is_full() { + Err(item) + } else { + unsafe { self.push_back_unchecked(item) } + Ok(()) + } + } + + /// Removes an item from the front of the deque and returns it + /// + /// # Safety + /// + /// This assumes the deque is not empty. + pub(crate) unsafe fn pop_front_unchecked(&mut self) -> T { + debug_assert!(!self.is_empty()); + + let index = self.front; + self.full = false; + self.front = Self::increment(self.front); + (self.buffer.get_unchecked_mut(index).as_ptr() as *const T).read() + } + + /// Removes an item from the back of the deque and returns it + /// + /// # Safety + /// + /// This assumes the deque is not empty. + pub(crate) unsafe fn pop_back_unchecked(&mut self) -> T { + debug_assert!(!self.is_empty()); + + self.full = false; + self.back = Self::decrement(self.back); + (self.buffer.get_unchecked_mut(self.back).as_ptr() as *const T).read() + } + + /// Appends an `item` to the front of the deque + /// + /// # Safety + /// + /// This assumes the deque is not full. + pub unsafe fn push_front_unchecked(&mut self, item: T) { + debug_assert!(!self.is_full()); + + 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.front = index; + if self.front == self.back { + self.full = true; + } + } + + /// Appends an `item` to the back of the deque + /// + /// # Safety + /// + /// This assumes the deque is not full. + pub unsafe fn push_back_unchecked(&mut self, item: T) { + debug_assert!(!self.is_full()); + + // 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); + 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[0] as *mut MaybeUninit, + front: self.front, + back: self.back, + done, + } + } +} + +// Trait implementations + +impl Default for Deque { + fn default() -> Self { + Self::new() + } +} + +impl Drop for Deque { + 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. + unsafe { self.drop_contents() } + } +} + +/// An iterator that moves out of a [`Deque`]. +/// +/// This struct is created by calling the `into_iter` method. +/// +#[derive(Clone)] +pub struct IntoIter { + deque: Deque, +} + +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { + self.deque.pop_front() + } +} + +impl IntoIterator for Deque { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { deque: self } + } +} + +/// 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 { + type Item = &'a T; + type IntoIter = Iter<'a, T, N>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T, const N: usize> IntoIterator for &'a mut Deque { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T, N>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl Clone for Deque +where + T: Clone, +{ + fn clone(&self) -> Self { + let mut res = Deque::new(); + for i in self { + // safety: the original and new deques have the same capacity, so it can + // not become full. + unsafe { res.push_back_unchecked(i.clone()) } + } + res + } +} + +#[cfg(test)] +mod tests { + use crate::Deque; + + #[test] + fn static_new() { + static mut _V: Deque = Deque::new(); + } + + #[test] + fn stack_new() { + static mut _V: Deque = Deque::new(); + } + + macro_rules! droppable { + () => { + struct Droppable; + impl Droppable { + fn new() -> Self { + unsafe { + COUNT += 1; + } + Droppable + } + } + impl Drop for Droppable { + fn drop(&mut self) { + unsafe { + COUNT -= 1; + } + } + } + + static mut COUNT: i32 = 0; + }; + } + + #[test] + fn drop() { + droppable!(); + + { + let mut v: Deque = Deque::new(); + v.push_back(Droppable::new()).ok().unwrap(); + v.push_back(Droppable::new()).ok().unwrap(); + v.pop_front().unwrap(); + } + + assert_eq!(unsafe { COUNT }, 0); + + { + let mut v: Deque = Deque::new(); + v.push_back(Droppable::new()).ok().unwrap(); + v.push_back(Droppable::new()).ok().unwrap(); + } + + assert_eq!(unsafe { COUNT }, 0); + { + let mut v: Deque = Deque::new(); + v.push_front(Droppable::new()).ok().unwrap(); + v.push_front(Droppable::new()).ok().unwrap(); + } + + assert_eq!(unsafe { COUNT }, 0); + } + + #[test] + fn full() { + let mut v: Deque = Deque::new(); + + v.push_back(0).unwrap(); + v.push_front(1).unwrap(); + v.push_back(2).unwrap(); + v.push_back(3).unwrap(); + + assert!(v.push_front(4).is_err()); + assert!(v.push_back(4).is_err()); + assert!(v.is_full()); + } + + #[test] + fn empty() { + let mut v: Deque = Deque::new(); + assert!(v.is_empty()); + + v.push_back(0).unwrap(); + assert!(!v.is_empty()); + + v.push_front(1).unwrap(); + assert!(!v.is_empty()); + + v.pop_front().unwrap(); + v.pop_front().unwrap(); + + assert!(v.pop_front().is_none()); + assert!(v.pop_back().is_none()); + assert!(v.is_empty()); + } + + #[test] + fn iter() { + let mut v: Deque = Deque::new(); + + v.push_back(0).unwrap(); + v.push_back(1).unwrap(); + v.push_front(2).unwrap(); + v.push_front(3).unwrap(); + v.pop_back().unwrap(); + v.push_front(4).unwrap(); + + let mut items = v.iter(); + + assert_eq!(items.next(), Some(&4)); + assert_eq!(items.next(), Some(&3)); + assert_eq!(items.next(), Some(&2)); + assert_eq!(items.next(), Some(&0)); + assert_eq!(items.next(), None); + } + + #[test] + fn iter_mut() { + let mut v: Deque = Deque::new(); + + v.push_back(0).unwrap(); + v.push_back(1).unwrap(); + v.push_front(2).unwrap(); + v.push_front(3).unwrap(); + v.pop_back().unwrap(); + v.push_front(4).unwrap(); + + let mut items = v.iter_mut(); + + assert_eq!(items.next(), Some(&mut 4)); + assert_eq!(items.next(), Some(&mut 3)); + assert_eq!(items.next(), Some(&mut 2)); + assert_eq!(items.next(), Some(&mut 0)); + assert_eq!(items.next(), None); + } + + #[test] + fn iter_move() { + let mut v: Deque = Deque::new(); + v.push_back(0).unwrap(); + v.push_back(1).unwrap(); + v.push_back(2).unwrap(); + v.push_back(3).unwrap(); + + let mut items = v.into_iter(); + + assert_eq!(items.next(), Some(0)); + assert_eq!(items.next(), Some(1)); + assert_eq!(items.next(), Some(2)); + assert_eq!(items.next(), Some(3)); + assert_eq!(items.next(), None); + } + + #[test] + fn iter_move_drop() { + droppable!(); + + { + let mut deque: Deque = Deque::new(); + deque.push_back(Droppable::new()).ok().unwrap(); + deque.push_back(Droppable::new()).ok().unwrap(); + let mut items = deque.into_iter(); + // Move all + let _ = items.next(); + let _ = items.next(); + } + + assert_eq!(unsafe { COUNT }, 0); + + { + let mut deque: Deque = Deque::new(); + deque.push_back(Droppable::new()).ok().unwrap(); + deque.push_back(Droppable::new()).ok().unwrap(); + let _items = deque.into_iter(); + // Move none + } + + assert_eq!(unsafe { COUNT }, 0); + + { + let mut deque: Deque = Deque::new(); + deque.push_back(Droppable::new()).ok().unwrap(); + deque.push_back(Droppable::new()).ok().unwrap(); + let mut items = deque.into_iter(); + let _ = items.next(); // Move partly + } + + assert_eq!(unsafe { COUNT }, 0); + } + + #[test] + fn push_and_pop() { + let mut q: Deque = Deque::new(); + assert_eq!(q.len(), 0); + + assert_eq!(q.pop_front(), None); + assert_eq!(q.pop_back(), None); + assert_eq!(q.len(), 0); + + q.push_back(0).unwrap(); + assert_eq!(q.len(), 1); + + assert_eq!(q.pop_back(), Some(0)); + assert_eq!(q.len(), 0); + + q.push_back(0).unwrap(); + q.push_back(1).unwrap(); + q.push_front(2).unwrap(); + q.push_front(3).unwrap(); + assert_eq!(q.len(), 4); + + // deque contains: 3 2 0 1 + assert_eq!(q.pop_front(), Some(3)); + assert_eq!(q.len(), 3); + assert_eq!(q.pop_front(), Some(2)); + assert_eq!(q.len(), 2); + assert_eq!(q.pop_back(), Some(1)); + assert_eq!(q.len(), 1); + assert_eq!(q.pop_front(), Some(0)); + assert_eq!(q.len(), 0); + + // deque is now empty + assert_eq!(q.pop_front(), None); + assert_eq!(q.pop_back(), None); + assert_eq!(q.len(), 0); + } + + #[test] + fn as_slices() { + let mut q: Deque = Deque::new(); + assert_eq!(q.len(), 0); + + q.push_back(0).unwrap(); + q.push_back(1).unwrap(); + q.push_back(2).unwrap(); + q.push_back(3).unwrap(); + assert_eq!(q.as_slices(), (&[0, 1, 2, 3][..], &[][..])); + + q.pop_front().unwrap(); + assert_eq!(q.as_slices(), (&[1, 2, 3][..], &[][..])); + + q.push_back(4).unwrap(); + assert_eq!(q.as_slices(), (&[1, 2, 3][..], &[4][..])); + } + + #[test] + fn clear() { + let mut q: Deque = Deque::new(); + assert_eq!(q.len(), 0); + + q.push_back(0).unwrap(); + q.push_back(1).unwrap(); + q.push_back(2).unwrap(); + q.push_back(3).unwrap(); + assert_eq!(q.len(), 4); + + q.clear(); + assert_eq!(q.len(), 0); + + q.push_back(0).unwrap(); + assert_eq!(q.len(), 1); + } +} diff --git a/src/lib.rs b/src/lib.rs index 005be008..2e72882e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,6 +74,7 @@ #![deny(const_err)] pub use binary_heap::BinaryHeap; +pub use deque::Deque; pub use histbuf::HistoryBuffer; pub use indexmap::{Bucket, FnvIndexMap, IndexMap, Pos}; pub use indexset::{FnvIndexSet, IndexSet}; @@ -82,6 +83,7 @@ pub use string::String; pub use vec::Vec; // NOTE this code was last ported from v0.4.1 of the indexmap crate +mod deque; mod histbuf; mod indexmap; mod indexset;